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