diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -147,6 +147,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,28 @@ +// RUN: %clang -fplugin=%llvmshlibdir/Attribute%pluginext -E %s | FileCheck %s +// RUN: %clang -fplugin=%llvmshlibdir/Attribute%pluginext -E %s -x c | FileCheck %s +// REQUIRES: plugins, examples + +#ifdef __cplusplus +# define HAS_ATTR(a) __has_cpp_attribute (a) +#else +# define HAS_ATTR(a) __has_c_attribute (a) +#endif + +#if __has_attribute(example) +// CHECK: has_attribute(example) was true +has_attribute(example) was true +#endif +#if HAS_ATTR(example) +// CHECK: has_$LANG_attribute(example) was true +has_$LANG_attribute(example) was true +#endif + +#if __has_attribute(doesnt_exist) +// CHECK-NOT: has_attribute(doesnt_exist) unexpectedly was true +has_attribute(doesnt_exist) unexpectedly was true +#endif + +#if HAS_ATTR(doesnt_exist) +// CHECK-NOT: has_$LANG_attribute(doesnt_exist) unexpectedly was true +has_$LANG_attribute(doesnt_exist) unexpectedly was true +#endif