[clang][pp] Handle attributes defined by plugin in __has_attribute

When using attributes by plugins (both in clang and clang-tidy) the
preprocessor functions `__has_attribute`, `__has_c_attribute`,
`__has_cpp_attribute` still returned 0.

That problem is fixed by having the "hasAttribute" function also check
if any of the plugins provide that attribute.

This also adds C2x spelling to the example plugin for attributes so that
`__has_c_attribute` can be tested.

Differential Revision: https://reviews.llvm.org/D144405
This commit is contained in:
Anders Waldenborg 2023-02-12 22:12:08 +01:00
parent 8629343a8b
commit 1285a495d5
4 changed files with 40 additions and 1 deletions

View File

@ -147,6 +147,8 @@ Attribute Changes in Clang
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
-----------------------------------

View File

@ -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 @@ struct ExampleAttrInfo : public ParsedAttrInfo {
// 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;

View File

@ -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 @@ int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
if (res)
return res;
// Check if any plugin provides this attribute.
for (auto &Ptr : getAttributePluginInstances())
if (Ptr->hasSpelling(Syntax, Name))
return 1;
return 0;
}

View File

@ -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