Skip to content

Commit 75d4d4b

Browse files
Add an attribute registry so plugins can add attributes
When constructing a ParsedAttr the ParsedAttrInfo gets looked up in the AttrInfoMap, which is auto-generated using tablegen. If that lookup fails then we look through the ParsedAttrInfos that plugins have added to the registry and check if any has a spelling that matches. Differential Revision: https://reviews.llvm.org/D31338
1 parent ddd1127 commit 75d4d4b

File tree

5 files changed

+178
-78
lines changed

5 files changed

+178
-78
lines changed

clang/include/clang/Basic/AttributeCommonInfo.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ class AttributeCommonInfo {
134134
const IdentifierInfo *getScopeName() const { return ScopeName; }
135135
SourceLocation getScopeLoc() const { return ScopeLoc; }
136136

137+
/// Gets the normalized full name, which consists of both scope and name and
138+
/// with surrounding underscores removed as appropriate (e.g.
139+
/// __gnu__::__attr__ will be normalized to gnu::attr).
140+
std::string getNormalizedFullName() const;
141+
137142
bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
138143
bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
139144

clang/include/clang/Sema/ParsedAttr.h

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/ADT/SmallVector.h"
2525
#include "llvm/ADT/TinyPtrVector.h"
2626
#include "llvm/Support/Allocator.h"
27+
#include "llvm/Support/Registry.h"
2728
#include "llvm/Support/VersionTuple.h"
2829
#include <cassert>
2930
#include <cstddef>
@@ -37,6 +38,72 @@ class Decl;
3738
class Expr;
3839
class IdentifierInfo;
3940
class LangOptions;
41+
class ParsedAttr;
42+
class Sema;
43+
44+
struct ParsedAttrInfo {
45+
/// Corresponds to the Kind enum.
46+
unsigned AttrKind : 16;
47+
/// The number of required arguments of this attribute.
48+
unsigned NumArgs : 4;
49+
/// The number of optional arguments of this attributes.
50+
unsigned OptArgs : 4;
51+
/// True if the parsing does not match the semantic content.
52+
unsigned HasCustomParsing : 1;
53+
/// True if this attribute is only available for certain targets.
54+
unsigned IsTargetSpecific : 1;
55+
/// True if this attribute applies to types.
56+
unsigned IsType : 1;
57+
/// True if this attribute applies to statements.
58+
unsigned IsStmt : 1;
59+
/// True if this attribute has any spellings that are known to gcc.
60+
unsigned IsKnownToGCC : 1;
61+
/// True if this attribute is supported by #pragma clang attribute.
62+
unsigned IsSupportedByPragmaAttribute : 1;
63+
/// The syntaxes supported by this attribute and how they're spelled.
64+
struct Spelling {
65+
AttributeCommonInfo::Syntax Syntax;
66+
std::string NormalizedFullName;
67+
};
68+
std::vector<Spelling> Spellings;
69+
70+
ParsedAttrInfo(AttributeCommonInfo::Kind AttrKind =
71+
AttributeCommonInfo::UnknownAttribute)
72+
: AttrKind(AttrKind), NumArgs(0), OptArgs(0), HasCustomParsing(0),
73+
IsTargetSpecific(0), IsType(0), IsStmt(0), IsKnownToGCC(0),
74+
IsSupportedByPragmaAttribute(0) {}
75+
76+
virtual ~ParsedAttrInfo() = default;
77+
78+
/// Check if this attribute appertains to D, and issue a diagnostic if not.
79+
virtual bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr,
80+
const Decl *D) const {
81+
return true;
82+
}
83+
/// Check if this attribute is allowed by the language we are compiling, and
84+
/// issue a diagnostic if not.
85+
virtual bool diagLangOpts(Sema &S, const ParsedAttr &Attr) const {
86+
return true;
87+
}
88+
/// Check if this attribute is allowed when compiling for the given target.
89+
virtual bool existsInTarget(const TargetInfo &Target) const {
90+
return true;
91+
}
92+
/// Convert the spelling index of Attr to a semantic spelling enum value.
93+
virtual unsigned
94+
spellingIndexToSemanticSpelling(const ParsedAttr &Attr) const {
95+
return UINT_MAX;
96+
}
97+
/// Populate Rules with the match rules of this attribute.
98+
virtual void getPragmaAttributeMatchRules(
99+
llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules,
100+
const LangOptions &LangOpts) const {
101+
}
102+
103+
static const ParsedAttrInfo &get(const AttributeCommonInfo &A);
104+
};
105+
106+
typedef llvm::Registry<ParsedAttrInfo> ParsedAttrInfoRegistry;
40107

