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
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Comment on lines +719 to +722
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?

Improvements to Clang's time-trace
----------------------------------

Expand Down
27 changes: 27 additions & 0 deletions clang/include/clang/Basic/Builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Comment on lines +383 to +404
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?


/// 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.
Expand Down
9 changes: 5 additions & 4 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Comment on lines 818 to 825
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?

def note_include_header_or_declare : Note<
"include the header <%0> or explicitly provide a declaration for '%1'">;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Analysis/exercise-ps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.

// expected-note{{include the header <string.h> or explicitly provide a declaration for 'memcpy'}}
}

Expand Down
2 changes: 1 addition & 1 deletion clang/test/Driver/implicit-function-as-error.c
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
}
2 changes: 1 addition & 1 deletion clang/test/Sema/builtin-setjmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Sema/implicit-builtin-decl.c
Original file line number Diff line number Diff line change
@@ -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.

// expected-note{{include the header <stdlib.h> or explicitly provide a declaration for 'malloc'}} \
// expected-note{{'malloc' is a builtin with type 'void *}}
}
Expand Down
14 changes: 7 additions & 7 deletions clang/test/SemaObjC/builtin_objc_lib_functions.m
Original file line number Diff line number Diff line change
@@ -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'}}
}
4 changes: 2 additions & 2 deletions clang/test/SemaObjC/builtin_objc_nslog.m
Original file line number Diff line number Diff line change
Expand Up @@ -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'}}
}
Loading