<div dir="ltr">For instance here are the kind of errors I have by running a sanitized clang on master (with or without my patch it doesn't make a difference)<div><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">cd /redacted/git/llvm-project/llvm/build-msan && /redacted/git/llvm-project/llvm/build-msan/bin/llvm-tblgen -gen-opt-parser-defs -I /redacted/git/llvm-project/llvm/tools/llvm-lipo -I /redacted/git/llvm-project/llvm/include /redacted/git/llvm-project/llvm/tools/llvm-lipo/LipoOpts.td --write-if-changed -o tools/llvm-lipo/LipoOpts.inc -d tools/llvm-lipo/LipoOpts.inc.d<br>==127351==WARNING: MemorySanitizer: use-of-uninitialized-value<br>    #0 0x1015ae9 in llvm::StringRef::split(llvm::SmallVectorImpl<llvm::StringRef>&, char, int, bool) const /redacted/git/llvm-project/llvm/build-msan/../lib/Support/StringRef.cpp:348:3<br>    #1 0x102e1d5 in llvm::Triple::Triple(llvm::Twine const&) /redacted/git/llvm-project/llvm/build-msan/../lib/Support/Triple.cpp:731:19<br>    #2 0x107dd7d in llvm::sys::getProcessTriple() /redacted/git/llvm-project/llvm/build-msan/../lib/Support/Host.cpp:1532:10<br>    #3 0xf873d7 in ParseCommandLineOptions /redacted/git/llvm-project/llvm/build-msan/../lib/Support/CommandLine.cpp:1267:17<br>    #4 0xf873d7 in llvm::cl::ParseCommandLineOptions(int, char const* const*, llvm::StringRef, llvm::raw_ostream*, char const*, bool) /redacted/git/llvm-project/llvm/build-msan/../lib/Support/CommandLine.cpp:1242:24<br>    #5 0xef2ea7 in main /redacted/git/llvm-project/llvm/build-msan/../utils/TableGen/TableGen.cpp:267:3<br>    #6 0x7f6202abf52a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2352a)<br>    #7 0x42d4a9 in _start (/redacted/git/llvm-project/llvm/build-msan/bin/llvm-tblgen+0x42d4a9)<br>  Uninitialized value was stored to memory at<br>    #0 0x102ecc6 in StringRef /redacted/git/llvm-project/llvm/build-msan/../include/llvm/ADT/StringRef.h:111:27<br>    #1 0x102ecc6 in llvm::Triple::Triple(llvm::Twine const&) /redacted/git/llvm-project/llvm/build-msan/../lib/Support/Triple.cpp:731:3<br>    #2 0x107dd7d in llvm::sys::getProcessTriple() /redacted/git/llvm-project/llvm/build-msan/../lib/Support/Host.cpp:1532:10<br>    #3 0xf873d7 in ParseCommandLineOptions /redacted/git/llvm-project/llvm/build-msan/../lib/Support/CommandLine.cpp:1267:17<br>    #4 0xf873d7 in llvm::cl::ParseCommandLineOptions(int, char const* const*, llvm::StringRef, llvm::raw_ostream*, char const*, bool) /redacted/git/llvm-project/llvm/build-msan/../lib/Support/CommandLine.cpp:1242:24<br>    #5 0xef2ea7 in main /redacted/git/llvm-project/llvm/build-msan/../utils/TableGen/TableGen.cpp:267:3<br>    #6 0x7f6202abf52a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2352a)<br>  Uninitialized value was created by an allocation of 'PT' in the stack frame of function '_ZN4llvm3sys16getProcessTripleEv'<br>    #0 0x107d9a0 in llvm::sys::getProcessTriple() /redacted/git/llvm-project/llvm/build-msan/../lib/Support/Host.cpp:1530<br></blockquote></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Oct 29, 2019 at 1:32 PM Guillaume Chatelet <<a href="mailto:gchatelet@google.com">gchatelet@google.com</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"><div dir="ltr">hi Vlad,<div><br></div><div>I've spend a big part of my day digging into this and I'm less and less convinced that my patch broke the builds.</div><div>IIUC the built bots are still failing although my patch has been reverted for quite some time now.</div><div><br></div><div>Am I missing something?</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Oct 28, 2019 at 11:24 PM Vlad Tsyrklevich <<a href="mailto:vlad@tsyrklevich.net" target="_blank">vlad@tsyrklevich.net</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"><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" target="_blank">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" target="_blank">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" target="_blank">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>
</blockquote></div>
</blockquote></div>