diff --git a/clang/examples/Attribute/Attribute.cpp b/clang/examples/Attribute/Attribute.cpp --- a/clang/examples/Attribute/Attribute.cpp +++ b/clang/examples/Attribute/Attribute.cpp @@ -9,6 +9,8 @@ // Example clang plugin which adds an an annotation to file-scope declarations // with the 'example' attribute. // +// This plugin is used by clang/test/Frontend/plugin-attribute tests. +// //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" @@ -27,9 +29,10 @@ // number of arguments. This just illustrates how many arguments a // `ParsedAttrInfo` can hold, we will not use that much in this example. OptArgs = 15; - // GNU-style __attribute__(("example")) and C++-style [[example]] and + // GNU-style __attribute__(("example")) and C++/C2x-style [[example]] and // [[plugin::example]] supported. static constexpr Spelling S[] = {{ParsedAttr::AS_GNU, "example"}, + {ParsedAttr::AS_C2x, "example"}, {ParsedAttr::AS_CXX11, "example"}, {ParsedAttr::AS_CXX11, "plugin::example"}}; Spellings = S; diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp --- a/clang/lib/Basic/Attributes.cpp +++ b/clang/lib/Basic/Attributes.cpp @@ -2,6 +2,7 @@ #include "clang/Basic/AttrSubjectMatchRules.h" #include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/ParsedAttrInfo.h" using namespace clang; static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name, @@ -40,6 +41,13 @@ if (res) return res; + // Check if any plugin provides this attribute. + for (auto &AttrPlugin : getAttributePluginInstances()) { + for (auto &S : AttrPlugin->Spellings) + if (S.Syntax == Syntax && S.NormalizedFullName == Name) + return 1; + } + return 0; } diff --git a/clang/test/Frontend/plugin-attribute-pp.cpp b/clang/test/Frontend/plugin-attribute-pp.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Frontend/plugin-attribute-pp.cpp @@ -0,0 +1,36 @@ +// RUN: split-file %s %t +// RUN: %clang -fplugin=%llvmshlibdir/Attribute%pluginext -E %t/has_attr.cpp | FileCheck %t/has_attr.cpp +// RUN: %clang -fplugin=%llvmshlibdir/Attribute%pluginext -E %t/has_attr.c | FileCheck %t/has_attr.c +// REQUIRES: plugins, examples + + +//--- has_attr.cpp +#if __has_attribute (example) +// CHECK: YES - It did exist +YES - It did exist +#endif +#if __has_cpp_attribute (example) +// CHECK: YES - It did cpp-exist +YES - It did cpp-exist +#endif + +#if __has_attribute (doesnt_exist) +// CHECK-NOT: NO - There is no such attribute +NO - There is no such attribute +#endif + + +//--- has_attr.c +#if __has_attribute (example) +// CHECK: YES - It did exist +YES - It did exist +#endif +#if __has_c_attribute (example) +// CHECK: YES - It did c-exist +YES - It did c-exist +#endif + +#if __has_attribute (doesnt_exist) +// CHECK-NOT: NO - There is no such attribute +NO - There is no such attribute +#endif