[clang] bd87916 - [clang] Add no_builtin attribute

Guillaume Chatelet via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 29 05:43:56 PDT 2019


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)

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
> ==127351==WARNING: MemorySanitizer: use-of-uninitialized-value
>     #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
>     #1 0x102e1d5 in llvm::Triple::Triple(llvm::Twine const&)
> /redacted/git/llvm-project/llvm/build-msan/../lib/Support/Triple.cpp:731:19
>     #2 0x107dd7d in llvm::sys::getProcessTriple()
> /redacted/git/llvm-project/llvm/build-msan/../lib/Support/Host.cpp:1532:10
>     #3 0xf873d7 in ParseCommandLineOptions
> /redacted/git/llvm-project/llvm/build-msan/../lib/Support/CommandLine.cpp:1267:17
>     #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
>     #5 0xef2ea7 in main
> /redacted/git/llvm-project/llvm/build-msan/../utils/TableGen/TableGen.cpp:267:3
>     #6 0x7f6202abf52a in __libc_start_main
> (/lib/x86_64-linux-gnu/libc.so.6+0x2352a)
>     #7 0x42d4a9 in _start
> (/redacted/git/llvm-project/llvm/build-msan/bin/llvm-tblgen+0x42d4a9)
>   Uninitialized value was stored to memory at
>     #0 0x102ecc6 in StringRef
> /redacted/git/llvm-project/llvm/build-msan/../include/llvm/ADT/StringRef.h:111:27
>     #1 0x102ecc6 in llvm::Triple::Triple(llvm::Twine const&)
> /redacted/git/llvm-project/llvm/build-msan/../lib/Support/Triple.cpp:731:3
>     #2 0x107dd7d in llvm::sys::getProcessTriple()
> /redacted/git/llvm-project/llvm/build-msan/../lib/Support/Host.cpp:1532:10
>     #3 0xf873d7 in ParseCommandLineOptions
> /redacted/git/llvm-project/llvm/build-msan/../lib/Support/CommandLine.cpp:1267:17
>     #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
>     #5 0xef2ea7 in main
> /redacted/git/llvm-project/llvm/build-msan/../utils/TableGen/TableGen.cpp:267:3
>     #6 0x7f6202abf52a in __libc_start_main
> (/lib/x86_64-linux-gnu/libc.so.6+0x2352a)
>   Uninitialized value was created by an allocation of 'PT' in the stack
> frame of function '_ZN4llvm3sys16getProcessTripleEv'
>     #0 0x107d9a0 in llvm::sys::getProcessTriple()
> /redacted/git/llvm-project/llvm/build-msan/../lib/Support/Host.cpp:1530
>

On Tue, Oct 29, 2019 at 1:32 PM Guillaume Chatelet <gchatelet at google.com>
wrote:

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


More information about the cfe-commits mailing list