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 namespace {
104 
105 #include "clang/Sema/AttrParsedAttrImpl.inc"
106 
107 } // namespace
108 
109 const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
110   // If we have a ParsedAttrInfo for this ParsedAttr then return that.
111   if ((size_t)A.getParsedKind() < std::size(AttrInfoMap))
112     return *AttrInfoMap[A.getParsedKind()];
113 
114   // If this is an ignored attribute then return an appropriate ParsedAttrInfo.
115   static const ParsedAttrInfo IgnoredParsedAttrInfo(
116       AttributeCommonInfo::IgnoredAttribute);
117   if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute)
118     return IgnoredParsedAttrInfo;
119 
120   // Otherwise this may be an attribute defined by a plugin.
121 
122   // Search for a ParsedAttrInfo whose name and syntax match.
123   std::string FullName = A.getNormalizedFullName();
124   AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax();
125   if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword)
126     SyntaxUsed = AttributeCommonInfo::AS_Keyword;
127 
128   for (auto &Ptr : getAttributePluginInstances())
129     if (Ptr->hasSpelling(SyntaxUsed, FullName))
130       return *Ptr;
131 
132   // If we failed to find a match then return a default ParsedAttrInfo.
133   static const ParsedAttrInfo DefaultParsedAttrInfo(
134       AttributeCommonInfo::UnknownAttribute);
135   return DefaultParsedAttrInfo;
136 }
137 
138 ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() {
139   return llvm::ArrayRef(AttrInfoMap);
140 }
141 
142 unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
143 
144 unsigned ParsedAttr::getMaxArgs() const {
145   return getMinArgs() + getInfo().OptArgs;
146 }
147 
148 unsigned ParsedAttr::getNumArgMembers() const {
149   return getInfo().NumArgMembers;
150 }
151 
152 bool ParsedAttr::hasCustomParsing() const {
153   return getInfo().HasCustomParsing;
154 }
155 
156 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
157   return getInfo().diagAppertainsToDecl(S, *this, D);
158 }
159 
160 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const {
161   return getInfo().diagAppertainsToStmt(S, *this, St);
162 }
163 
164 bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const {
165   return getInfo().diagMutualExclusion(S, *this, D);
166 }
167 
168 bool ParsedAttr::appliesToDecl(const Decl *D,
169                                attr::SubjectMatchRule MatchRule) const {
170   return checkAttributeMatchRuleAppliesTo(D, MatchRule);
171 }
172 
173 void ParsedAttr::getMatchRules(
174     const LangOptions &LangOpts,
175     SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
176     const {
177   return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts);
178 }
179 
180 bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
181   if (getInfo().acceptsLangOpts(S.getLangOpts()))
182     return true;
183   S.Diag(getLoc(), diag::warn_attribute_ignored) << *this;
184   return false;
185 }
186 
187 bool ParsedAttr::isTargetSpecificAttr() const {
188   return getInfo().IsTargetSpecific;
189 }
190 
191 bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; }
192 
193 bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; }
194 
195 bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {
196   return getInfo().existsInTarget(Target);
197 }
198 
199 bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; }
200 
201 bool ParsedAttr::isSupportedByPragmaAttribute() const {
202   return getInfo().IsSupportedByPragmaAttribute;
203 }
204 
205 bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {
206   if (isRegularKeywordAttribute())
207     // The appurtenance rules are applied strictly for all regular keyword
208     // atributes.
209     return false;
210 
211   assert(isStandardAttributeSyntax());
212 
213   // We have historically allowed some type attributes with standard attribute
214   // syntax to slide to the decl-specifier-seq, so we have to keep supporting
215   // it. This property is consciously not defined as a flag in Attr.td because
216   // we don't want new attributes to specify it.
217   //
218   // Note: No new entries should be added to this list. Entries should be
219   // removed from this list after a suitable deprecation period, provided that
220   // there are no compatibility considerations with other compilers. If
221   // possible, we would like this list to go away entirely.
222   switch (getParsedKind()) {
223   case AT_AddressSpace:
224   case AT_OpenCLPrivateAddressSpace:
225   case AT_OpenCLGlobalAddressSpace:
226   case AT_OpenCLGlobalDeviceAddressSpace:
227   case AT_OpenCLGlobalHostAddressSpace:
228   case AT_OpenCLLocalAddressSpace:
229   case AT_OpenCLConstantAddressSpace:
230   case AT_OpenCLGenericAddressSpace:
231   case AT_NeonPolyVectorType:
232   case AT_NeonVectorType:
233   case AT_ArmMveStrictPolymorphism:
234   case AT_BTFTypeTag:
235   case AT_ObjCGC:
236   case AT_MatrixType:
237     return true;
238   default:
239     return false;
240   }
241 }
242 
243 bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
244 
245 unsigned ParsedAttr::getSemanticSpelling() const {
246   return getInfo().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().OptArgs == 15;
255 }
256 
257 bool ParsedAttr::isParamExpr(size_t N) const {
258   return getInfo().isParamExpr(N);
259 }
260 
261 void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const {
262   ::handleAttrWithDelayedArgs(S, D, *this);
263 }
264 
265 static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
266   // FIXME: Include the type in the argument list.
267   return AL.getNumArgs() + AL.hasParsedType();
268 }
269 
270 template <typename Compare>
271 static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL,
272                                       unsigned Num, unsigned Diag,
273                                       Compare Comp) {
274   if (Comp(getNumAttributeArgs(AL), Num)) {
275     S.Diag(AL.getLoc(), Diag) << AL << Num;
276     return false;
277   }
278   return true;
279 }
280 
281 bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const {
282   return checkAttributeNumArgsImpl(S, *this, Num,
283                                    diag::err_attribute_wrong_number_arguments,
284                                    std::not_equal_to<unsigned>());
285 }
286 bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const {
287   return checkAttributeNumArgsImpl(S, *this, Num,
288                                    diag::err_attribute_too_few_arguments,
289                                    std::less<unsigned>());
290 }
291 bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const {
292   return checkAttributeNumArgsImpl(S, *this, Num,
293                                    diag::err_attribute_too_many_arguments,
294                                    std::greater<unsigned>());
295 }
296 
297 void clang::takeAndConcatenateAttrs(ParsedAttributes &First,
298                                     ParsedAttributes &Second,
299                                     ParsedAttributes &Result) {
300   // Note that takeAllFrom() puts the attributes at the beginning of the list,
301   // so to obtain the correct ordering, we add `Second`, then `First`.
302   Result.takeAllFrom(Second);
303   Result.takeAllFrom(First);
304   if (First.Range.getBegin().isValid())
305     Result.Range.setBegin(First.Range.getBegin());
306   else
307     Result.Range.setBegin(Second.Range.getBegin());
308   if (Second.Range.getEnd().isValid())
309     Result.Range.setEnd(Second.Range.getEnd());
310   else
311     Result.Range.setEnd(First.Range.getEnd());
312 }
313