Skip to content

Improve clarity of the implicit declaration diagnostic #149314

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

AaronBallman
Copy link
Collaborator

The previous text was "implicitly declaring library function 'exp' with
type 'double (double)'" which helpfully mentioned the type. However, it
was also confusing because an implicit function declaration in C89 was
'int()', so when we'd implicitly declare a library function that isn't
present in the specified language mode, the type information was a bit
confusing.

The new message calls out the library functions which come from a
particular standard (C, C++, or POSIX) to mention that the type
selected is because the standard mandates that type. That makes it a
little more clear why the type is not 'int()'.

Fixes #146924

The previous text was "implicitly declaring library function 'exp' with
type 'double (double)'" which helpfully mentioned the type. However, it
was also confusing because an implicit function declaration in C89 was
'int()', so when we'd implicitly declare a library function that isn't
present in the specified language mode, the type information was a bit
confusing.

The new message calls out the library functions which come from a
particular standard (C, C++, or POSIX) to mention that the type
selected is because the standard mandates that type. That makes it a
little more clear why the type is not 'int()'.

Fixes llvm#146924
@AaronBallman AaronBallman added clang Clang issues not falling into any other category quality-of-implementation clang:diagnostics New/improved warning or error message in Clang, but not in clang-tidy or static analyzer labels Jul 17, 2025
@llvmbot llvmbot added clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:static analyzer labels Jul 17, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 17, 2025

@llvm/pr-subscribers-clang-driver

@llvm/pr-subscribers-clang

Author: Aaron Ballman (AaronBallman)

Changes

The previous text was "implicitly declaring library function 'exp' with
type 'double (double)'" which helpfully mentioned the type. However, it
was also confusing because an implicit function declaration in C89 was
'int()', so when we'd implicitly declare a library function that isn't
present in the specified language mode, the type information was a bit
confusing.

The new message calls out the library functions which come from a
particular standard (C, C++, or POSIX) to mention that the type
selected is because the standard mandates that type. That makes it a
little more clear why the type is not 'int()'.

Fixes #146924


Full diff: https://github.com/llvm/llvm-project/pull/149314.diff

10 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+4)
  • (modified) clang/include/clang/Basic/Builtins.h (+27)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+5-4)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+3-1)
  • (modified) clang/test/Analysis/exercise-ps.c (+1-1)
  • (modified) clang/test/Driver/implicit-function-as-error.c (+1-1)
  • (modified) clang/test/Sema/builtin-setjmp.c (+1-1)
  • (modified) clang/test/Sema/implicit-builtin-decl.c (+1-1)
  • (modified) clang/test/SemaObjC/builtin_objc_lib_functions.m (+7-7)
  • (modified) clang/test/SemaObjC/builtin_objc_nslog.m (+2-2)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fcd3887ec7a09..dbbe1ce4b3d09 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -716,6 +716,10 @@ Improvements to Clang's diagnostics
   Added a new warning in this group for the case where the attribute is missing/implicit on
   an override of a virtual method.
 
