1 //======- ParsedAttr.cpp --------------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the ParsedAttr class implementation
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/Sema/ParsedAttr.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/Basic/AttrSubjectMatchRules.h"
17 #include "clang/Basic/IdentifierTable.h"
18 #include "clang/Basic/TargetInfo.h"
19 #include "clang/Sema/SemaInternal.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/ADT/StringRef.h"
23 #include <cassert>
24 #include <cstddef>
25 #include <utility>
26
27 using namespace clang;
28
create(ASTContext & Ctx,SourceLocation Loc,IdentifierInfo * Ident)29 IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc,
30 IdentifierInfo *Ident) {
31 IdentifierLoc *Result = new (Ctx) IdentifierLoc;
32 Result->Loc = Loc;
33 Result->Ident = Ident;
34 return Result;
35 }
36
allocated_size() const37 size_t ParsedAttr::allocated_size() const {
38 if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;
39 else if (IsTypeTagForDatatype)
40 return AttributeFactory::TypeTagForDatatypeAllocSize;
41 else if (IsProperty)
42 return AttributeFactory::PropertyAllocSize;
43 else if (HasParsedType)
44 return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
45 detail::TypeTagForDatatypeData, ParsedType,
46 detail::PropertyData>(0, 0, 0, 1, 0);
47 return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
48 detail::TypeTagForDatatypeData, ParsedType,
49 detail::PropertyData>(NumArgs, 0, 0, 0, 0);
50 }
51
AttributeFactory()52 AttributeFactory::AttributeFactory() {
53 // Go ahead and configure all the inline capacity. This is just a memset.
54 FreeLists.resize(InlineFreeListsCapacity);
55 }
56 AttributeFactory::~AttributeFactory() = default;
57
getFreeListIndexForSize(size_t size)58 static size_t getFreeListIndexForSize(size_t size) {
59 assert(size >= sizeof(ParsedAttr));
60 assert((size % sizeof(void*)) == 0);
61 return ((size - sizeof(ParsedAttr)) / sizeof(void *));
62 }
63
allocate(size_t size)64 void *AttributeFactory::allocate(size_t size) {
65 // Check for a previously reclaimed attribute.
66 size_t index = getFreeListIndexForSize(size);
67 if (index < FreeLists.size() && !FreeLists[index].empty()) {
68 ParsedAttr *attr = FreeLists[index].back();
69 FreeLists[index].pop_back();
70 return attr;
71 }
72
73 // Otherwise, allocate something new.
74 return Alloc.Allocate(size, alignof(AttributeFactory));
75 }
76
deallocate(ParsedAttr * Attr)77 void AttributeFactory::deallocate(ParsedAttr *Attr) {
78 size_t size = Attr->allocated_size();
79 size_t freeListIndex = getFreeListIndexForSize(size);
80
81 // Expand FreeLists to the appropriate size, if required.
82 if (freeListIndex >= FreeLists.size())
83 FreeLists.resize(freeListIndex + 1);
84
85 #ifndef NDEBUG
86 // In debug mode, zero out the attribute to help find memory overwriting.
87 memset(Attr, 0, size);
88 #endif
89
90 // Add 'Attr' to the appropriate free-list.
91 FreeLists[freeListIndex].push_back(Attr);
92 }
93
reclaimPool(AttributePool & cur)94 void AttributeFactory::reclaimPool(AttributePool &cur) {
95 for (ParsedAttr *AL : cur.Attrs)
96 deallocate(AL);
97 }
98
takePool(AttributePool & pool)99 void AttributePool::takePool(AttributePool &pool) {
100 Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end());
101 pool.Attrs.clear();
102 }
103
104 #include "clang/Sema/AttrParsedAttrKinds.inc"
105
normalizeAttrScopeName(StringRef ScopeName,ParsedAttr::Syntax SyntaxUsed)106 static StringRef normalizeAttrScopeName(StringRef ScopeName,
107 ParsedAttr::Syntax SyntaxUsed) {
108 // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
109 // to be "clang".
110 if (SyntaxUsed == ParsedAttr::AS_CXX11 ||
111 SyntaxUsed == ParsedAttr::AS_C2x) {
112 if (ScopeName == "__gnu__")
113 ScopeName = "gnu";
114 else if (ScopeName == "_Clang")
115 ScopeName = "clang";
116 }
117 return ScopeName;
118 }
119
normalizeAttrName(StringRef AttrName,StringRef NormalizedScopeName,ParsedAttr::Syntax SyntaxUsed)120 static StringRef normalizeAttrName(StringRef AttrName,
121 StringRef NormalizedScopeName,
122 ParsedAttr::Syntax SyntaxUsed) {
123 // Normalize the attribute name, __foo__ becomes foo. This is only allowable
124 // for GNU attributes, and attributes using the double square bracket syntax.
125 bool ShouldNormalize =
126 SyntaxUsed == ParsedAttr::AS_GNU ||
127 ((SyntaxUsed == ParsedAttr::AS_CXX11 ||
128 SyntaxUsed == ParsedAttr::AS_C2x) &&
129 (NormalizedScopeName == "gnu" || NormalizedScopeName == "clang"));
130 if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") &&
131 AttrName.endswith("__"))
132 AttrName = AttrName.slice(2, AttrName.size() - 2);
133
134 return AttrName;
135 }
136
getKind(const IdentifierInfo * Name,const IdentifierInfo * ScopeName,Syntax SyntaxUsed)137 ParsedAttr::Kind ParsedAttr::getKind(const IdentifierInfo *Name,
138 const IdentifierInfo *ScopeName,
139 Syntax SyntaxUsed) {
140 StringRef AttrName = Name->getName();
141
142 SmallString<64> FullName;
143 if (ScopeName)
144 FullName += normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed);
145
146 AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed);
147
148 // Ensure that in the case of C++11 attributes, we look for '::foo' if it is
149 // unscoped.
150 if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x)
151 FullName += "::";
152 FullName += AttrName;
153
154 return ::getAttrKind(FullName, SyntaxUsed);
155 }
156
getAttributeSpellingListIndex() const157 unsigned ParsedAttr::getAttributeSpellingListIndex() const {
158 // Both variables will be used in tablegen generated
159 // attribute spell list index matching code.
160 auto Syntax = static_cast<ParsedAttr::Syntax>(SyntaxUsed);
161 StringRef Scope =
162 ScopeName ? normalizeAttrScopeName(ScopeName->getName(), Syntax) : "";
163 StringRef Name = normalizeAttrName(AttrName->getName(), Scope, Syntax);
164
165 #include "clang/Sema/AttrSpellingListIndex.inc"
166
167 }
168
169 struct ParsedAttrInfo {
170 unsigned NumArgs : 4;
171 unsigned OptArgs : 4;
172 unsigned HasCustomParsing : 1;
173 unsigned IsTargetSpecific : 1;
174 unsigned IsType : 1;
175 unsigned IsStmt : 1;
176 unsigned IsKnownToGCC : 1;
177 unsigned IsSupportedByPragmaAttribute : 1;
178
179 bool (*DiagAppertainsToDecl)(Sema &S, const ParsedAttr &Attr, const Decl *);
180 bool (*DiagLangOpts)(Sema &S, const ParsedAttr &Attr);
181 bool (*ExistsInTarget)(const TargetInfo &Target);
182 unsigned (*SpellingIndexToSemanticSpelling)(const ParsedAttr &Attr);
183 void (*GetPragmaAttributeMatchRules)(
184 llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules,
185 const LangOptions &LangOpts);
186 };
187
188 namespace {
189
190 #include "clang/Sema/AttrParsedAttrImpl.inc"
191
192 } // namespace
193
getInfo(const ParsedAttr & A)194 static const ParsedAttrInfo &getInfo(const ParsedAttr &A) {
195 return AttrInfoMap[A.getKind()];
196 }
197
getMinArgs() const198 unsigned ParsedAttr::getMinArgs() const { return getInfo(*this).NumArgs; }
199
getMaxArgs() const200 unsigned ParsedAttr::getMaxArgs() const {
201 return getMinArgs() + getInfo(*this).OptArgs;
202 }
203
hasCustomParsing() const204 bool ParsedAttr::hasCustomParsing() const {
205 return getInfo(*this).HasCustomParsing;
206 }
207
diagnoseAppertainsTo(Sema & S,const Decl * D) const208 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
209 return getInfo(*this).DiagAppertainsToDecl(S, *this, D);
210 }
211
appliesToDecl(const Decl * D,attr::SubjectMatchRule MatchRule) const212 bool ParsedAttr::appliesToDecl(const Decl *D,
213 attr::SubjectMatchRule MatchRule) const {
214 return checkAttributeMatchRuleAppliesTo(D, MatchRule);
215 }
216
getMatchRules(const LangOptions & LangOpts,SmallVectorImpl<std::pair<attr::SubjectMatchRule,bool>> & MatchRules) const217 void ParsedAttr::getMatchRules(
218 const LangOptions &LangOpts,
219 SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
220 const {
221 return getInfo(*this).GetPragmaAttributeMatchRules(MatchRules, LangOpts);
222 }
223
diagnoseLangOpts(Sema & S) const224 bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
225 return getInfo(*this).DiagLangOpts(S, *this);
226 }
227
isTargetSpecificAttr() const228 bool ParsedAttr::isTargetSpecificAttr() const {
229 return getInfo(*this).IsTargetSpecific;
230 }
231
isTypeAttr() const232 bool ParsedAttr::isTypeAttr() const { return getInfo(*this).IsType; }
233
isStmtAttr() const234 bool ParsedAttr::isStmtAttr() const { return getInfo(*this).IsStmt; }
235
existsInTarget(const TargetInfo & Target) const236 bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {
237 return getInfo(*this).ExistsInTarget(Target);
238 }
239
isKnownToGCC() const240 bool ParsedAttr::isKnownToGCC() const { return getInfo(*this).IsKnownToGCC; }
241
isSupportedByPragmaAttribute() const242 bool ParsedAttr::isSupportedByPragmaAttribute() const {
243 return getInfo(*this).IsSupportedByPragmaAttribute;
244 }
245
getSemanticSpelling() const246 unsigned ParsedAttr::getSemanticSpelling() const {
247 return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
248 }
249
hasVariadicArg() const250 bool ParsedAttr::hasVariadicArg() const {
251 // If the attribute has the maximum number of optional arguments, we will
252 // claim that as being variadic. If we someday get an attribute that
253 // legitimately bumps up against that maximum, we can use another bit to track
254 // whether it's truly variadic or not.
255 return getInfo(*this).OptArgs == 15;
256 }
257