1e5dd7070Spatrick //======- ParsedAttr.cpp --------------------------------------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file defines the ParsedAttr class implementation
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #include "clang/Sema/ParsedAttr.h"
14e5dd7070Spatrick #include "clang/AST/ASTContext.h"
15e5dd7070Spatrick #include "clang/Basic/AttrSubjectMatchRules.h"
16e5dd7070Spatrick #include "clang/Basic/IdentifierTable.h"
17e5dd7070Spatrick #include "clang/Basic/TargetInfo.h"
18e5dd7070Spatrick #include "clang/Sema/SemaInternal.h"
19e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
20e5dd7070Spatrick #include "llvm/ADT/SmallVector.h"
21e5dd7070Spatrick #include "llvm/ADT/StringRef.h"
22ec727ea7Spatrick #include "llvm/Support/ManagedStatic.h"
23e5dd7070Spatrick #include <cassert>
24e5dd7070Spatrick #include <cstddef>
25e5dd7070Spatrick #include <utility>
26e5dd7070Spatrick
27e5dd7070Spatrick using namespace clang;
28e5dd7070Spatrick
LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry)29ec727ea7Spatrick LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry)
30ec727ea7Spatrick
31e5dd7070Spatrick IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc,
32e5dd7070Spatrick IdentifierInfo *Ident) {
33e5dd7070Spatrick IdentifierLoc *Result = new (Ctx) IdentifierLoc;
34e5dd7070Spatrick Result->Loc = Loc;
35e5dd7070Spatrick Result->Ident = Ident;
36e5dd7070Spatrick return Result;
37e5dd7070Spatrick }
38e5dd7070Spatrick
allocated_size() const39e5dd7070Spatrick size_t ParsedAttr::allocated_size() const {
40e5dd7070Spatrick if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;
41e5dd7070Spatrick else if (IsTypeTagForDatatype)
42e5dd7070Spatrick return AttributeFactory::TypeTagForDatatypeAllocSize;
43e5dd7070Spatrick else if (IsProperty)
44e5dd7070Spatrick return AttributeFactory::PropertyAllocSize;
45e5dd7070Spatrick else if (HasParsedType)
46e5dd7070Spatrick return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
47e5dd7070Spatrick detail::TypeTagForDatatypeData, ParsedType,
48e5dd7070Spatrick detail::PropertyData>(0, 0, 0, 1, 0);
49e5dd7070Spatrick return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
50e5dd7070Spatrick detail::TypeTagForDatatypeData, ParsedType,
51e5dd7070Spatrick detail::PropertyData>(NumArgs, 0, 0, 0, 0);
52e5dd7070Spatrick }
53e5dd7070Spatrick
AttributeFactory()54e5dd7070Spatrick AttributeFactory::AttributeFactory() {
55e5dd7070Spatrick // Go ahead and configure all the inline capacity. This is just a memset.
56e5dd7070Spatrick FreeLists.resize(InlineFreeListsCapacity);
57e5dd7070Spatrick }
58e5dd7070Spatrick AttributeFactory::~AttributeFactory() = default;
59e5dd7070Spatrick
getFreeListIndexForSize(size_t size)60e5dd7070Spatrick static size_t getFreeListIndexForSize(size_t size) {
61e5dd7070Spatrick assert(size >= sizeof(ParsedAttr));
62e5dd7070Spatrick assert((size % sizeof(void*)) == 0);
63e5dd7070Spatrick return ((size - sizeof(ParsedAttr)) / sizeof(void *));
64e5dd7070Spatrick }
65e5dd7070Spatrick
allocate(size_t size)66e5dd7070Spatrick void *AttributeFactory::allocate(size_t size) {
67e5dd7070Spatrick // Check for a previously reclaimed attribute.
68e5dd7070Spatrick size_t index = getFreeListIndexForSize(size);
69e5dd7070Spatrick if (index < FreeLists.size() && !FreeLists[index].empty()) {
70e5dd7070Spatrick ParsedAttr *attr = FreeLists[index].back();
71e5dd7070Spatrick FreeLists[index].pop_back();
72e5dd7070Spatrick return attr;
73e5dd7070Spatrick }
74e5dd7070Spatrick
75e5dd7070Spatrick // Otherwise, allocate something new.
76e5dd7070Spatrick return Alloc.Allocate(size, alignof(AttributeFactory));
77e5dd7070Spatrick }
78e5dd7070Spatrick
deallocate(ParsedAttr * Attr)79e5dd7070Spatrick void AttributeFactory::deallocate(ParsedAttr *Attr) {
80e5dd7070Spatrick size_t size = Attr->allocated_size();
81e5dd7070Spatrick size_t freeListIndex = getFreeListIndexForSize(size);
82e5dd7070Spatrick
83e5dd7070Spatrick // Expand FreeLists to the appropriate size, if required.
84e5dd7070Spatrick if (freeListIndex >= FreeLists.size())
85e5dd7070Spatrick FreeLists.resize(freeListIndex + 1);
86e5dd7070Spatrick
87e5dd7070Spatrick #ifndef NDEBUG
88e5dd7070Spatrick // In debug mode, zero out the attribute to help find memory overwriting.
89e5dd7070Spatrick memset(Attr, 0, size);
90e5dd7070Spatrick #endif
91e5dd7070Spatrick
92e5dd7070Spatrick // Add 'Attr' to the appropriate free-list.
93e5dd7070Spatrick FreeLists[freeListIndex].push_back(Attr);
94e5dd7070Spatrick }
95e5dd7070Spatrick
reclaimPool(AttributePool & cur)96e5dd7070Spatrick void AttributeFactory::reclaimPool(AttributePool &cur) {
97e5dd7070Spatrick for (ParsedAttr *AL : cur.Attrs)
98e5dd7070Spatrick deallocate(AL);
99e5dd7070Spatrick }
100e5dd7070Spatrick
takePool(AttributePool & pool)101e5dd7070Spatrick void AttributePool::takePool(AttributePool &pool) {
102e5dd7070Spatrick Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end());
103e5dd7070Spatrick pool.Attrs.clear();
104e5dd7070Spatrick }
105e5dd7070Spatrick
106e5dd7070Spatrick namespace {
107e5dd7070Spatrick
108e5dd7070Spatrick #include "clang/Sema/AttrParsedAttrImpl.inc"
109e5dd7070Spatrick
110e5dd7070Spatrick } // namespace
111e5dd7070Spatrick
get(const AttributeCommonInfo & A)112ec727ea7Spatrick const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
113ec727ea7Spatrick // If we have a ParsedAttrInfo for this ParsedAttr then return that.
114*12c85518Srobert if ((size_t)A.getParsedKind() < std::size(AttrInfoMap))
115ec727ea7Spatrick return *AttrInfoMap[A.getParsedKind()];
116ec727ea7Spatrick
117ec727ea7Spatrick // If this is an ignored attribute then return an appropriate ParsedAttrInfo.
118ec727ea7Spatrick static const ParsedAttrInfo IgnoredParsedAttrInfo(
119ec727ea7Spatrick AttributeCommonInfo::IgnoredAttribute);
120ec727ea7Spatrick if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute)
121ec727ea7Spatrick return IgnoredParsedAttrInfo;
122ec727ea7Spatrick
123ec727ea7Spatrick // Otherwise this may be an attribute defined by a plugin. First instantiate
124ec727ea7Spatrick // all plugin attributes if we haven't already done so.
125ec727ea7Spatrick static llvm::ManagedStatic<std::list<std::unique_ptr<ParsedAttrInfo>>>
126ec727ea7Spatrick PluginAttrInstances;
127ec727ea7Spatrick if (PluginAttrInstances->empty())
128ec727ea7Spatrick for (auto It : ParsedAttrInfoRegistry::entries())
129ec727ea7Spatrick PluginAttrInstances->emplace_back(It.instantiate());
130ec727ea7Spatrick
131ec727ea7Spatrick // Search for a ParsedAttrInfo whose name and syntax match.
132ec727ea7Spatrick std::string FullName = A.getNormalizedFullName();
133ec727ea7Spatrick AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax();
134ec727ea7Spatrick if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword)
135ec727ea7Spatrick SyntaxUsed = AttributeCommonInfo::AS_Keyword;
136ec727ea7Spatrick
137ec727ea7Spatrick for (auto &Ptr : *PluginAttrInstances)
138ec727ea7Spatrick for (auto &S : Ptr->Spellings)
139ec727ea7Spatrick if (S.Syntax == SyntaxUsed && S.NormalizedFullName == FullName)
140ec727ea7Spatrick return *Ptr;
141ec727ea7Spatrick
142ec727ea7Spatrick // If we failed to find a match then return a default ParsedAttrInfo.
143ec727ea7Spatrick static const ParsedAttrInfo DefaultParsedAttrInfo(
144ec727ea7Spatrick AttributeCommonInfo::UnknownAttribute);
145ec727ea7Spatrick return DefaultParsedAttrInfo;
146e5dd7070Spatrick }
147e5dd7070Spatrick
getAllBuiltin()148*12c85518Srobert ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() {
149*12c85518Srobert return llvm::ArrayRef(AttrInfoMap);
150*12c85518Srobert }
151*12c85518Srobert
getMinArgs() const152ec727ea7Spatrick unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
153e5dd7070Spatrick
getMaxArgs() const154e5dd7070Spatrick unsigned ParsedAttr::getMaxArgs() const {
155ec727ea7Spatrick return getMinArgs() + getInfo().OptArgs;
156e5dd7070Spatrick }
157e5dd7070Spatrick
getNumArgMembers() const158*12c85518Srobert unsigned ParsedAttr::getNumArgMembers() const {
159*12c85518Srobert return getInfo().NumArgMembers;
160*12c85518Srobert }
161*12c85518Srobert
hasCustomParsing() const162e5dd7070Spatrick bool ParsedAttr::hasCustomParsing() const {
163ec727ea7Spatrick return getInfo().HasCustomParsing;
164e5dd7070Spatrick }
165e5dd7070Spatrick
diagnoseAppertainsTo(Sema & S,const Decl * D) const166e5dd7070Spatrick bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
167ec727ea7Spatrick return getInfo().diagAppertainsToDecl(S, *this, D);
168e5dd7070Spatrick }
169e5dd7070Spatrick
diagnoseAppertainsTo(Sema & S,const Stmt * St) const170a9ac8606Spatrick bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const {
171a9ac8606Spatrick return getInfo().diagAppertainsToStmt(S, *this, St);
172a9ac8606Spatrick }
173a9ac8606Spatrick
diagnoseMutualExclusion(Sema & S,const Decl * D) const174a9ac8606Spatrick bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const {
175a9ac8606Spatrick return getInfo().diagMutualExclusion(S, *this, D);
176a9ac8606Spatrick }
177a9ac8606Spatrick
appliesToDecl(const Decl * D,attr::SubjectMatchRule MatchRule) const178e5dd7070Spatrick bool ParsedAttr::appliesToDecl(const Decl *D,
179e5dd7070Spatrick attr::SubjectMatchRule MatchRule) const {
180e5dd7070Spatrick return checkAttributeMatchRuleAppliesTo(D, MatchRule);
181e5dd7070Spatrick }
182e5dd7070Spatrick
getMatchRules(const LangOptions & LangOpts,SmallVectorImpl<std::pair<attr::SubjectMatchRule,bool>> & MatchRules) const183e5dd7070Spatrick void ParsedAttr::getMatchRules(
184e5dd7070Spatrick const LangOptions &LangOpts,
185e5dd7070Spatrick SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
186e5dd7070Spatrick const {
187ec727ea7Spatrick return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts);
188e5dd7070Spatrick }
189e5dd7070Spatrick
diagnoseLangOpts(Sema & S) const190e5dd7070Spatrick bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
191*12c85518Srobert if (getInfo().acceptsLangOpts(S.getLangOpts()))
192*12c85518Srobert return true;
193*12c85518Srobert S.Diag(getLoc(), diag::warn_attribute_ignored) << *this;
194*12c85518Srobert return false;
195e5dd7070Spatrick }
196e5dd7070Spatrick
isTargetSpecificAttr() const197e5dd7070Spatrick bool ParsedAttr::isTargetSpecificAttr() const {
198ec727ea7Spatrick return getInfo().IsTargetSpecific;
199e5dd7070Spatrick }
200e5dd7070Spatrick
isTypeAttr() const201ec727ea7Spatrick bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; }
202e5dd7070Spatrick
isStmtAttr() const203ec727ea7Spatrick bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; }
204e5dd7070Spatrick
existsInTarget(const TargetInfo & Target) const205e5dd7070Spatrick bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {
206ec727ea7Spatrick return getInfo().existsInTarget(Target);
207e5dd7070Spatrick }
208e5dd7070Spatrick
isKnownToGCC() const209ec727ea7Spatrick bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; }
210e5dd7070Spatrick
isSupportedByPragmaAttribute() const211e5dd7070Spatrick bool ParsedAttr::isSupportedByPragmaAttribute() const {
212ec727ea7Spatrick return getInfo().IsSupportedByPragmaAttribute;
213e5dd7070Spatrick }
214e5dd7070Spatrick
slidesFromDeclToDeclSpecLegacyBehavior() const215*12c85518Srobert bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {
216*12c85518Srobert assert(isStandardAttributeSyntax());
217*12c85518Srobert
218*12c85518Srobert // We have historically allowed some type attributes with standard attribute
219*12c85518Srobert // syntax to slide to the decl-specifier-seq, so we have to keep supporting
220*12c85518Srobert // it. This property is consciously not defined as a flag in Attr.td because
221*12c85518Srobert // we don't want new attributes to specify it.
222*12c85518Srobert //
223*12c85518Srobert // Note: No new entries should be added to this list. Entries should be
224*12c85518Srobert // removed from this list after a suitable deprecation period, provided that
225*12c85518Srobert // there are no compatibility considerations with other compilers. If
226*12c85518Srobert // possible, we would like this list to go away entirely.
227*12c85518Srobert switch (getParsedKind()) {
228*12c85518Srobert case AT_AddressSpace:
229*12c85518Srobert case AT_OpenCLPrivateAddressSpace:
230*12c85518Srobert case AT_OpenCLGlobalAddressSpace:
231*12c85518Srobert case AT_OpenCLGlobalDeviceAddressSpace:
232*12c85518Srobert case AT_OpenCLGlobalHostAddressSpace:
233*12c85518Srobert case AT_OpenCLLocalAddressSpace:
234*12c85518Srobert case AT_OpenCLConstantAddressSpace:
235*12c85518Srobert case AT_OpenCLGenericAddressSpace:
236*12c85518Srobert case AT_NeonPolyVectorType:
237*12c85518Srobert case AT_NeonVectorType:
238*12c85518Srobert case AT_ArmMveStrictPolymorphism:
239*12c85518Srobert case AT_BTFTypeTag:
240*12c85518Srobert case AT_ObjCGC:
241*12c85518Srobert case AT_MatrixType:
242*12c85518Srobert return true;
243*12c85518Srobert default:
244*12c85518Srobert return false;
245*12c85518Srobert }
246*12c85518Srobert }
247*12c85518Srobert
acceptsExprPack() const248*12c85518Srobert bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
249*12c85518Srobert
getSemanticSpelling() const250e5dd7070Spatrick unsigned ParsedAttr::getSemanticSpelling() const {
251ec727ea7Spatrick return getInfo().spellingIndexToSemanticSpelling(*this);
252e5dd7070Spatrick }
253e5dd7070Spatrick
hasVariadicArg() const254e5dd7070Spatrick bool ParsedAttr::hasVariadicArg() const {
255e5dd7070Spatrick // If the attribute has the maximum number of optional arguments, we will
256e5dd7070Spatrick // claim that as being variadic. If we someday get an attribute that
257e5dd7070Spatrick // legitimately bumps up against that maximum, we can use another bit to track
258e5dd7070Spatrick // whether it's truly variadic or not.
259ec727ea7Spatrick return getInfo().OptArgs == 15;
260e5dd7070Spatrick }
261a9ac8606Spatrick
isParamExpr(size_t N) const262*12c85518Srobert bool ParsedAttr::isParamExpr(size_t N) const {
263*12c85518Srobert return getInfo().isParamExpr(N);
264*12c85518Srobert }
265*12c85518Srobert
handleAttrWithDelayedArgs(Sema & S,Decl * D) const266*12c85518Srobert void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const {
267*12c85518Srobert ::handleAttrWithDelayedArgs(S, D, *this);
268*12c85518Srobert }
269*12c85518Srobert
getNumAttributeArgs(const ParsedAttr & AL)270a9ac8606Spatrick static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
271a9ac8606Spatrick // FIXME: Include the type in the argument list.
272a9ac8606Spatrick return AL.getNumArgs() + AL.hasParsedType();
273a9ac8606Spatrick }
274a9ac8606Spatrick
275a9ac8606Spatrick template <typename Compare>
checkAttributeNumArgsImpl(Sema & S,const ParsedAttr & AL,unsigned Num,unsigned Diag,Compare Comp)276a9ac8606Spatrick static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL,
277a9ac8606Spatrick unsigned Num, unsigned Diag,
278a9ac8606Spatrick Compare Comp) {
279a9ac8606Spatrick if (Comp(getNumAttributeArgs(AL), Num)) {
280a9ac8606Spatrick S.Diag(AL.getLoc(), Diag) << AL << Num;
281a9ac8606Spatrick return false;
282a9ac8606Spatrick }
283a9ac8606Spatrick return true;
284a9ac8606Spatrick }
285a9ac8606Spatrick
checkExactlyNumArgs(Sema & S,unsigned Num) const286a9ac8606Spatrick bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const {
287a9ac8606Spatrick return checkAttributeNumArgsImpl(S, *this, Num,
288a9ac8606Spatrick diag::err_attribute_wrong_number_arguments,
289a9ac8606Spatrick std::not_equal_to<unsigned>());
290a9ac8606Spatrick }
checkAtLeastNumArgs(Sema & S,unsigned Num) const291a9ac8606Spatrick bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const {
292a9ac8606Spatrick return checkAttributeNumArgsImpl(S, *this, Num,
293a9ac8606Spatrick diag::err_attribute_too_few_arguments,
294a9ac8606Spatrick std::less<unsigned>());
295a9ac8606Spatrick }
checkAtMostNumArgs(Sema & S,unsigned Num) const296a9ac8606Spatrick bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const {
297a9ac8606Spatrick return checkAttributeNumArgsImpl(S, *this, Num,
298a9ac8606Spatrick diag::err_attribute_too_many_arguments,
299a9ac8606Spatrick std::greater<unsigned>());
300a9ac8606Spatrick }
301*12c85518Srobert
takeAndConcatenateAttrs(ParsedAttributes & First,ParsedAttributes & Second,ParsedAttributes & Result)302*12c85518Srobert void clang::takeAndConcatenateAttrs(ParsedAttributes &First,
303*12c85518Srobert ParsedAttributes &Second,
304*12c85518Srobert ParsedAttributes &Result) {
305*12c85518Srobert // Note that takeAllFrom() puts the attributes at the beginning of the list,
306*12c85518Srobert // so to obtain the correct ordering, we add `Second`, then `First`.
307*12c85518Srobert Result.takeAllFrom(Second);
308*12c85518Srobert Result.takeAllFrom(First);
309*12c85518Srobert if (First.Range.getBegin().isValid())
310*12c85518Srobert Result.Range.setBegin(First.Range.getBegin());
311*12c85518Srobert else
312*12c85518Srobert Result.Range.setBegin(Second.Range.getBegin());
313*12c85518Srobert if (Second.Range.getEnd().isValid())
314*12c85518Srobert Result.Range.setEnd(Second.Range.getEnd());
315*12c85518Srobert else
316*12c85518Srobert Result.Range.setEnd(First.Range.getEnd());
317*12c85518Srobert }
318