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