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 @@ -593,6 +593,12 @@ let Subjects = SubjectList<[Function, GlobalVar], ErrorDiag>; let Documentation = [Undocumented]; } +def ClangBuiltinOverride : Attr { + let Spellings = [GCC<"__clang_builtin">]; + let Args = [IdentifierArgument<"BuiltinName">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} def Aligned : InheritableAttr { let Spellings = [GCC<"aligned">, Declspec<"align">, Keyword<"alignas">, 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 @@ -3075,10 +3075,18 @@ /// functions as their wrapped builtins. This shouldn't be done in general, but /// it's useful in Sema to diagnose calls to wrappers based on their semantics. unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const { - if (!getIdentifier()) - return 0; + unsigned BuiltinID; + + if (hasAttr()) { + IdentifierInfo *II = getAttr()->getBuiltinName(); + BuiltinID = II->getBuiltinID(); + } else { + if (!getIdentifier()) + return 0; + + BuiltinID = getIdentifier()->getBuiltinID(); + } - unsigned BuiltinID = getIdentifier()->getBuiltinID(); if (!BuiltinID) return 0; @@ -3102,7 +3110,8 @@ // If the function is marked "overloadable", it has a different mangled name // and is not the C library function. - if (!ConsiderWrapperFunctions && hasAttr()) + if (!ConsiderWrapperFunctions && hasAttr() && + !hasAttr()) return 0; if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5041,6 +5041,13 @@ AL.getAttributeSpellingListIndex())); } +static void handleClangBuiltinOverrideAttribute(Sema &S, Decl *D, + const ParsedAttr &AL) { + D->addAttr(::new (S.Context) ClangBuiltinOverrideAttr( + AL.getRange(), S.Context, AL.getArgAsIdent(0)->Ident, + AL.getAttributeSpellingListIndex())); +} + //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// @@ -7430,6 +7437,10 @@ case ParsedAttr::AT_MSAllocator: handleMSAllocatorAttr(S, D, AL); break; + + case ParsedAttr::AT_ClangBuiltinOverride: + handleClangBuiltinOverrideAttribute(S, D, AL); + break; } } diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -36,6 +36,7 @@ // CHECK-NEXT: Callback (SubjectMatchRule_function) // CHECK-NEXT: Capability (SubjectMatchRule_record, SubjectMatchRule_type_alias) // CHECK-NEXT: CarriesDependency (SubjectMatchRule_variable_is_parameter, SubjectMatchRule_objc_method, SubjectMatchRule_function) +// CHECK-NEXT: ClangBuiltinOverride (SubjectMatchRule_function) // CHECK-NEXT: Cold (SubjectMatchRule_function) // CHECK-NEXT: Common (SubjectMatchRule_variable) // CHECK-NEXT: Constructor (SubjectMatchRule_function)