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 "llvm/Support/ManagedStatic.h"
23 #include <cassert>
24 #include <cstddef>
25 #include <utility>
26 
27 using namespace clang;
28 
29 LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry)
30 
31 IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc,
32                                      IdentifierInfo *Ident) {
33   IdentifierLoc *Result = new (Ctx) IdentifierLoc;
34   Result->Loc = Loc;
35   Result->Ident = Ident;
36   return Result;
37 }
38 
39 size_t ParsedAttr::allocated_size() const {
40   if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;
41   else if (IsTypeTagForDatatype)
42     return AttributeFactory::TypeTagForDatatypeAllocSize;
43   else if (IsProperty)
44     return AttributeFactory::PropertyAllocSize;
45   else if (HasParsedType)
46     return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
47                             detail::TypeTagForDatatypeData, ParsedType,
48                             detail::PropertyData>(0, 0, 0, 1, 0);
49   return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
50                           detail::TypeTagForDatatypeData, ParsedType,
51                           detail::PropertyData>(NumArgs, 0, 0, 0, 0);
52 }
53 
54 AttributeFactory::AttributeFactory() {
55   // Go ahead and configure all the inline capacity.  This is just a memset.
56   FreeLists.resize(InlineFreeListsCapacity);
57 }
58 AttributeFactory::~AttributeFactory() = default;
59 
60 static size_t getFreeListIndexForSize(size_t size) {
61   assert(size >= sizeof(ParsedAttr));
62   assert((size % sizeof(void*)) == 0);
63   return ((size - sizeof(ParsedAttr)) / sizeof(void *));
64 }
65 
66 void *AttributeFactory::allocate(size_t size) {
67   // Check for a previously reclaimed attribute.
68   size_t index = getFreeListIndexForSize(size);
69   if (index < FreeLists.size() && !FreeLists[index].empty()) {
70     ParsedAttr *attr = FreeLists[index].back();
71     FreeLists[index].pop_back();
72     return attr;
73   }
74 
75   // Otherwise, allocate something new.
76   return Alloc.Allocate(size, alignof(AttributeFactory));
77 }
78 
79 void AttributeFactory::deallocate(ParsedAttr *Attr) {
80   size_t size = Attr->allocated_size();
81   size_t freeListIndex = getFreeListIndexForSize(size);
82 
83   // Expand FreeLists to the appropriate size, if required.
84   if (freeListIndex >= FreeLists.size())
85     FreeLists.resize(freeListIndex + 1);
86 
87 #ifndef NDEBUG
88   // In debug mode, zero out the attribute to help find memory overwriting.
89   memset(Attr, 0, size);
90 #endif
91 
92   // Add 'Attr' to the appropriate free-list.
93   FreeLists[freeListIndex].push_back(Attr);
94 }
95 
96 void AttributeFactory::reclaimPool(AttributePool &cur) {
97   for (ParsedAttr *AL : cur.Attrs)
98     deallocate(AL);
99 }
100 
101 void AttributePool::takePool(AttributePool &pool) {
102   Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end());
103   pool.Attrs.clear();
104 }
105 
106 namespace {
107 
108 #include "clang/Sema/AttrParsedAttrImpl.inc"
109 
110 } // namespace
111 
112 const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
113   // If we have a ParsedAttrInfo for this ParsedAttr then return that.
114   if ((size_t)A.getParsedKind() < llvm::array_lengthof(AttrInfoMap))
115     return *AttrInfoMap[A.getParsedKind()];
116 
117   // If this is an ignored attribute then return an appropriate ParsedAttrInfo.
118   static const ParsedAttrInfo IgnoredParsedAttrInfo(
119       AttributeCommonInfo::IgnoredAttribute);
120   if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute)
121     return IgnoredParsedAttrInfo;
122 
123   // Otherwise this may be an attribute defined by a plugin. First instantiate
124   // all plugin attributes if we haven't already done so.
125   static llvm::ManagedStatic<std::list<std::unique_ptr<ParsedAttrInfo>>>
126       PluginAttrInstances;
127   if (PluginAttrInstances->empty())
128     for (auto It : ParsedAttrInfoRegistry::entries())
129       PluginAttrInstances->emplace_back(It.instantiate());
130 
131   // Search for a ParsedAttrInfo whose name and syntax match.
132   std::string FullName = A.getNormalizedFullName();
133   AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax();
134   if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword)
135     SyntaxUsed = AttributeCommonInfo::AS_Keyword;
136 
137   for (auto &Ptr : *PluginAttrInstances)
138     for (auto &S : Ptr->Spellings)
139       if (S.Syntax == SyntaxUsed && S.NormalizedFullName == FullName)
140         return *Ptr;
141 
142   // If we failed to find a match then return a default ParsedAttrInfo.
143   static const ParsedAttrInfo DefaultParsedAttrInfo(
144       AttributeCommonInfo::UnknownAttribute);
145   return DefaultParsedAttrInfo;
146 }
147 
148 ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() {
149   return llvm::makeArrayRef(AttrInfoMap);
150 }
151 
152 unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
153 
154 unsigned ParsedAttr::getMaxArgs() const {
155   return getMinArgs() + getInfo().OptArgs;
156 }
157 
158 unsigned ParsedAttr::getNumArgMembers() const {
159   return getInfo().NumArgMembers;
160 }
161 
162 bool ParsedAttr::hasCustomParsing() const {
163   return getInfo().HasCustomParsing;
164 }
165 
166 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
167   return getInfo().diagAppertainsToDecl(S, *this, D);
168 }
169 
170 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const {
171   return getInfo().diagAppertainsToStmt(S, *this, St);
172 }
173 
174 bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const {
175   return getInfo().diagMutualExclusion(S, *this, D);
176 }
177 
178 bool ParsedAttr::appliesToDecl(const Decl *D,
179                                attr::SubjectMatchRule MatchRule) const {
180   return checkAttributeMatchRuleAppliesTo(D, MatchRule);
181 }
182 
183 void ParsedAttr::getMatchRules(
184     const LangOptions &LangOpts,
185     SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
186     const {
187   return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts);
188 }
189 
190 bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
191   if (getInfo().acceptsLangOpts(S.getLangOpts()))
192     return true;
193   S.Diag(getLoc(), diag::warn_attribute_ignored) << *this;
194   return false;
195 }
196 
197 bool ParsedAttr::isTargetSpecificAttr() const {
198   return getInfo().IsTargetSpecific;
199 }
200 
201 bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; }
202 
203 bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; }
204 
205 bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {
206   return getInfo().existsInTarget(Target);
207 }
208 
209 bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; }
210 
211 bool ParsedAttr::isSupportedByPragmaAttribute() const {
212   return getInfo().IsSupportedByPragmaAttribute;
213 }
214 
215 bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {
216   assert(isStandardAttributeSyntax());
217 
218   // We have historically allowed some type attributes with standard attribute
219   // syntax to slide to the decl-specifier-seq, so we have to keep supporting
220   // it. This property is consciously not defined as a flag in Attr.td because
221   // we don't want new attributes to specify it.
222   //
223   // Note: No new entries should be added to this list. Entries should be
224   // removed from this list after a suitable deprecation period, provided that
225   // there are no compatibility considerations with other compilers. If
226   // possible, we would like this list to go away entirely.
227   switch (getParsedKind()) {
228   case AT_AddressSpace:
229   case AT_OpenCLPrivateAddressSpace:
230   case AT_OpenCLGlobalAddressSpace:
231   case AT_OpenCLGlobalDeviceAddressSpace:
232   case AT_OpenCLGlobalHostAddressSpace:
233   case AT_OpenCLLocalAddressSpace:
234   case AT_OpenCLConstantAddressSpace:
235   case AT_OpenCLGenericAddressSpace:
236   case AT_NeonPolyVectorType:
237   case AT_NeonVectorType:
238   case AT_ArmMveStrictPolymorphism:
239   case AT_BTFTypeTag:
240   case AT_ObjCGC:
241   case AT_MatrixType:
242     return true;
243   default:
244     return false;
245   }
246 }
247 
248 bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
249 
250 unsigned ParsedAttr::getSemanticSpelling() const {
251   return getInfo().spellingIndexToSemanticSpelling(*this);
252 }
253 
254 bool ParsedAttr::hasVariadicArg() const {
255   // If the attribute has the maximum number of optional arguments, we will
256   // claim that as being variadic. If we someday get an attribute that
257   // legitimately bumps up against that maximum, we can use another bit to track
258   // whether it's truly variadic or not.
259   return getInfo().OptArgs == 15;
260 }
261 
262 bool ParsedAttr::isParamExpr(size_t N) const {
263   return getInfo().isParamExpr(N);
264 }
265 
266 void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const {
267   ::handleAttrWithDelayedArgs(S, D, *this);
268 }
269 
270 static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
271   // FIXME: Include the type in the argument list.
272   return AL.getNumArgs() + AL.hasParsedType();
273 }
274 
275 template <typename Compare>
276 static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL,
277                                       unsigned Num, unsigned Diag,
278                                       Compare Comp) {
279   if (Comp(getNumAttributeArgs(AL), Num)) {
280     S.Diag(AL.getLoc(), Diag) << AL << Num;
281     return false;
282   }
283   return true;
284 }
285 
286 bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const {
287   return checkAttributeNumArgsImpl(S, *this, Num,
288                                    diag::err_attribute_wrong_number_arguments,
289                                    std::not_equal_to<unsigned>());
290 }
291 bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const {
292   return checkAttributeNumArgsImpl(S, *this, Num,
293                                    diag::err_attribute_too_few_arguments,
294                                    std::less<unsigned>());
295 }
296 bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const {
297   return checkAttributeNumArgsImpl(S, *this, Num,
298                                    diag::err_attribute_too_many_arguments,
299                                    std::greater<unsigned>());
300 }
301 
302 void clang::takeAndConcatenateAttrs(ParsedAttributes &First,
303                                     ParsedAttributes &Second,
304                                     ParsedAttributes &Result) {
305   // Note that takeAllFrom() puts the attributes at the beginning of the list,
306   // so to obtain the correct ordering, we add `Second`, then `First`.
307   Result.takeAllFrom(Second);
308   Result.takeAllFrom(First);
309   if (First.Range.getBegin().isValid())
310     Result.Range.setBegin(First.Range.getBegin());
311   else
312     Result.Range.setBegin(Second.Range.getBegin());
313   if (Second.Range.getEnd().isValid())
314     Result.Range.setEnd(Second.Range.getEnd());
315   else
316     Result.Range.setEnd(First.Range.getEnd());
317 }
318