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
LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry)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
allocated_size() const39 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
AttributeFactory()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
getFreeListIndexForSize(size_t size)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
allocate(size_t size)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
deallocate(ParsedAttr * Attr)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
reclaimPool(AttributePool & cur)96 void AttributeFactory::reclaimPool(AttributePool &cur) {
97 for (ParsedAttr *AL : cur.Attrs)
98 deallocate(AL);
99 }
100
takePool(AttributePool & pool)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
get(const AttributeCommonInfo & A)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() < std::size(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
getAllBuiltin()148 ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() {
149 return llvm::ArrayRef(AttrInfoMap);
150 }
151
getMinArgs() const152 unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
153
getMaxArgs() const154 unsigned ParsedAttr::getMaxArgs() const {
155 return getMinArgs() + getInfo().OptArgs;
156 }
157
getNumArgMembers() const158 unsigned ParsedAttr::getNumArgMembers() const {
159 return getInfo().NumArgMembers;
160 }
161
hasCustomParsing() const162 bool ParsedAttr::hasCustomParsing() const {
163 return getInfo().HasCustomParsing;
164 }
165
diagnoseAppertainsTo(Sema & S,const Decl * D) const166 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
167 return getInfo().diagAppertainsToDecl(S, *this, D);
168 }
169
diagnoseAppertainsTo(Sema & S,const Stmt * St) const170 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const {
171 return getInfo().diagAppertainsToStmt(S, *this, St);
172 }
173
diagnoseMutualExclusion(Sema & S,const Decl * D) const174 bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const {
175 return getInfo().diagMutualExclusion(S, *this, D);
176 }
177
appliesToDecl(const Decl * D,attr::SubjectMatchRule MatchRule) const178 bool ParsedAttr::appliesToDecl(const Decl *D,
179 attr::SubjectMatchRule MatchRule) const {
180 return checkAttributeMatchRuleAppliesTo(D, MatchRule);
181 }
182
getMatchRules(const LangOptions & LangOpts,SmallVectorImpl<std::pair<attr::SubjectMatchRule,bool>> & MatchRules) const183 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
diagnoseLangOpts(Sema & S) const190 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
isTargetSpecificAttr() const197 bool ParsedAttr::isTargetSpecificAttr() const {
198 return getInfo().IsTargetSpecific;
199 }
200
isTypeAttr() const201 bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; }
202
isStmtAttr() const203 bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; }
204
existsInTarget(const TargetInfo & Target) const205 bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {
206 return getInfo().existsInTarget(Target);
207 }
208
isKnownToGCC() const209 bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; }
210
isSupportedByPragmaAttribute() const211 bool ParsedAttr::isSupportedByPragmaAttribute() const {
212 return getInfo().IsSupportedByPragmaAttribute;
213 }
214
slidesFromDeclToDeclSpecLegacyBehavior() const215 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
acceptsExprPack() const248 bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
249
getSemanticSpelling() const250 unsigned ParsedAttr::getSemanticSpelling() const {
251 return getInfo().spellingIndexToSemanticSpelling(*this);
252 }
253
hasVariadicArg() const254 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
isParamExpr(size_t N) const262 bool ParsedAttr::isParamExpr(size_t N) const {
263 return getInfo().isParamExpr(N);
264 }
265
handleAttrWithDelayedArgs(Sema & S,Decl * D) const266 void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const {
267 ::handleAttrWithDelayedArgs(S, D, *this);
268 }
269
getNumAttributeArgs(const ParsedAttr & AL)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>
checkAttributeNumArgsImpl(Sema & S,const ParsedAttr & AL,unsigned Num,unsigned Diag,Compare Comp)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
checkExactlyNumArgs(Sema & S,unsigned Num) const286 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 }
checkAtLeastNumArgs(Sema & S,unsigned Num) const291 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 }
checkAtMostNumArgs(Sema & S,unsigned Num) const296 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
takeAndConcatenateAttrs(ParsedAttributes & First,ParsedAttributes & Second,ParsedAttributes & Result)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