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