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