+ - Reworded the ``-Wimplicit-function-declaration`` diagnostic to make it more
+   clear that the type selected for the implicit declaration is based on the
+   signature of a standard (C, C++, POSIX) library function. (#GH146924)
+
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h
index 3a5e31de2bc50..4bb860e537b8a 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -376,6 +376,33 @@ class Context {
     return getInfo(ID).Header.getName();
   }
 
+  /// Returns true if a library function is declared within a C or C++ standard
+  /// header (like stdio.h) or POSIX header (like malloc.h), false if the
+  /// function is not declared within a header or is declared in a non-standard
+  /// header (like Microsoft or Objective-C headers).
+  bool isDeclaredInStandardHeader(unsigned ID) const {
+    switch (getInfo(ID).Header.ID) {
+    default:
+      return false;
+    case HeaderDesc::COMPLEX_H: // C99
+    case HeaderDesc::CTYPE_H:   // C89
+    case HeaderDesc::MATH_H:    // C89
+    case HeaderDesc::MALLOC_H:  // POSIX
+    case HeaderDesc::MEMORY:    // C++98
+    case HeaderDesc::PTHREAD_H: // POSIX
+    case HeaderDesc::SETJMP_H:  // C89
+    case HeaderDesc::STDARG_H:  // C89
+    case HeaderDesc::STDIO_H:   // C89
+    case HeaderDesc::STDLIB_H:  // C89
+    case HeaderDesc::STRING_H:  // C89
+    case HeaderDesc::STRINGS_H: // POSIX
+    case HeaderDesc::UNISTD_H:  // POSIX
+    case HeaderDesc::UTILITY:   // C++98
+    case HeaderDesc::WCHAR_H:   // C99
+      return true;
+    }
+  }
+
   /// Determine whether this builtin is like printf in its
   /// formatting rules and, if so, set the index to the format string
   /// argument and whether this function as a va_list argument.
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b2ea65ae111be..abb916a66984c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -816,11 +816,12 @@ def warn_unreachable_association : Warning<
 
 /// Built-in functions.
 def ext_implicit_lib_function_decl : ExtWarn<
-  "implicitly declaring library function '%0' with type %1">,
-  InGroup<ImplicitFunctionDeclare>;
+  "implicitly declaring library function '%0' with%select{| standards-mandated}2 "
+  "type %1">, InGroup<ImplicitFunctionDeclare>;
 def ext_implicit_lib_function_decl_c99 : ExtWarn<
-  "call to undeclared library function '%0' with type %1; ISO C99 and later "
-  "do not support implicit function declarations">,
+  "call to undeclared library function '%0', will assume it exists with"
+  "%select{| standards-mandated}2 type %1; ISO C99 and later do not support "
+  "implicit function declarations">,
   InGroup<ImplicitFunctionDeclare>, DefaultError;
 def note_include_header_or_declare : Note<
   "include the header <%0> or explicitly provide a declaration for '%1'">;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 14403e65e8f42..8824ce69c17cc 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2380,9 +2380,11 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
   if (!ForRedeclaration &&
       (Context.BuiltinInfo.isPredefinedLibFunction(ID) ||
        Context.BuiltinInfo.isHeaderDependentFunction(ID))) {
+    bool IsStandardsMandated =
+        Context.BuiltinInfo.isDeclaredInStandardHeader(ID);
     Diag(Loc, LangOpts.C99 ? diag::ext_implicit_lib_function_decl_c99
                            : diag::ext_implicit_lib_function_decl)
-        << Context.BuiltinInfo.getName(ID) << R;
+        << Context.BuiltinInfo.getName(ID) << R << IsStandardsMandated;
     if (const char *Header = Context.BuiltinInfo.getHeaderName(ID))
       Diag(Loc, diag::note_include_header_or_declare)
           << Header << Context.BuiltinInfo.getName(ID);
diff --git a/clang/test/Analysis/exercise-ps.c b/clang/test/Analysis/exercise-ps.c
index 21d97a364e190..2de884b56ca7f 100644
--- a/clang/test/Analysis/exercise-ps.c
+++ b/clang/test/Analysis/exercise-ps.c
@@ -22,7 +22,7 @@ void_typedef f2_helper(void);
 static void f2(void *buf) {
   F12_typedef* x;
   x = f2_helper();
-  memcpy((&x[1]), (buf), 1); // expected-warning{{call to undeclared library function 'memcpy' with type 'void *(void *, const void *}} \
+  memcpy((&x[1]), (buf), 1); // expected-warning{{call to undeclared library function 'memcpy', will assume it exists with standards-mandated type 'void *(void *, const void *,}} \
   // expected-note{{include the header <string.h> or explicitly provide a declaration for 'memcpy'}}
 }
 
diff --git a/clang/test/Driver/implicit-function-as-error.c b/clang/test/Driver/implicit-function-as-error.c
index a7f815c8ed69b..f2db881a3eb2e 100644
--- a/clang/test/Driver/implicit-function-as-error.c
+++ b/clang/test/Driver/implicit-function-as-error.c
@@ -6,6 +6,6 @@
 // to an error.
 
 void radar_10894044(void) {
-  printf("Hi\n"); // expected-error {{call to undeclared library function 'printf' with type 'int (const char *, ...)'}} expected-note {{include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
+  printf("Hi\n"); // expected-error {{call to undeclared library function 'printf', will assume it exists with standards-mandated type 'int (const char *, ...)'; ISO C99 and later do not support implicit function declarations}} expected-note {{include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
   radar_10894044_not_declared(); // expected-error {{call to undeclared function 'radar_10894044_not_declared'; ISO C99 and later do not support implicit function declarations}}
 }
diff --git a/clang/test/Sema/builtin-setjmp.c b/clang/test/Sema/builtin-setjmp.c
index a71f87162612d..61ebf8012cdba 100644
--- a/clang/test/Sema/builtin-setjmp.c
+++ b/clang/test/Sema/builtin-setjmp.c
@@ -38,7 +38,7 @@ void use(void) {
   // c-error@-3 {{call to undeclared function 'setjmp'; ISO C99 and later do not support implicit function declarations}}
   #elif ONLY_JMP_BUF
   // cxx-error@-5 {{undeclared identifier 'setjmp'}}
-  // c-error@-6 {{call to undeclared library function 'setjmp' with type 'int (jmp_buf)' (aka 'int (int *)'); ISO C99 and later do not support implicit function declarations}}
+  // c-error@-6 {{call to undeclared library function 'setjmp', will assume it exists with standards-mandated type 'int (jmp_buf)' (aka 'int (int *)'); ISO C99 and later do not support implicit function declarations}}
   // c-note@-7 {{include the header <setjmp.h> or explicitly provide a declaration for 'setjmp'}}
   #else
   // cxx-no-diagnostics
diff --git a/clang/test/Sema/implicit-builtin-decl.c b/clang/test/Sema/implicit-builtin-decl.c
index 055ba7e70eb12..a36263a27d14c 100644
--- a/clang/test/Sema/implicit-builtin-decl.c
+++ b/clang/test/Sema/implicit-builtin-decl.c
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -Wno-strict-prototypes -verify %s
 
 void f() {
-  int *ptr = malloc(sizeof(int) * 10); // expected-error{{call to undeclared library function 'malloc' with type}} \
+  int *ptr = malloc(sizeof(int) * 10); // expected-error{{call to undeclared library function 'malloc'}} \
   // expected-note{{include the header <stdlib.h> or explicitly provide a declaration for 'malloc'}} \
   // expected-note{{'malloc' is a builtin with type 'void *}}
 }
diff --git a/clang/test/SemaObjC/builtin_objc_lib_functions.m b/clang/test/SemaObjC/builtin_objc_lib_functions.m
index a98abdf6039cb..449ae5edfb34e 100644
--- a/clang/test/SemaObjC/builtin_objc_lib_functions.m
+++ b/clang/test/SemaObjC/builtin_objc_lib_functions.m
@@ -1,27 +1,27 @@
 // RUN: %clang_cc1 -x objective-c %s -fsyntax-only -verify
-Class f0(void) { return objc_getClass("a"); } // expected-error {{call to undeclared library function 'objc_getClass' with type 'id (const char *)'}} \
+Class f0(void) { return objc_getClass("a"); } // expected-error {{call to undeclared library function 'objc_getClass', will assume it exists with type 'id (const char *)'; ISO C99 and later do not support implicit function declarations}} \
 					  // expected-note {{include the header <objc/runtime.h> or explicitly provide a declaration for 'objc_getClass'}}
 
-Class f1(void) { return objc_getMetaClass("a"); } // expected-error {{call to undeclared library function 'objc_getMetaClass' with type 'id (const char *)'}} \
+Class f1(void) { return objc_getMetaClass("a"); } // expected-error {{call to undeclared library function 'objc_getMetaClass', will assume it exists with type 'id (const char *)'; ISO C99 and later do not support implicit function declarations}} \
 					  // expected-note {{include the header <objc/runtime.h> or explicitly provide a declaration for 'objc_getMetaClass'}}
 
-void f2(id val) { objc_enumerationMutation(val); } // expected-error {{call to undeclared library function 'objc_enumerationMutation' with type 'void (id)'}} \
+void f2(id val) { objc_enumerationMutation(val); } // expected-error {{call to undeclared library function 'objc_enumerationMutation', will assume it exists with type 'void (id)'; ISO C99 and later do not support implicit function declarations}} \
 						   // expected-note {{include the header <objc/runtime.h> or explicitly provide a declaration for 'objc_enumerationMutation'}}
 
-long double f3(id self, SEL op) { return objc_msgSend_fpret(self, op); } // expected-error {{call to undeclared library function 'objc_msgSend_fpret' with type 'long double (id, SEL, ...)'}} \
+long double f3(id self, SEL op) { return objc_msgSend_fpret(self, op); } // expected-error {{call to undeclared library function 'objc_msgSend_fpret', will assume it exists with type 'long double (id, SEL, ...)'; ISO C99 and later do not support implicit function declarations}} \
     // expected-note {{include the header <objc/message.h> or explicitly provide a declaration for 'objc_msgSend_fpret'}}
 
 id f4(struct objc_super *super, SEL op) { // expected-warning {{declaration of 'struct objc_super' will not be visible outside of this function}}
-  return objc_msgSendSuper(super, op); // expected-error {{call to undeclared library function 'objc_msgSendSuper' with type 'id (struct objc_super *, SEL, ...)'}} \
+  return objc_msgSendSuper(super, op); // expected-error {{call to undeclared library function 'objc_msgSendSuper', will assume it exists with type 'id (struct objc_super *, SEL, ...)'; ISO C99 and later do not support implicit function declarations}} \
 					// expected-note {{include the header <objc/message.h> or explicitly provide a declaration for 'objc_msgSendSuper'}}
 }
 
 id f5(id val, id *dest) {
-  return objc_assign_strongCast(val, dest); // expected-error {{call to undeclared library function 'objc_assign_strongCast' with type 'id (id, id *)'}} \
+  return objc_assign_strongCast(val, dest); // expected-error {{call to undeclared library function 'objc_assign_strongCast', will assume it exists with type 'id (id, id *)'; ISO C99 and later do not support implicit function declarations}} \
 					    // expected-note {{include the header <objc/objc-auto.h> or explicitly provide a declaration for 'objc_assign_strongCast'}}
 }
 
 int f6(Class exceptionClass, id exception) {
-  return objc_exception_match(exceptionClass, exception); // expected-error {{call to undeclared library function 'objc_exception_match' with type 'int (id, id)'}} \
+  return objc_exception_match(exceptionClass, exception); // expected-error {{call to undeclared library function 'objc_exception_match', will assume it exists with type 'int (id, id)'; ISO C99 and later do not support implicit function declarations}} \
   							  // expected-note {{include the header <objc/objc-exception.h> or explicitly provide a declaration for 'objc_exception_match'}}
 }
diff --git a/clang/test/SemaObjC/builtin_objc_nslog.m b/clang/test/SemaObjC/builtin_objc_nslog.m
index 3c35a02d9b8a3..855d861516f72 100644
--- a/clang/test/SemaObjC/builtin_objc_nslog.m
+++ b/clang/test/SemaObjC/builtin_objc_nslog.m
@@ -3,11 +3,11 @@
 #include <stdarg.h>
 
 void f1(id arg) {
-  NSLog(@"%@", arg); // expected-error {{call to undeclared library function 'NSLog' with type 'void (id, ...)'}} \
+  NSLog(@"%@", arg); // expected-error {{call to undeclared library function 'NSLog', will assume it exists with type 'void (id, ...)'; ISO C99 and later do not support implicit function declaration}} \
   // expected-note {{include the header <Foundation/NSObjCRuntime.h> or explicitly provide a declaration for 'NSLog'}}
 }
 
 void f2(id str, va_list args) {
-  NSLogv(@"%@", args); // expected-error {{call to undeclared library function 'NSLogv' with type }} \
+  NSLogv(@"%@", args); // expected-error {{call to undeclared library function 'NSLogv', will assume it exists with type 'void (id, __builtin_va_list)'; ISO C99 and later do not support implicit function declarations}} \
   // expected-note {{include the header <Foundation/NSObjCRuntime.h> or explicitly provide a declaration for 'NSLogv'}}
 }

@llvmbot
Copy link
Member

llvmbot commented Jul 17, 2025

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Aaron Ballman (AaronBallman)

Changes

The previous text was "implicitly declaring library function 'exp' with
type 'double (double)'" which helpfully mentioned the type. However, it
was also confusing because an implicit function declaration in C89 was
'int()', so when we'd implicitly declare a library function that isn't
present in the specified language mode, the type information was a bit
confusing.

The new message calls out the library functions which come from a
particular standard (C, C++, or POSIX) to mention that the type
selected is because the standard mandates that type. That makes it a
little more clear why the type is not 'int()'.

Fixes #146924


Full diff: https://github.com/llvm/llvm-project/pull/149314.diff

10 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+4)
  • (modified) clang/include/clang/Basic/Builtins.h (+27)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+5-4)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+3-1)
  • (modified) clang/test/Analysis/exercise-ps.c (+1-1)
  • (modified) clang/test/Driver/implicit-function-as-error.c (+1-1)
  • (modified) clang/test/Sema/builtin-setjmp.c (+1-1)
  • (modified) clang/test/Sema/implicit-builtin-decl.c (+1-1)
  • (modified) clang/test/SemaObjC/builtin_objc_lib_functions.m (+7-7)
  • (modified) clang/test/SemaObjC/builtin_objc_nslog.m (+2-2)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fcd3887ec7a09..dbbe1ce4b3d09 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -716,6 +716,10 @@ Improvements to Clang's diagnostics
   Added a new warning in this group for the case where the attribute is missing/implicit on
   an override of a virtual method.
 
