Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Sema/ParsedAttr.cpp
35233 views
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
26
using namespace clang;
27
28
IdentifierLoc *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
36
size_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>(0, 0, 0, 1, 0);
46
return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
47
detail::TypeTagForDatatypeData, ParsedType,
48
detail::PropertyData>(NumArgs, 0, 0, 0, 0);
49
}
50
51
AttributeFactory::AttributeFactory() {
52
// Go ahead and configure all the inline capacity. This is just a memset.
53
FreeLists.resize(InlineFreeListsCapacity);
54
}
55
AttributeFactory::~AttributeFactory() = default;
56
57
static 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
63
void *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, alignof(AttributeFactory));
74
}
75
76
void 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(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(Attr);
91
}
92
93
void AttributeFactory::reclaimPool(AttributePool &cur) {
94
for (ParsedAttr *AL : cur.Attrs)
95
deallocate(AL);
96
}
97
98
void AttributePool::takePool(AttributePool &pool) {
99
Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end());
100
pool.Attrs.clear();
101
}
102
103
void AttributePool::takeFrom(ParsedAttributesView &List, AttributePool &Pool) {
104
assert(&Pool != this && "AttributePool can't take attributes from itself");
105
llvm::for_each(List.AttrList, [&Pool](ParsedAttr *A) { Pool.remove(A); });
106
Attrs.insert(Attrs.end(), List.AttrList.begin(), List.AttrList.end());
107
}
108
109
namespace {
110
111
#include "clang/Sema/AttrParsedAttrImpl.inc"
112
113
} // namespace
114
115
const 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(SyntaxUsed, 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
144
ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() {
145
return llvm::ArrayRef(AttrInfoMap);
146
}
147
148
unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
149
150
unsigned ParsedAttr::getMaxArgs() const {
151
return getMinArgs() + getInfo().OptArgs;
152
}
153
154
unsigned ParsedAttr::getNumArgMembers() const {
155
return getInfo().NumArgMembers;
156
}
157
158
bool ParsedAttr::hasCustomParsing() const {
159
return getInfo().HasCustomParsing;
160
}
161
162
bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
163
return getInfo().diagAppertainsToDecl(S, *this, D);
164
}
165
166
bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const {
167
return getInfo().diagAppertainsToStmt(S, *this, St);
168
}
169
170
bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const {
171
return getInfo().diagMutualExclusion(S, *this, D);
172
}
173
174
bool ParsedAttr::appliesToDecl(const Decl *D,
175
attr::SubjectMatchRule MatchRule) const {
176
return checkAttributeMatchRuleAppliesTo(D, MatchRule);
177
}
178
179
void ParsedAttr::getMatchRules(
180
const LangOptions &LangOpts,
181
SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
182
const {
183
return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts);
184
}
185
186
bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
187
if (getInfo().acceptsLangOpts(S.getLangOpts()))
188
return true;
189
S.Diag(getLoc(), diag::warn_attribute_ignored) << *this;
190
return false;
191
}
192
193
bool ParsedAttr::isTargetSpecificAttr() const {
194
return getInfo().IsTargetSpecific;
195
}
196
197
bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; }
198
199
bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; }
200
201
bool 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, getAttributeSpellingListIndex());
212
213
return getInfo().existsInTarget(Target) && TargetSpecificSpellingExists;
214
}
215
216
bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; }
217
218
bool ParsedAttr::isSupportedByPragmaAttribute() const {
219
return getInfo().IsSupportedByPragmaAttribute;
220
}
221
222
bool 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
260
bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
261
262
unsigned ParsedAttr::getSemanticSpelling() const {
263
return getInfo().spellingIndexToSemanticSpelling(*this);
264
}
265
266
bool 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
274
bool ParsedAttr::isParamExpr(size_t N) const {
275
return getInfo().isParamExpr(N);
276
}
277
278
void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const {
279
::handleAttrWithDelayedArgs(S, D, *this);
280
}
281
282
static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
283
// FIXME: Include the type in the argument list.
284
return AL.getNumArgs() + AL.hasParsedType();
285
}
286
287
template <typename Compare>
288
static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL,
289
unsigned Num, unsigned Diag,
290
Compare Comp) {
291
if (Comp(getNumAttributeArgs(AL), Num)) {
292
S.Diag(AL.getLoc(), Diag) << AL << Num;
293
return false;
294
}
295
return true;
296
}
297
298
bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const {
299
return checkAttributeNumArgsImpl(S, *this, Num,
300
diag::err_attribute_wrong_number_arguments,
301
std::not_equal_to<unsigned>());
302
}
303
bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const {
304
return checkAttributeNumArgsImpl(S, *this, Num,
305
diag::err_attribute_too_few_arguments,
306
std::less<unsigned>());
307
}
308
bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const {
309
return checkAttributeNumArgsImpl(S, *this, Num,
310
diag::err_attribute_too_many_arguments,
311
std::greater<unsigned>());
312
}
313
314
void 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(Second);
320
Result.takeAllFrom(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
331