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