+ - Reworded the ``-Wimplicit-function-declaration`` diagnostic to make it more
+   clear that the type selected for the implicit declaration is based on the
+   signature of a standard (C, C++, POSIX) library function. (#GH146924)
+
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h
index 3a5e31de2bc50..4bb860e537b8a 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -376,6 +376,33 @@ class Context {
     return getInfo(ID).Header.getName();
   }
 
+  /// Returns true if a library function is declared within a C or C++ standard
+  /// header (like stdio.h) or POSIX header (like malloc.h), false if the
+  /// function is not declared within a header or is declared in a non-standard
+  /// header (like Microsoft or Objective-C headers).
+  bool isDeclaredInStandardHeader(unsigned ID) const {
+    switch (getInfo(ID).Header.ID) {
+    default:
+      return false;
+    case HeaderDesc::COMPLEX_H: // C99
+    case HeaderDesc::CTYPE_H:   // C89
+    case HeaderDesc::MATH_H:    // C89
+    case HeaderDesc::MALLOC_H:  // POSIX
+    case HeaderDesc::MEMORY:    // C++98
+    case HeaderDesc::PTHREAD_H: // POSIX
+    case HeaderDesc::SETJMP_H:  // C89
+    case HeaderDesc::STDARG_H:  // C89
+    case HeaderDesc::STDIO_H:   // C89
+    case HeaderDesc::STDLIB_H:  // C89
+    case HeaderDesc::STRING_H:  // C89
+    case HeaderDesc::STRINGS_H: // POSIX
+    case HeaderDesc::UNISTD_H:  // POSIX
+    case HeaderDesc::UTILITY:   // C++98
+    case HeaderDesc::WCHAR_H:   // C99
+      return true;
+    }
+  }
+
   /// Determine whether this builtin is like printf in its
   /// formatting rules and, if so, set the index to the format string
   /// argument and whether this function as a va_list argument.
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b2ea65ae111be..abb916a66984c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -816,11 +816,12 @@ def warn_unreachable_association : Warning<
 
 /// Built-in functions.
 def ext_implicit_lib_function_decl : ExtWarn<
-  "implicitly declaring library function '%0' with type %1">,
-  InGroup<ImplicitFunctionDeclare>;
+  "implicitly declaring library function '%0' with%select{| standards-mandated}2 "
+  "type %1">, InGroup<ImplicitFunctionDeclare>;
 def ext_implicit_lib_function_decl_c99 : ExtWarn<
-  "call to undeclared library function '%0' with type %1; ISO C99 and later "
-  "do not support implicit function declarations">,
+  "call to undeclared library function '%0', will assume it exists with"
+  "%select{| standards-mandated}2 type %1; ISO C99 and later do not support "
+  "implicit function declarations">,
   InGroup<ImplicitFunctionDeclare>, DefaultError;
 def note_include_header_or_declare : Note<
   "include the header <%0> or explicitly provide a declaration for '%1'">;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 14403e65e8f42..8824ce69c17cc 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2380,9 +2380,11 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
   if (!ForRedeclaration &&
       (Context.BuiltinInfo.isPredefinedLibFunction(ID) ||
        Context.BuiltinInfo.isHeaderDependentFunction(ID))) {
+    bool IsStandardsMandated =
+        Context.BuiltinInfo.isDeclaredInStandardHeader(ID);
     Diag(Loc, LangOpts.C99 ? diag::ext_implicit_lib_function_decl_c99
                            : diag::ext_implicit_lib_function_decl)
-        << Context.BuiltinInfo.getName(ID) << R;
+        << Context.BuiltinInfo.getName(ID) << R << IsStandardsMandated;
     if (const char *Header = Context.BuiltinInfo.getHeaderName(ID))
       Diag(Loc, diag::note_include_header_or_declare)
           << Header << Context.BuiltinInfo.getName(ID);
diff --git a/clang/test/Analysis/exercise-ps.c b/clang/test/Analysis/exercise-ps.c
index 21d97a364e190..2de884b56ca7f 100644
--- a/clang/test/Analysis/exercise-ps.c
+++ b/clang/test/Analysis/exercise-ps.c
@@ -22,7 +22,7 @@ void_typedef f2_helper(void);
 static void f2(void *buf) {
   F12_typedef* x;
   x = f2_helper();
-  memcpy((&x[1]), (buf), 1); // expected-warning{{call to undeclared library function 'memcpy' with type 'void *(void *, const void *}} \
+  memcpy((&x[1]), (buf), 1); // expected-warning{{call to undeclared library function 'memcpy', will assume it exists with standards-mandated type 'void *(void *, const void *,}} \
   // expected-note{{include the header <string.h> or explicitly provide a declaration for 'memcpy'}}
 }
 
diff --git a/clang/test/Driver/implicit-function-as-error.c b/clang/test/Driver/implicit-function-as-error.c
index a7f815c8ed69b..f2db881a3eb2e 100644
--- a/clang/test/Driver/implicit-function-as-error.c
+++ b/clang/test/Driver/implicit-function-as-error.c
@@ -6,6 +6,6 @@
 // to an error.
 
 void radar_10894044(void) {
-  printf("Hi\n"); // expected-error {{call to undeclared library function 'printf' with type 'int (const char *, ...)'}} expected-note {{include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
+  printf("Hi\n"); // expected-error {{call to undeclared library function 'printf', will assume it exists with standards-mandated type 'int (const char *, ...)'; ISO C99 and later do not support implicit function declarations}} expected-note {{include the header <stdio.h> or explicitly provide a declaration for 'printf'}}
   radar_10894044_not_declared(); // expected-error {{call to undeclared function 'radar_10894044_not_declared'; ISO C99 and later do not support implicit function declarations}}
 }
diff --git a/clang/test/Sema/builtin-setjmp.c b/clang/test/Sema/builtin-setjmp.c
index a71f87162612d..61ebf8012cdba 100644
--- a/clang/test/Sema/builtin-setjmp.c
+++ b/clang/test/Sema/builtin-setjmp.c
@@ -38,7 +38,7 @@ void use(void) {
   // c-error@-3 {{call to undeclared function 'setjmp'; ISO C99 and later do not support implicit function declarations}}
   #elif ONLY_JMP_BUF
   // cxx-error@-5 {{undeclared identifier 'setjmp'}}
-  // c-error@-6 {{call to undeclared library function 'setjmp' with type 'int (jmp_buf)' (aka 'int (int *)'); ISO C99 and later do not support implicit function declarations}}
+  // c-error@-6 {{call to undeclared library function 'setjmp', will assume it exists with standards-mandated type 'int (jmp_buf)' (aka 'int (int *)'); ISO C99 and later do not support implicit function declarations}}
   // c-note@-7 {{include the header <setjmp.h> or explicitly provide a declaration for 'setjmp'}}
   #else
   // cxx-no-diagnostics
diff --git a/clang/test/Sema/implicit-builtin-decl.c b/clang/test/Sema/implicit-builtin-decl.c
index 055ba7e70eb12..a36263a27d14c 100644
--- a/clang/test/Sema/implicit-builtin-decl.c
+++ b/clang/test/Sema/implicit-builtin-decl.c
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -Wno-strict-prototypes -verify %s
 
 void f() {
-  int *ptr = malloc(sizeof(int) * 10); // expected-error{{call to undeclared library function 'malloc' with type}} \
+  int *ptr = malloc(sizeof(int) * 10); // expected-error{{call to undeclared library function 'malloc'}} \
   // expected-note{{include the header <stdlib.h> or explicitly provide a declaration for 'malloc'}} \
   // expected-note{{'malloc' is a builtin with type 'void *}}
 }
diff --git a/clang/test/SemaObjC/builtin_objc_lib_functions.m b/clang/test/SemaObjC/builtin_objc_lib_functions.m
index a98abdf6039cb..449ae5edfb34e 100644
--- a/clang/test/SemaObjC/builtin_objc_lib_functions.m
+++ b/clang/test/SemaObjC/builtin_objc_lib_functions.m
@@ -1,27 +1,27 @@
 // RUN: %clang_cc1 -x objective-c %s -fsyntax-only -verify
-Class f0(void) { return objc_getClass("a"); } // expected-error {{call to undeclared library function 'objc_getClass' with type 'id (const char *)'}} \
+Class f0(void) { return objc_getClass("a"); } // expected-error {{call to undeclared library function 'objc_getClass', will assume it exists with type 'id (const char *)'; ISO C99 and later do not support implicit function declarations}} \
 					  // expected-note {{include the header <objc/runtime.h> or explicitly provide a declaration for 'objc_getClass'}}
 
-Class f1(void) { return objc_getMetaClass("a"); } // expected-error {{call to undeclared library function 'objc_getMetaClass' with type 'id (const char *)'}} \
+Class f1(void) { return objc_getMetaClass("a"); } // expected-error {{call to undeclared library function 'objc_getMetaClass', will assume it exists with type 'id (const char *)'; ISO C99 and later do not support implicit function declarations}} \
 					  // expected-note {{include the header <objc/runtime.h> or explicitly provide a declaration for 'objc_getMetaClass'}}
 
-void f2(id val) { objc_enumerationMutation(val); } // expected-error {{call to undeclared library function 'objc_enumerationMutation' with type 'void (id)'}} \
+void f2(id val) { objc_enumerationMutation(val); } // expected-error {{call to undeclared library function 'objc_enumerationMutation', will assume it exists with type 'void (id)'; ISO C99 and later do not support implicit function declarations}} \
 						   // expected-note {{include the header <objc/runtime.h> or explicitly provide a declaration for 'objc_enumerationMutation'}}
 
-long double f3(id self, SEL op) { return objc_msgSend_fpret(self, op); } // expected-error {{call to undeclared library function 'objc_msgSend_fpret' with type 'long double (id, SEL, ...)'}} \
+long double f3(id self, SEL op) { return objc_msgSend_fpret(self, op); } // expected-error {{call to undeclared library function 'objc_msgSend_fpret', will assume it exists with type 'long double (id, SEL, ...)'; ISO C99 and later do not support implicit function declarations}} \
     // expected-note {{include the header <objc/message.h> or explicitly provide a declaration for 'objc_msgSend_fpret'}}
 
 id f4(struct objc_super *super, SEL op) { // expected-warning {{declaration of 'struct objc_super' will not be visible outside of this function}}
-  return objc_msgSendSuper(super, op); // expected-error {{call to undeclared library function 'objc_msgSendSuper' with type 'id (struct objc_super *, SEL, ...)'}} \
+  return objc_msgSendSuper(super, op); // expected-error {{call to undeclared library function 'objc_msgSendSuper', will assume it exists with type 'id (struct objc_super *, SEL, ...)'; ISO C99 and later do not support implicit function declarations}} \
 					// expected-note {{include the header <objc/message.h> or explicitly provide a declaration for 'objc_msgSendSuper'}}
 }
 
 id f5(id val, id *dest) {
-  return objc_assign_strongCast(val, dest); // expected-error {{call to undeclared library function 'objc_assign_strongCast' with type 'id (id, id *)'}} \
+  return objc_assign_strongCast(val, dest); // expected-error {{call to undeclared library function 'objc_assign_strongCast', will assume it exists with type 'id (id, id *)'; ISO C99 and later do not support implicit function declarations}} \
 					    // expected-note {{include the header <objc/objc-auto.h> or explicitly provide a declaration for 'objc_assign_strongCast'}}
 }
 
 int f6(Class exceptionClass, id exception) {
-  return objc_exception_match(exceptionClass, exception); // expected-error {{call to undeclared library function 'objc_exception_match' with type 'int (id, id)'}} \
+  return objc_exception_match(exceptionClass, exception); // expected-error {{call to undeclared library function 'objc_exception_match', will assume it exists with type 'int (id, id)'; ISO C99 and later do not support implicit function declarations}} \
   							  // expected-note {{include the header <objc/objc-exception.h> or explicitly provide a declaration for 'objc_exception_match'}}
 }
diff --git a/clang/test/SemaObjC/builtin_objc_nslog.m b/clang/test/SemaObjC/builtin_objc_nslog.m
index 3c35a02d9b8a3..855d861516f72 100644
--- a/clang/test/SemaObjC/builtin_objc_nslog.m
+++ b/clang/test/SemaObjC/builtin_objc_nslog.m
@@ -3,11 +3,11 @@
 #include <stdarg.h>
 
 void f1(id arg) {
-  NSLog(@"%@", arg); // expected-error {{call to undeclared library function 'NSLog' with type 'void (id, ...)'}} \
+  NSLog(@"%@", arg); // expected-error {{call to undeclared library function 'NSLog', will assume it exists with type 'void (id, ...)'; ISO C99 and later do not support implicit function declaration}} \
   // expected-note {{include the header <Foundation/NSObjCRuntime.h> or explicitly provide a declaration for 'NSLog'}}
 }
 
 void f2(id str, va_list args) {
-  NSLogv(@"%@", args); // expected-error {{call to undeclared library function 'NSLogv' with type }} \
+  NSLogv(@"%@", args); // expected-error {{call to undeclared library function 'NSLogv', will assume it exists with type 'void (id, __builtin_va_list)'; ISO C99 and later do not support implicit function declarations}} \
   // expected-note {{include the header <Foundation/NSObjCRuntime.h> or explicitly provide a declaration for 'NSLogv'}}
 }

@@ -22,7 +22,7 @@ void_typedef f2_helper(void);
static void f2(void *buf) {
F12_typedef* x;
x = f2_helper();
memcpy((&x[1]), (buf), 1); // expected-warning{{call to undeclared library function 'memcpy' with type 'void *(void *, const void *}} \
memcpy((&x[1]), (buf), 1); // expected-warning{{call to undeclared library function 'memcpy', will assume it exists with standards-mandated type 'void *(void *, const void *,}} \
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, there's another type in the parameter list, but it's size_t which resolves to different types on different systems, so it's dropped here for the same reason it was dropped before.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The target tripple is pinned in the test. We could spell it out if we wanted.
But it's also fine if we rtrim it after ... 'memcpy'.
No action expected here. I just left this if you find this useful.

@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -Wno-strict-prototypes -verify %s

void f() {
int *ptr = malloc(sizeof(int) * 10); // expected-error{{call to undeclared library function 'malloc' with type}} \
int *ptr = malloc(sizeof(int) * 10); // expected-error{{call to undeclared library function 'malloc'}} \
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing happening here as above.

Comment on lines +719 to +722
- Reworded the ``-Wimplicit-function-declaration`` diagnostic to make it more
clear that the type selected for the implicit declaration is based on the
signature of a standard (C, C++, POSIX) library function. (#GH146924)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you double check this is aligned as it should?

Comment on lines +383 to +404
bool isDeclaredInStandardHeader(unsigned ID) const {
switch (getInfo(ID).Header.ID) {
default:
return false;
case HeaderDesc::COMPLEX_H: // C99
case HeaderDesc::CTYPE_H: // C89
case HeaderDesc::MATH_H: // C89
case HeaderDesc::MALLOC_H: // POSIX
case HeaderDesc::MEMORY: // C++98
case HeaderDesc::PTHREAD_H: // POSIX
case HeaderDesc::SETJMP_H: // C89
case HeaderDesc::STDARG_H: // C89
case HeaderDesc::STDIO_H: // C89
case HeaderDesc::STDLIB_H: // C89
case HeaderDesc::STRING_H: // C89
case HeaderDesc::STRINGS_H: // POSIX
case HeaderDesc::UNISTD_H: // POSIX
case HeaderDesc::UTILITY: // C++98
case HeaderDesc::WCHAR_H: // C99
return true;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we modify the HEADER macro in BuiltinHeaders.def to generate that automatically?

Comment on lines 818 to 825
def ext_implicit_lib_function_decl : ExtWarn<
"implicitly declaring library function '%0' with type %1">,
InGroup<ImplicitFunctionDeclare>;
"implicitly declaring library function '%0' with%select{| standards-mandated}2 "
"type %1">, InGroup<ImplicitFunctionDeclare>;
def ext_implicit_lib_function_decl_c99 : ExtWarn<
"call to undeclared library function '%0' with type %1; ISO C99 and later "
"do not support implicit function declarations">,
"call to undeclared library function '%0', will assume it exists with"
"%select{| standards-mandated}2 type %1; ISO C99 and later do not support "
"implicit function declarations">,
InGroup<ImplicitFunctionDeclare>, DefaultError;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A way to simplify (ie, get rid of isDeclaredInStandardHeader)
would be to say " will assume it exists with type %1 as if header <%2>" had been included"

(where %2 is Context.BuiltinInfo.getName(ID))

WDYT?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:diagnostics New/improved warning or error message in Clang, but not in clang-tidy or static analyzer clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:static analyzer clang Clang issues not falling into any other category quality-of-implementation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Clang] improve -Wimplicit-function-declaration wording
4 participants