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