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
24using namespace clang;
25
26size_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>(Counts: 0, Counts: 0, Counts: 0, Counts: 1, Counts: 0);
36 return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
37 detail::TypeTagForDatatypeData, ParsedType,
38 detail::PropertyData>(Counts: NumArgs, Counts: 0, Counts: 0, Counts: 0, Counts: 0);
39}
40
41AttributeFactory::AttributeFactory() {
42 // Go ahead and configure all the inline capacity. This is just a memset.
43 FreeLists.resize(N: InlineFreeListsCapacity);
44}
45AttributeFactory::~AttributeFactory() = default;
46
47static 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
53void *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: size, Alignment: alignof(AttributeFactory));
63}
64
65void 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(N: freeListIndex + 1);
72
73#ifndef NDEBUG
74 // In debug mode, zero out the attribute to help find memory overwriting.
75 memset(s: Attr, c: 0, n: size);
76#endif
77
78 // Add 'Attr' to the appropriate free-list.
79 FreeLists[freeListIndex].push_back(Elt: Attr);
80}
81
82void AttributeFactory::reclaimPool(AttributePool &cur) {
83 for (ParsedAttr *AL : cur.Attrs)
84 deallocate(Attr: AL);
85}
86
87void AttributePool::takePool(AttributePool &pool) {
88 llvm::append_range(C&: Attrs, R&: pool.Attrs);
89 pool.Attrs.clear();
90}
91
92void 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(attr: A);
96 llvm::append_range(C&: Attrs, R&: List.AttrList);
97}
98
99namespace {
100
101#include "clang/Sema/AttrParsedAttrImpl.inc"
102
103} // namespace
104
105const 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
134ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() {
135 return llvm::ArrayRef(AttrInfoMap);
136}
137
138unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
139
140unsigned ParsedAttr::getMaxArgs() const {
141 return getMinArgs() + getInfo().OptArgs;
142}
143
144unsigned ParsedAttr::getNumArgMembers() const {
145 return getInfo().NumArgMembers;
146}
147
148bool ParsedAttr::hasCustomParsing() const {
149 return getInfo().HasCustomParsing;
150}
151
152bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
153 return getInfo().diagAppertainsToDecl(S, Attr: *this, D);
154}
155
156bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const {
157 return getInfo().diagAppertainsToStmt(S, Attr: *this, St);
158}
159
160bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const {
161 return getInfo().diagMutualExclusion(S, A: *this, D);
162}
163
164bool ParsedAttr::appliesToDecl(const Decl *D,
165 attr::SubjectMatchRule MatchRule) const {
166 return checkAttributeMatchRuleAppliesTo(D, MatchRule);
167}
168
169void ParsedAttr::getMatchRules(
170 const LangOptions &LangOpts,
171 SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
172 const {
173 return getInfo().getPragmaAttributeMatchRules(Rules&: MatchRules, LangOpts);
174}
175
176bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
177 if (getInfo().acceptsLangOpts(LO: S.getLangOpts()))
178 return true;
179 S.Diag(getLoc(), diag::warn_attribute_ignored) << *this;
180 return false;
181}
182
183bool ParsedAttr::isTargetSpecificAttr() const {
184 return getInfo().IsTargetSpecific;
185}
186
187bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; }
188
189bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; }
190
191bool 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, SpellingListIndex: getAttributeSpellingListIndex());
202
203 return getInfo().existsInTarget(Target) && TargetSpecificSpellingExists;
204}
205
206bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; }
207
208bool ParsedAttr::isSupportedByPragmaAttribute() const {
209 return getInfo().IsSupportedByPragmaAttribute;
210}
211
212bool 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
250bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
251
252unsigned ParsedAttr::getSemanticSpelling() const {
253 return getInfo().spellingIndexToSemanticSpelling(Attr: *this);
254}
255
256bool 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
264bool ParsedAttr::isParamExpr(size_t N) const {
265 return getInfo().isParamExpr(N);
266}
267
268void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const {
269 ::handleAttrWithDelayedArgs(S, D, *this);
270}
271
272static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
273 // FIXME: Include the type in the argument list.
274 return AL.getNumArgs() + AL.hasParsedType();
275}
276
277template <typename Compare>
278static 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
288bool 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}
293bool 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}
298bool 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
304void clang::takeAndConcatenateAttrs(ParsedAttributes &First,
305 ParsedAttributes &&Second) {
306
307 First.takeAllAtEndFrom(Other&: 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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of clang/lib/Sema/ParsedAttr.cpp