41108
/// Represents information about a change in availability for
42109
/// an entity, which is part of the encoding of the 'availability'
@@ -181,6 +248,8 @@ class ParsedAttr final
181248

182249
const Expr *MessageExpr;
183250

251+
const ParsedAttrInfo &Info;
252+
184253
ArgsUnion *getArgsBuffer() { return getTrailingObjects<ArgsUnion>(); }
185254
ArgsUnion const *getArgsBuffer() const {
186255
return getTrailingObjects<ArgsUnion>();
@@ -207,7 +276,8 @@ class ParsedAttr final
207276
EllipsisLoc(ellipsisLoc), NumArgs(numArgs), Invalid(false),
208277
UsedAsTypeAttr(false), IsAvailability(false),
209278
IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
210-
HasProcessingCache(false), IsPragmaClangAttribute(false) {
279+
HasProcessingCache(false), IsPragmaClangAttribute(false),
280+
Info(ParsedAttrInfo::get(*this)) {
211281
if (numArgs)
212282
memcpy(getArgsBuffer(), args, numArgs * sizeof(ArgsUnion));
213283
}
@@ -225,7 +295,8 @@ class ParsedAttr final
225295
NumArgs(1), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
226296
IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
227297
HasProcessingCache(false), IsPragmaClangAttribute(false),
228-
UnavailableLoc(unavailable), MessageExpr(messageExpr) {
298+
UnavailableLoc(unavailable), MessageExpr(messageExpr),
299+
Info(ParsedAttrInfo::get(*this)) {
229300
ArgsUnion PVal(Parm);
230301
memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
231302
new (getAvailabilityData()) detail::AvailabilityData(
@@ -242,7 +313,7 @@ class ParsedAttr final
242313
NumArgs(3), Invalid(false), UsedAsTypeAttr(false),
243314
IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false),
244315
HasParsedType(false), HasProcessingCache(false),
245-
IsPragmaClangAttribute(false) {
316+
IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) {
246317
ArgsUnion *Args = getArgsBuffer();
247318
Args[0] = Parm1;
248319
Args[1] = Parm2;
@@ -259,7 +330,7 @@ class ParsedAttr final
259330
NumArgs(1), Invalid(false), UsedAsTypeAttr(false),
260331
IsAvailability(false), IsTypeTagForDatatype(true), IsProperty(false),
261332
HasParsedType(false), HasProcessingCache(false),
262-
IsPragmaClangAttribute(false) {
333+
IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) {
263334
ArgsUnion PVal(ArgKind);
264335
memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
265336
detail::TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot();
@@ -277,7 +348,7 @@ class ParsedAttr final
277348
NumArgs(0), Invalid(false), UsedAsTypeAttr(false),
278349
IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false),
279350
HasParsedType(true), HasProcessingCache(false),
280-
IsPragmaClangAttribute(false) {
351+
IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) {
281352
new (&getTypeBuffer()) ParsedType(typeArg);
282353
}
283354

@@ -291,7 +362,7 @@ class ParsedAttr final
291362
NumArgs(0), Invalid(false), UsedAsTypeAttr(false),
292363
IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(true),
293364
HasParsedType(false), HasProcessingCache(false),
294-
IsPragmaClangAttribute(false) {
365+
IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) {
295366
new (&getPropertyDataBuffer()) detail::PropertyData(getterId, setterId);
296367
}
297368

@@ -534,7 +605,10 @@ class ParsedAttr final
534605
}
535606
}
536607

537-
AttributeCommonInfo::Kind getKind() const { return getParsedKind(); }
608+
AttributeCommonInfo::Kind getKind() const {
609+
return AttributeCommonInfo::Kind(Info.AttrKind);
610+
}
611+
const ParsedAttrInfo &getInfo() const { return Info; }
538612
};
539613

540614
class AttributePool;

clang/lib/Basic/Attributes.cpp

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,14 @@ const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
3636
}
3737

3838
static StringRef
39-
normalizeAttrScopeName(StringRef ScopeName,
39+
normalizeAttrScopeName(const IdentifierInfo *Scope,
4040
AttributeCommonInfo::Syntax SyntaxUsed) {
41+
if (!Scope)
42+
return "";
43+
4144
// Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
4245
// to be "clang".
46+
StringRef ScopeName = Scope->getName();
4347
if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
4448
SyntaxUsed == AttributeCommonInfo::AS_C2x) {
4549
if (ScopeName == "__gnu__")
@@ -50,7 +54,7 @@ normalizeAttrScopeName(StringRef ScopeName,
5054
return ScopeName;
5155
}
5256

53-
static StringRef normalizeAttrName(StringRef AttrName,
57+
static StringRef normalizeAttrName(const IdentifierInfo *Name,
5458
StringRef NormalizedScopeName,
5559
AttributeCommonInfo::Syntax SyntaxUsed) {
5660
// Normalize the attribute name, __foo__ becomes foo. This is only allowable
@@ -61,6 +65,7 @@ static StringRef normalizeAttrName(StringRef AttrName,
6165
SyntaxUsed == AttributeCommonInfo::AS_C2x) &&
6266
(NormalizedScopeName.empty() || NormalizedScopeName == "gnu" ||
6367
NormalizedScopeName == "clang"));
68+
StringRef AttrName = Name->getName();
6469
if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") &&
6570
AttrName.endswith("__"))
6671
AttrName = AttrName.slice(2, AttrName.size() - 2);
@@ -74,35 +79,41 @@ bool AttributeCommonInfo::isGNUScope() const {
7479

7580
#include "clang/Sema/AttrParsedAttrKinds.inc"
7681

77-
AttributeCommonInfo::Kind
78-
AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
79-
const IdentifierInfo *ScopeName,
80-
Syntax SyntaxUsed) {
81-
StringRef AttrName = Name->getName();
82-
83-
SmallString<64> FullName;
84-
if (ScopeName)
85-
FullName += normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed);
86-
87-
AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed);
82+
static SmallString<64> normalizeName(const IdentifierInfo *Name,
83+
const IdentifierInfo *Scope,
84+
AttributeCommonInfo::Syntax SyntaxUsed) {
85+
StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed);
86+
StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed);
8887

8988
// Ensure that in the case of C++11 attributes, we look for '::foo' if it is
9089
// unscoped.
91-
if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x)
90+
SmallString<64> FullName = ScopeName;
91+
if (Scope || SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
92+
SyntaxUsed == AttributeCommonInfo::AS_C2x)
9293
FullName += "::";
9394
FullName += AttrName;
9495

95-
return ::getAttrKind(FullName, SyntaxUsed);
96+
return FullName;
97+
}
98+
99+
AttributeCommonInfo::Kind
100+
AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
101+
const IdentifierInfo *ScopeName,
102+
Syntax SyntaxUsed) {
103+
return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
104+
}
105+
106+
std::string AttributeCommonInfo::getNormalizedFullName() const {
107+
return static_cast<std::string>(
108+
normalizeName(getAttrName(), getScopeName(), getSyntax()));
96109
}
97110

98111
unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
99112
// Both variables will be used in tablegen generated
100113
// attribute spell list index matching code.
101114
auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax());
102-
StringRef Scope =
103-
getScopeName() ? normalizeAttrScopeName(getScopeName()->getName(), Syntax)
104-
: "";
105-
StringRef Name = normalizeAttrName(getAttrName()->getName(), Scope, Syntax);
115+
StringRef Scope = normalizeAttrScopeName(getScopeName(), Syntax);
116+
StringRef Name = normalizeAttrName(getAttrName(), Scope, Syntax);
106117

107118
#include "clang/Sema/AttrSpellingListIndex.inc"
108119
}

0 commit comments

Comments
 (0)