<div dir="ltr">I've reverted this change as it was causing ASan/MSan failures in check-clang, e.g. take a look at the bottom 2 failures here: <a href="http://lab.llvm.org:8014/builders/sanitizer-x86_64-linux-bootstrap/builds/124/steps/check-clang%20asan/logs/stdio">http://lab.llvm.org:8014/builders/sanitizer-x86_64-linux-bootstrap/builds/124/steps/check-clang%20asan/logs/stdio</a> or here <a href="http://lab.llvm.org:8014/builders/sanitizer-x86_64-linux-fast/builds/126/steps/check-clang%20msan/logs/stdio">http://lab.llvm.org:8014/builders/sanitizer-x86_64-linux-fast/builds/126/steps/check-clang%20msan/logs/stdio</a></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Oct 28, 2019 at 9:30 AM Guillaume Chatelet via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
Author: Guillaume Chatelet<br>
Date: 2019-10-28T17:30:11+01:00<br>
New Revision: bd87916109483d33455cbf20da2309197b983cdd<br>
<br>
URL: <a href="https://github.com/llvm/llvm-project/commit/bd87916109483d33455cbf20da2309197b983cdd" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/bd87916109483d33455cbf20da2309197b983cdd</a><br>
DIFF: <a href="https://github.com/llvm/llvm-project/commit/bd87916109483d33455cbf20da2309197b983cdd.diff" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/bd87916109483d33455cbf20da2309197b983cdd.diff</a><br>
<br>
LOG: [clang] Add no_builtin attribute<br>
<br>
Summary:<br>
This is a follow up on <a href="https://reviews.llvm.org/D61634" rel="noreferrer" target="_blank">https://reviews.llvm.org/D61634</a><br>
This patch is simpler and only adds the no_builtin attribute.<br>
<br>
Reviewers: tejohnson, courbet, theraven, t.p.northover, jdoerfert<br>
<br>
Subscribers: mgrang, cfe-commits<br>
<br>
Tags: #clang<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D68028" rel="noreferrer" target="_blank">https://reviews.llvm.org/D68028</a><br>
<br>
Added: <br>
clang/test/CodeGen/no-builtin.cpp<br>
clang/test/Sema/no-builtin.cpp<br>
<br>
Modified: <br>
clang/include/clang/AST/Decl.h<br>
clang/include/clang/Basic/Attr.td<br>
clang/include/clang/Basic/AttrDocs.td<br>
clang/include/clang/Basic/DiagnosticSemaKinds.td<br>
clang/lib/CodeGen/CGCall.cpp<br>
clang/lib/Sema/SemaDecl.cpp<br>
clang/lib/Sema/SemaDeclAttr.cpp<br>
clang/test/Misc/pragma-attribute-supported-attributes-list.test<br>
<br>
Removed: <br>
<br>
<br>
<br>
################################################################################<br>
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h<br>
index b3e7a570fd6d..16094c0988fa 100644<br>
--- a/clang/include/clang/AST/Decl.h<br>
+++ b/clang/include/clang/AST/Decl.h<br>
@@ -2031,6 +2031,10 @@ class FunctionDecl : public DeclaratorDecl,<br>
///<br>
/// This does not determine whether the function has been defined (e.g., in a<br>
/// previous definition); for that information, use isDefined.<br>
+ ///<br>
+ /// Note: the function declaration does not become a definition until the<br>
+ /// parser reaches the definition, if called before, this function will return<br>
+ /// `false`.<br>
bool isThisDeclarationADefinition() const {<br>
return isDeletedAsWritten() || isDefaulted() || Body || hasSkippedBody() ||<br>
isLateTemplateParsed() || willHaveBody() || hasDefiningAttr();<br>
<br>
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td<br>
index 4557a614d361..d5018f444e1c 100644<br>
--- a/clang/include/clang/Basic/Attr.td<br>
+++ b/clang/include/clang/Basic/Attr.td<br>
@@ -3427,3 +3427,10 @@ def ObjCExternallyRetained : InheritableAttr {<br>
let Subjects = SubjectList<[NonParmVar, Function, Block, ObjCMethod]>;<br>
let Documentation = [ObjCExternallyRetainedDocs];<br>
}<br>
+<br>
+def NoBuiltin : Attr {<br>
+ let Spellings = [Clang<"no_builtin">];<br>
+ let Args = [VariadicStringArgument<"BuiltinNames">];<br>
+ let Subjects = SubjectList<[Function]>;<br>
+ let Documentation = [NoBuiltinDocs];<br>
+}<br>
<br>
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td<br>
index 6e79d0bb3631..9d0d27407573 100644<br>
--- a/clang/include/clang/Basic/AttrDocs.td<br>
+++ b/clang/include/clang/Basic/AttrDocs.td<br>
@@ -4413,3 +4413,40 @@ and is not a general mechanism for declaring arbitrary aliases for<br>
clang builtin functions.<br>
}];<br>
}<br>
+<br>
+def NoBuiltinDocs : Documentation {<br>
+ let Category = DocCatFunction;<br>
+ let Content = [{<br>
+.. Note:: This attribute is not yet fully implemented, it is validated but has<br>
+no effect on the generated code.<br>
+<br>
+The ``__attribute__((no_builtin))`` is similar to the ``-fno-builtin`` flag<br>
+except it is specific to the body of a function. The attribute may also be<br>
+applied to a virtual function but has no effect on the behavior of overriding<br>
+functions in a derived class.<br>
+<br>
+It accepts one or more strings corresponding to the specific names of the<br>
+builtins to disable (e.g. "memcpy", "memset").<br>
+If the attribute is used without parameters it will disable all buitins at<br>
+once.<br>
+<br>
+.. code-block:: c++<br>
+<br>
+ // The compiler is not allowed to add any builtin to foo's body.<br>
+ void foo(char* data, size_t count) __attribute__((no_builtin)) {<br>
+ // The compiler is not allowed to convert the loop into<br>
+ // `__builtin_memset(data, 0xFE, count);`.<br>
+ for (size_t i = 0; i < count; ++i)<br>
+ data[i] = 0xFE;<br>
+ }<br>
+<br>
+ // The compiler is not allowed to add the `memcpy` builtin to bar's body.<br>
+ void bar(char* data, size_t count) __attribute__((no_builtin("memcpy"))) {<br>
+ // The compiler is allowed to convert the loop into<br>
+ // `__builtin_memset(data, 0xFE, count);` but cannot generate any<br>
+ // `__builtin_memcpy`<br>
+ for (size_t i = 0; i < count; ++i)<br>
+ data[i] = 0xFE;<br>
+ }<br>
+ }];<br>
+}<br>
<br>
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td<br>
index db877a46c300..20670a98fe03 100644<br>
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td<br>
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td<br>
@@ -3624,6 +3624,15 @@ def err_attribute_overloadable_no_prototype : Error<<br>
def err_attribute_overloadable_multiple_unmarked_overloads : Error<<br>
"at most one overload for a given name may lack the 'overloadable' "<br>
"attribute">;<br>
+def warn_attribute_no_builtin_invalid_builtin_name : Warning<<br>
+ "'%0' is not a valid builtin name for %1">,<br>
+ InGroup<DiagGroup<"invalid-no-builtin-names">>;<br>
+def err_attribute_no_builtin_wildcard_or_builtin_name : Error<<br>
+ "empty %0 cannot be composed with named ones">;<br>
+def err_attribute_no_builtin_on_non_definition : Error<<br>
+ "%0 attribute is permitted on definitions only">;<br>
+def err_attribute_no_builtin_on_defaulted_deleted_function : Error<<br>
+ "%0 attribute has no effect on defaulted or deleted functions">;<br>
def warn_ns_attribute_wrong_return_type : Warning<<br>
"%0 attribute only applies to %select{functions|methods|properties}1 that "<br>
"return %select{an Objective-C object|a pointer|a non-retainable pointer}2">,<br>
<br>
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp<br>
index b74f6f942426..62e8fa037013 100644<br>
--- a/clang/lib/CodeGen/CGCall.cpp<br>
+++ b/clang/lib/CodeGen/CGCall.cpp<br>
@@ -1853,11 +1853,27 @@ void CodeGenModule::ConstructAttributeList(<br>
if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {<br>
AddAttributesFromFunctionProtoType(<br>
getContext(), FuncAttrs, Fn->getType()->getAs<FunctionProtoType>());<br>
- // Don't use [[noreturn]] or _Noreturn for a call to a virtual function.<br>
- // These attributes are not inherited by overloads.<br>
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn);<br>
- if (Fn->isNoReturn() && !(AttrOnCallSite && MD && MD->isVirtual()))<br>
- FuncAttrs.addAttribute(llvm::Attribute::NoReturn);<br>
+ const bool IsVirtualCall = MD && MD->isVirtual();<br>
+ // Don't use [[noreturn]], _Noreturn or [[no_builtin]] for a call to a<br>
+ // virtual function. These attributes are not inherited by overloads.<br>
+ if (!(AttrOnCallSite && IsVirtualCall)) {<br>
+ if (Fn->isNoReturn())<br>
+ FuncAttrs.addAttribute(llvm::Attribute::NoReturn);<br>
+<br>
+ if (const auto *NBA = TargetDecl->getAttr<NoBuiltinAttr>()) {<br>
+ bool HasWildcard = llvm::is_contained(NBA->builtinNames(), "*");<br>
+ if (HasWildcard)<br>
+ FuncAttrs.addAttribute("no-builtins");<br>
+ else<br>
+ for (StringRef BuiltinName : NBA->builtinNames()) {<br>
+ SmallString<32> AttributeName;<br>
+ AttributeName += "no-builtin-";<br>
+ AttributeName += BuiltinName;<br>
+ FuncAttrs.addAttribute(AttributeName);<br>
+ }<br>
+ }<br>
+ }<br>
}<br>
<br>
// 'const', 'pure' and 'noalias' attributed functions are also nounwind.<br>
<br>
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp<br>
index 6202391ee0b8..aba7049b0a51 100644<br>
--- a/clang/lib/Sema/SemaDecl.cpp<br>
+++ b/clang/lib/Sema/SemaDecl.cpp<br>
@@ -9529,6 +9529,29 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,<br>
}<br>
}<br>
<br>
+ // Diagnose no_builtin attribute on function declaration that are not a<br>
+ // definition.<br>
+ // FIXME: We should really be doing this in<br>
+ // SemaDeclAttr.cpp::handleNoBuiltinAttr, unfortunately we only have access to<br>
+ // the FunctionDecl and at this point of the code<br>
+ // FunctionDecl::isThisDeclarationADefinition() which always returns `false`<br>
+ // because Sema::ActOnStartOfFunctionDef has not been called yet.<br>
+ if (const auto *NBA = NewFD->getAttr<NoBuiltinAttr>())<br>
+ switch (D.getFunctionDefinitionKind()) {<br>
+ case FDK_Defaulted:<br>
+ case FDK_Deleted:<br>
+ Diag(NBA->getLocation(),<br>
+ diag::err_attribute_no_builtin_on_defaulted_deleted_function)<br>
+ << NBA->getSpelling();<br>
+ break;<br>
+ case FDK_Declaration:<br>
+ Diag(NBA->getLocation(), diag::err_attribute_no_builtin_on_non_definition)<br>
+ << NBA->getSpelling();<br>
+ break;<br>
+ case FDK_Definition:<br>
+ break;<br>
+ }<br>
+<br>
return NewFD;<br>
}<br>
<br>
<br>
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp<br>
index abbd597a26d0..99eb23c3fe61 100644<br>
--- a/clang/lib/Sema/SemaDeclAttr.cpp<br>
+++ b/clang/lib/Sema/SemaDeclAttr.cpp<br>
@@ -1069,6 +1069,56 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {<br>
S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D)));<br>
}<br>
<br>
+static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) {<br>
+ static constexpr const StringRef kWildcard = "*";<br>
+<br>
+ llvm::SmallVector<StringRef, 16> Names;<br>
+ bool HasWildcard = false;<br>
+<br>
+ const auto AddBuiltinName = [&Names, &HasWildcard](StringRef Name) {<br>
+ if (Name == kWildcard)<br>
+ HasWildcard = true;<br>
+ Names.push_back(Name);<br>
+ };<br>
+<br>
+ // Add previously defined attributes.<br>
+ if (const auto *NBA = D->getAttr<NoBuiltinAttr>())<br>
+ for (StringRef BuiltinName : NBA->builtinNames())<br>
+ AddBuiltinName(BuiltinName);<br>
+<br>
+ // Add current attributes.<br>
+ if (AL.getNumArgs() == 0)<br>
+ AddBuiltinName(kWildcard);<br>
+ else<br>
+ for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {<br>
+ StringRef BuiltinName;<br>
+ SourceLocation LiteralLoc;<br>
+ if (!S.checkStringLiteralArgumentAttr(AL, I, BuiltinName, &LiteralLoc))<br>
+ return;<br>
+<br>
+ if (Builtin::Context::isBuiltinFunc(BuiltinName.data()))<br>
+ AddBuiltinName(BuiltinName);<br>
+ else<br>
+ S.Diag(LiteralLoc, diag::warn_attribute_no_builtin_invalid_builtin_name)<br>
+ << BuiltinName << AL.getAttrName()->getName();<br>
+ }<br>
+<br>
+ // Repeating the same attribute is fine.<br>
+ llvm::sort(Names);<br>
+ Names.erase(std::unique(Names.begin(), Names.end()), Names.end());<br>
+<br>
+ // Empty no_builtin must be on its own.<br>
+ if (HasWildcard && Names.size() > 1)<br>
+ S.Diag(D->getLocation(),<br>
+ diag::err_attribute_no_builtin_wildcard_or_builtin_name)<br>
+ << AL.getAttrName()->getName();<br>
+<br>
+ if (D->hasAttr<NoBuiltinAttr>())<br>
+ D->dropAttr<NoBuiltinAttr>();<br>
+ D->addAttr(::new (S.Context)<br>
+ NoBuiltinAttr(S.Context, AL, Names.data(), Names.size()));<br>
+}<br>
+<br>
static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {<br>
if (D->hasAttr<PassObjectSizeAttr>()) {<br>
S.Diag(D->getBeginLoc(), diag::err_attribute_only_once_per_parameter) << AL;<br>
@@ -6608,6 +6658,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,<br>
case ParsedAttr::AT_DiagnoseIf:<br>
handleDiagnoseIfAttr(S, D, AL);<br>
break;<br>
+ case ParsedAttr::AT_NoBuiltin:<br>
+ handleNoBuiltinAttr(S, D, AL);<br>
+ break;<br>
case ParsedAttr::AT_ExtVectorType:<br>
handleExtVectorTypeAttr(S, D, AL);<br>
break;<br>
<br>
diff --git a/clang/test/CodeGen/no-builtin.cpp b/clang/test/CodeGen/no-builtin.cpp<br>
new file mode 100644<br>
index 000000000000..3c5d681282da<br>
--- /dev/null<br>
+++ b/clang/test/CodeGen/no-builtin.cpp<br>
@@ -0,0 +1,64 @@<br>
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - %s | FileCheck %s<br>
+<br>
+// CHECK-LABEL: define void @foo_no_mempcy() #0<br>
+extern "C" void foo_no_mempcy() __attribute__((no_builtin("memcpy"))) {}<br>
+<br>
+// CHECK-LABEL: define void @foo_no_mempcy_twice() #0<br>
+extern "C" void foo_no_mempcy_twice() __attribute__((no_builtin("memcpy"))) __attribute__((no_builtin("memcpy"))) {}<br>
+<br>
+// CHECK-LABEL: define void @foo_no_builtins() #1<br>
+extern "C" void foo_no_builtins() __attribute__((no_builtin)) {}<br>
+<br>
+// CHECK-LABEL: define void @foo_no_mempcy_memset() #2<br>
+extern "C" void foo_no_mempcy_memset() __attribute__((no_builtin("memset", "memcpy"))) {}<br>
+<br>
+// CHECK-LABEL: define void @separate_attrs() #2<br>
+extern "C" void separate_attrs() __attribute__((no_builtin("memset"))) __attribute__((no_builtin("memcpy"))) {}<br>
+<br>
+// CHECK-LABEL: define void @separate_attrs_ordering() #2<br>
+extern "C" void separate_attrs_ordering() __attribute__((no_builtin("memcpy"))) __attribute__((no_builtin("memset"))) {}<br>
+<br>
+struct A {<br>
+ virtual int foo() const __attribute__((no_builtin("memcpy"))) { return 1; }<br>
+ virtual ~A();<br>
+};<br>
+<br>
+struct B : public A {<br>
+ int foo() const override __attribute__((no_builtin("memmove"))) { return 2; }<br>
+ virtual ~B();<br>
+};<br>
+<br>
+// CHECK-LABEL: define void @call_a_foo(%struct.A* %a) #3<br>
+extern "C" void call_a_foo(A *a) {<br>
+ // CHECK: %call = call i32 %2(%struct.A* %0)<br>
+ a->foo(); // virtual call is not annotated<br>
+}<br>
+<br>
+// CHECK-LABEL: define void @call_b_foo(%struct.B* %b) #3<br>
+extern "C" void call_b_foo(B *b) {<br>
+ // CHECK: %call = call i32 %2(%struct.B* %0)<br>
+ b->foo(); // virtual call is not annotated<br>
+}<br>
+<br>
+// CHECK-LABEL: define void @call_foo_no_mempcy() #3<br>
+extern "C" void call_foo_no_mempcy() {<br>
+ // CHECK: call void @foo_no_mempcy() #6<br>
+ foo_no_mempcy(); // call gets annotated with "no-builtin-memcpy"<br>
+}<br>
+<br>
+A::~A() {} // Anchoring A so A::foo() gets generated<br>
+B::~B() {} // Anchoring B so B::foo() gets generated<br>
+<br>
+// CHECK-LABEL: define linkonce_odr i32 @_ZNK1A3fooEv(%struct.A* %this) unnamed_addr #0 comdat align 2<br>
+// CHECK-LABEL: define linkonce_odr i32 @_ZNK1B3fooEv(%struct.B* %this) unnamed_addr #5 comdat align 2<br>
+<br>
+// CHECK: attributes #0 = {{{.*}}"no-builtin-memcpy"{{.*}}}<br>
+// CHECK-NOT: attributes #0 = {{{.*}}"no-builtin-memmove"{{.*}}}<br>
+// CHECK-NOT: attributes #0 = {{{.*}}"no-builtin-memset"{{.*}}}<br>
+// CHECK: attributes #1 = {{{.*}}"no-builtins"{{.*}}}<br>
+// CHECK: attributes #2 = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}}<br>
+// CHECK-NOT: attributes #2 = {{{.*}}"no-builtin-memmove"{{.*}}}<br>
+// CHECK: attributes #5 = {{{.*}}"no-builtin-memmove"{{.*}}}<br>
+// CHECK-NOT: attributes #5 = {{{.*}}"no-builtin-memcpy"{{.*}}}<br>
+// CHECK-NOT: attributes #5 = {{{.*}}"no-builtin-memset"{{.*}}}<br>
+// CHECK: attributes #6 = { "no-builtin-memcpy" }<br>
<br>
diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test<br>
index 25802bd73c51..729e9b7a6f77 100644<br>
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test<br>
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test<br>
@@ -75,6 +75,7 @@<br>
// CHECK-NEXT: NSConsumed (SubjectMatchRule_variable_is_parameter)<br>
// CHECK-NEXT: NSConsumesSelf (SubjectMatchRule_objc_method)<br>
// CHECK-NEXT: Naked (SubjectMatchRule_function)<br>
+// CHECK-NEXT: NoBuiltin (SubjectMatchRule_function)<br>
// CHECK-NEXT: NoCommon (SubjectMatchRule_variable)<br>
// CHECK-NEXT: NoDebug (SubjectMatchRule_type_alias, SubjectMatchRule_hasType_functionType, SubjectMatchRule_objc_method, SubjectMatchRule_variable_not_is_parameter)<br>
// CHECK-NEXT: NoDestroy (SubjectMatchRule_variable)<br>
<br>
diff --git a/clang/test/Sema/no-builtin.cpp b/clang/test/Sema/no-builtin.cpp<br>
new file mode 100644<br>
index 000000000000..40781abd3037<br>
--- /dev/null<br>
+++ b/clang/test/Sema/no-builtin.cpp<br>
@@ -0,0 +1,51 @@<br>
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s<br>
+<br>
+/// Prevent use of all builtins.<br>
+void valid_attribute_all_1() __attribute__((no_builtin)) {}<br>
+void valid_attribute_all_2() __attribute__((no_builtin())) {}<br>
+<br>
+/// Prevent use of specific builtins.<br>
+void valid_attribute_function() __attribute__((no_builtin("memcpy"))) {}<br>
+void valid_attribute_functions() __attribute__((no_builtin("memcpy"))) __attribute__((no_builtin("memcmp"))) {}<br>
+<br>
+/// Many times the same builtin is fine.<br>
+void many_attribute_function_1() __attribute__((no_builtin)) __attribute__((no_builtin)) {}<br>
+void many_attribute_function_2() __attribute__((no_builtin("memcpy"))) __attribute__((no_builtin("memcpy"))) {}<br>
+void many_attribute_function_3() __attribute__((no_builtin("memcpy", "memcpy"))) {}<br>
+void many_attribute_function_4() __attribute__((no_builtin("memcpy", "memcpy"))) __attribute__((no_builtin("memcpy"))) {}<br>
+<br>
+/// Invalid builtin name.<br>
+void invalid_builtin() __attribute__((no_builtin("not_a_builtin"))) {}<br>
+// expected-warning@-1 {{'not_a_builtin' is not a valid builtin name for no_builtin}}<br>
+<br>
+/// Can't use bare no_builtin with a named one.<br>
+void wildcard_and_functionname() __attribute__((no_builtin)) __attribute__((no_builtin("memcpy"))) {}<br>
+// expected-error@-1 {{empty no_builtin cannot be composed with named ones}}<br>
+<br>
+/// Can't attach attribute to a variable.<br>
+int __attribute__((no_builtin)) variable;<br>
+// expected-warning@-1 {{'no_builtin' attribute only applies to functions}}<br>
+<br>
+/// Can't attach attribute to a declaration.<br>
+void nobuiltin_on_declaration() __attribute__((no_builtin));<br>
+// expected-error@-1 {{no_builtin attribute is permitted on definitions only}}<br>
+<br>
+struct S {<br>
+ /// Can't attach attribute to a defaulted function,<br>
+ S()<br>
+ __attribute__((no_builtin)) = default;<br>
+ // expected-error@-1 {{no_builtin attribute has no effect on defaulted or deleted functions}}<br>
+<br>
+ /// Can't attach attribute to a deleted function,<br>
+ S(const S &)<br>
+ __attribute__((no_builtin)) = delete;<br>
+ // expected-error@-1 {{no_builtin attribute has no effect on defaulted or deleted functions}}<br>
+<br>
+ void whatever() __attribute__((no_builtin("memcpy")));<br>
+ // expected-error@-1 {{no_builtin attribute is permitted on definitions only}}<br>
+};<br>
+<br>
+/// Can't attach attribute to an aliased function.<br>
+void alised_function() {}<br>
+void aliasing_function() __attribute__((no_builtin)) __attribute__((alias("alised_function")));<br>
+// expected-error@-1 {{no_builtin attribute is permitted on definitions only}}<br>
<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>