diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -146,6 +146,8 @@ uses the optional USR value when indexing Clang's AST. This value is expected to be generated by an external compiler when generating C++ bindings during the compilation of the foreign language sources (e.g. Swift). +- The ``__has_attribute``, ``__has_c_attribute`` and ``__has_cpp_attribute`` + preprocessor operators now return 1 also for attributes defined by plugins. Improvements to Clang's diagnostics ----------------------------------- 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,11 @@ if (res) return res; + // Check if any plugin provides this attribute. + for (auto &Ptr : getAttributePluginInstances()) + if (Ptr->hasSpelling(Syntax, 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