diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3440,3 +3440,11 @@ let Subjects = SubjectList<[ParmVar]>; let Documentation = [ReleaseHandleDocs]; } + +def Builtin : InheritableAttr { + let Spellings = []; + let Args = [UnsignedArgument<"ID">]; + let Subjects = SubjectList<[Function]>; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -225,7 +225,7 @@ } void setObjCKeywordID(tok::ObjCKeywordKind ID) { ObjCOrBuiltinID = ID; } - /// True if setNotBuiltin() was called. + /// True if revertBuiltin() was called. bool hasRevertedBuiltin() const { return ObjCOrBuiltinID == tok::NUM_OBJC_KEYWORDS; } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3164,10 +3164,12 @@ if (const auto *ABAA = getAttr()) { BuiltinID = ABAA->getBuiltinName()->getBuiltinID(); } else { - if (!getIdentifier()) + const auto *Attr = getAttr(); + + if (!Attr) return 0; - BuiltinID = getIdentifier()->getBuiltinID(); + BuiltinID = Attr->getID(); } if (!BuiltinID) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2108,6 +2108,7 @@ false, R->isFunctionProtoType()); New->setImplicit(); + New->addAttr(BuiltinAttr::CreateImplicit(Context, ID)); // Create Decl objects for each parameter, adding them to the // FunctionDecl. @@ -3330,7 +3331,11 @@ // there but not here. NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); RequiresAdjustment = true; - } else if (New->getBuiltinID()) { + } else if (Old->getBuiltinID()) { + // Builtin attribute isn't propagated to the new one yet at this point. + // Check if the old is a builtin. + // TODO: Maybe we should only warn if the redeclaration is compatible? + // Calling Conventions on a Builtin aren't really useful and setting a // default calling convention and cdecl'ing some builtin redeclarations is // common, so warn and ignore the calling convention on the redeclaration. @@ -3756,6 +3761,7 @@ // If the previous declaration was an implicitly-generated builtin // declaration, then at the very least we should use a specialized note. unsigned BuiltinID; + // TODO: Remove isImplicit check? if (Old->isImplicit() && (BuiltinID = Old->getBuiltinID())) { // If it's actually a library-defined builtin function like 'malloc' // or 'printf', just warn about the incompatible redeclaration. @@ -8859,6 +8865,20 @@ if (D.isInvalidType()) NewFD->setInvalidDecl(); + // In C builtins get merged with implicitly lazily created declarations. + // In C++ we need to check if it's a builtin and add the BuiltinAttr here. + if (IdentifierInfo *II = Previous.getLookupName().getAsIdentifierInfo()) { + if (II->getBuiltinID()) { + // A builtin needs to have C linkage. + LinkageSpecDecl *linkage = + dyn_cast(NewFD->getFirstDecl()->getDeclContext()); + if (linkage && linkage->getLanguage() == LinkageSpecDecl::lang_c) { + NewFD->addAttr( + BuiltinAttr::CreateImplicit(Context, II->getBuiltinID())); + } + } + } + // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. bool Invalid = false; diff --git a/clang/test/AST/ast-dump-attr.cpp b/clang/test/AST/ast-dump-attr.cpp --- a/clang/test/AST/ast-dump-attr.cpp +++ b/clang/test/AST/ast-dump-attr.cpp @@ -109,6 +109,7 @@ extern "C" int printf(const char *format, ...); // CHECK: FunctionDecl{{.*}}printf // CHECK-NEXT: ParmVarDecl{{.*}}format{{.*}}'const char *' +// CHECK-NEXT: BuiltinAttr{{.*}}Implicit // CHECK-NEXT: FormatAttr{{.*}}Implicit printf 1 2 alignas(8) extern int x; diff --git a/clang/test/CodeGen/builtin-redeclaration.c b/clang/test/CodeGen/builtin-redeclaration.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/builtin-redeclaration.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -emit-llvm-only %s + +// PR45410 +// Ensure we mark local extern redeclarations with a different type as non-builtin. +void non_builtin() { + extern float exp(); + exp(); // Will crash due to wrong number of arguments if this calls the builtin. +} + +// PR45410 +// We mark exp() builtin as const with -fno-math-errno (default). +// We mustn't do that for extern redeclarations of builtins where the type differs. +float attribute() { + extern float exp(); + return exp(1); +} diff --git a/clang/test/Sema/implicit-builtin-decl.c b/clang/test/Sema/implicit-builtin-decl.c --- a/clang/test/Sema/implicit-builtin-decl.c +++ b/clang/test/Sema/implicit-builtin-decl.c @@ -60,12 +60,15 @@ extern float fmaxf(float, float); -struct __jmp_buf_tag {}; -void sigsetjmp(struct __jmp_buf_tag[1], int); // expected-warning{{declaration of built-in function 'sigsetjmp' requires the declaration of the 'jmp_buf' type, commonly provided in the header .}} +typedef struct __jmp_buf_tag { +} sigjmp_buf[1]; -// CHECK: FunctionDecl {{.*}} col:6 sigsetjmp ' +int sigsetjmp(struct __jmp_buf_tag[1], int); + +// CHECK: FunctionDecl {{.*}} col:5 implicit sigsetjmp ' +// CHECK: FunctionDecl {{.*}} col:5 sigsetjmp ' // CHECK-NOT: FunctionDecl -// CHECK: ReturnsTwiceAttr {{.*}} <{{.*}}> Implicit +// CHECK: ReturnsTwiceAttr {{.*}} <{{.*}}> Inherited Implicit // PR40692 void pthread_create(); // no warning expected