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 
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 
37 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 
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 
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 
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 
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 #if !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 
94 void AttributeFactory::reclaimPool(AttributePool &cur) {
95   for (ParsedAttr *AL : cur.Attrs)
96     deallocate(AL);
97 }
98 
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 
106 static StringRef normalizeAttrName(StringRef AttrName, StringRef ScopeName,
107                                    ParsedAttr::Syntax SyntaxUsed) {
108   // Normalize the attribute name, __foo__ becomes foo. This is only allowable
109   // for GNU attributes.
110   bool IsGNU = SyntaxUsed == ParsedAttr::AS_GNU ||
111                ((SyntaxUsed == ParsedAttr::AS_CXX11 ||
112                  SyntaxUsed == ParsedAttr::AS_C2x) &&
113                 ScopeName == "gnu");
114   if (IsGNU && AttrName.size() >= 4 && AttrName.startswith("__") &&
115       AttrName.endswith("__"))
116     AttrName = AttrName.slice(2, AttrName.size() - 2);
117 
118   return AttrName;
119 }
120 
121 ParsedAttr::Kind ParsedAttr::getKind(const IdentifierInfo *Name,
122                                      const IdentifierInfo *ScopeName,
123                                      Syntax SyntaxUsed) {
124   StringRef AttrName = Name->getName();
125 
126   SmallString<64> FullName;
127   if (ScopeName)
128     FullName += ScopeName->getName();
129 
130   AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed);
131 
132   // Ensure that in the case of C++11 attributes, we look for '::foo' if it is
133   // unscoped.
134   if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x)
135     FullName += "::";
136   FullName += AttrName;
137 
138   return ::getAttrKind(FullName, SyntaxUsed);
139 }
140 
141 unsigned ParsedAttr::getAttributeSpellingListIndex() const {
142   // Both variables will be used in tablegen generated
143   // attribute spell list index matching code.
144   StringRef Scope = ScopeName ? ScopeName->getName() : "";
145   StringRef Name = normalizeAttrName(AttrName->getName(), Scope,
146                                      (ParsedAttr::Syntax)SyntaxUsed);
147 
148 #include "clang/Sema/AttrSpellingListIndex.inc"
149 
150 }
151 
152 struct ParsedAttrInfo {
153   unsigned NumArgs : 4;
154   unsigned OptArgs : 4;
155   unsigned HasCustomParsing : 1;
156   unsigned IsTargetSpecific : 1;
157   unsigned IsType : 1;
158   unsigned IsStmt : 1;
159   unsigned IsKnownToGCC : 1;
160   unsigned IsSupportedByPragmaAttribute : 1;
161 
162   bool (*DiagAppertainsToDecl)(Sema &S, const ParsedAttr &Attr, const Decl *);
163   bool (*DiagLangOpts)(Sema &S, const ParsedAttr &Attr);
164   bool (*ExistsInTarget)(const TargetInfo &Target);
165   unsigned (*SpellingIndexToSemanticSpelling)(const ParsedAttr &Attr);
166   void (*GetPragmaAttributeMatchRules)(
167       llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules,
168       const LangOptions &LangOpts);
169 };
170 
171 namespace {
172 
173 #include "clang/Sema/AttrParsedAttrImpl.inc"
174 
175 } // namespace
176 
177 static const ParsedAttrInfo &getInfo(const ParsedAttr &A) {
178   return AttrInfoMap[A.getKind()];
179 }
180 
181 unsigned ParsedAttr::getMinArgs() const { return getInfo(*this).NumArgs; }
182 
183 unsigned ParsedAttr::getMaxArgs() const {
184   return getMinArgs() + getInfo(*this).OptArgs;
185 }
186 
187 bool ParsedAttr::hasCustomParsing() const {
188   return getInfo(*this).HasCustomParsing;
189 }
190 
191 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
192   return getInfo(*this).DiagAppertainsToDecl(S, *this, D);
193 }
194 
195 bool ParsedAttr::appliesToDecl(const Decl *D,
196                                attr::SubjectMatchRule MatchRule) const {
197   return checkAttributeMatchRuleAppliesTo(D, MatchRule);
198 }
199 
200 void ParsedAttr::getMatchRules(
201     const LangOptions &LangOpts,
202     SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
203     const {
204   return getInfo(*this).GetPragmaAttributeMatchRules(MatchRules, LangOpts);
205 }
206 
207 bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
208   return getInfo(*this).DiagLangOpts(S, *this);
209 }
210 
211 bool ParsedAttr::isTargetSpecificAttr() const {
212   return getInfo(*this).IsTargetSpecific;
213 }
214 
215 bool ParsedAttr::isTypeAttr() const { return getInfo(*this).IsType; }
216 
217 bool ParsedAttr::isStmtAttr() const { return getInfo(*this).IsStmt; }
218 
219 bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {
220   return getInfo(*this).ExistsInTarget(Target);
221 }
222 
223 bool ParsedAttr::isKnownToGCC() const { return getInfo(*this).IsKnownToGCC; }
224 
225 bool ParsedAttr::isSupportedByPragmaAttribute() const {
226   return getInfo(*this).IsSupportedByPragmaAttribute;
227 }
228 
229 unsigned ParsedAttr::getSemanticSpelling() const {
230   return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
231 }
232 
233 bool ParsedAttr::hasVariadicArg() const {
234   // If the attribute has the maximum number of optional arguments, we will
235   // claim that as being variadic. If we someday get an attribute that
236   // legitimately bumps up against that maximum, we can use another bit to track
237   // whether it's truly variadic or not.
238   return getInfo(*this).OptArgs == 15;
239 }
240