1 //======- ParsedAttr.cpp --------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines the ParsedAttr class implementation
11 //===----------------------------------------------------------------------===//
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"
26 using namespace clang
;
28 IdentifierLoc
*IdentifierLoc::create(ASTContext
&Ctx
, SourceLocation Loc
,
29 IdentifierInfo
*Ident
) {
30 IdentifierLoc
*Result
= new (Ctx
) IdentifierLoc
;
32 Result
->Ident
= Ident
;
36 size_t ParsedAttr::allocated_size() const {
37 if (IsAvailability
) return AttributeFactory::AvailabilityAllocSize
;
38 else if (IsTypeTagForDatatype
)
39 return AttributeFactory::TypeTagForDatatypeAllocSize
;
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);
51 AttributeFactory::AttributeFactory() {
52 // Go ahead and configure all the inline capacity. This is just a memset.
53 FreeLists
.resize(InlineFreeListsCapacity
);
55 AttributeFactory::~AttributeFactory() = default;
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 *));
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();
72 // Otherwise, allocate something new.
73 return Alloc
.Allocate(size
, alignof(AttributeFactory
));
76 void AttributeFactory::deallocate(ParsedAttr
*Attr
) {
77 size_t size
= Attr
->allocated_size();
78 size_t freeListIndex
= getFreeListIndexForSize(size
);
80 // Expand FreeLists to the appropriate size, if required.
81 if (freeListIndex
>= FreeLists
.size())
82 FreeLists
.resize(freeListIndex
+ 1);
85 // In debug mode, zero out the attribute to help find memory overwriting.
86 memset(Attr
, 0, size
);
89 // Add 'Attr' to the appropriate free-list.
90 FreeLists
[freeListIndex
].push_back(Attr
);
93 void AttributeFactory::reclaimPool(AttributePool
&cur
) {
94 for (ParsedAttr
*AL
: cur
.Attrs
)
98 void AttributePool::takePool(AttributePool
&pool
) {
99 Attrs
.insert(Attrs
.end(), pool
.Attrs
.begin(), pool
.Attrs
.end());
105 #include "clang/Sema/AttrParsedAttrImpl.inc"
109 const ParsedAttrInfo
&ParsedAttrInfo::get(const AttributeCommonInfo
&A
) {
110 // If we have a ParsedAttrInfo for this ParsedAttr then return that.
111 if ((size_t)A
.getParsedKind() < std::size(AttrInfoMap
))
112 return *AttrInfoMap
[A
.getParsedKind()];
114 // If this is an ignored attribute then return an appropriate ParsedAttrInfo.
115 static const ParsedAttrInfo
IgnoredParsedAttrInfo(
116 AttributeCommonInfo::IgnoredAttribute
);
117 if (A
.getParsedKind() == AttributeCommonInfo::IgnoredAttribute
)
118 return IgnoredParsedAttrInfo
;
120 // Otherwise this may be an attribute defined by a plugin.
122 // Search for a ParsedAttrInfo whose name and syntax match.
123 std::string FullName
= A
.getNormalizedFullName();
124 AttributeCommonInfo::Syntax SyntaxUsed
= A
.getSyntax();
125 if (SyntaxUsed
== AttributeCommonInfo::AS_ContextSensitiveKeyword
)
126 SyntaxUsed
= AttributeCommonInfo::AS_Keyword
;
128 for (auto &Ptr
: getAttributePluginInstances())
129 if (Ptr
->hasSpelling(SyntaxUsed
, FullName
))
132 // If we failed to find a match then return a default ParsedAttrInfo.
133 static const ParsedAttrInfo
DefaultParsedAttrInfo(
134 AttributeCommonInfo::UnknownAttribute
);
135 return DefaultParsedAttrInfo
;
138 ArrayRef
<const ParsedAttrInfo
*> ParsedAttrInfo::getAllBuiltin() {
139 return llvm::ArrayRef(AttrInfoMap
);
142 unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs
; }
144 unsigned ParsedAttr::getMaxArgs() const {
145 return getMinArgs() + getInfo().OptArgs
;
148 unsigned ParsedAttr::getNumArgMembers() const {
149 return getInfo().NumArgMembers
;
152 bool ParsedAttr::hasCustomParsing() const {
153 return getInfo().HasCustomParsing
;
156 bool ParsedAttr::diagnoseAppertainsTo(Sema
&S
, const Decl
*D
) const {
157 return getInfo().diagAppertainsToDecl(S
, *this, D
);
160 bool ParsedAttr::diagnoseAppertainsTo(Sema
&S
, const Stmt
*St
) const {
161 return getInfo().diagAppertainsToStmt(S
, *this, St
);
164 bool ParsedAttr::diagnoseMutualExclusion(Sema
&S
, const Decl
*D
) const {
165 return getInfo().diagMutualExclusion(S
, *this, D
);
168 bool ParsedAttr::appliesToDecl(const Decl
*D
,
169 attr::SubjectMatchRule MatchRule
) const {
170 return checkAttributeMatchRuleAppliesTo(D
, MatchRule
);
173 void ParsedAttr::getMatchRules(
174 const LangOptions
&LangOpts
,
175 SmallVectorImpl
<std::pair
<attr::SubjectMatchRule
, bool>> &MatchRules
)
177 return getInfo().getPragmaAttributeMatchRules(MatchRules
, LangOpts
);
180 bool ParsedAttr::diagnoseLangOpts(Sema
&S
) const {
181 if (getInfo().acceptsLangOpts(S
.getLangOpts()))
183 S
.Diag(getLoc(), diag::warn_attribute_ignored
) << *this;
187 bool ParsedAttr::isTargetSpecificAttr() const {
188 return getInfo().IsTargetSpecific
;
191 bool ParsedAttr::isTypeAttr() const { return getInfo().IsType
; }
193 bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt
; }
195 bool ParsedAttr::existsInTarget(const TargetInfo
&Target
) const {
196 return getInfo().existsInTarget(Target
) &&
197 getInfo().spellingExistsInTarget(Target
,
198 getAttributeSpellingListIndex());
201 bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC
; }
203 bool ParsedAttr::isSupportedByPragmaAttribute() const {
204 return getInfo().IsSupportedByPragmaAttribute
;
207 bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {
208 if (isRegularKeywordAttribute())
209 // The appurtenance rules are applied strictly for all regular keyword
213 assert(isStandardAttributeSyntax());
215 // We have historically allowed some type attributes with standard attribute
216 // syntax to slide to the decl-specifier-seq, so we have to keep supporting
217 // it. This property is consciously not defined as a flag in Attr.td because
218 // we don't want new attributes to specify it.
220 // Note: No new entries should be added to this list. Entries should be
221 // removed from this list after a suitable deprecation period, provided that
222 // there are no compatibility considerations with other compilers. If
223 // possible, we would like this list to go away entirely.
224 switch (getParsedKind()) {
225 case AT_AddressSpace
:
226 case AT_OpenCLPrivateAddressSpace
:
227 case AT_OpenCLGlobalAddressSpace
:
228 case AT_OpenCLGlobalDeviceAddressSpace
:
229 case AT_OpenCLGlobalHostAddressSpace
:
230 case AT_OpenCLLocalAddressSpace
:
231 case AT_OpenCLConstantAddressSpace
:
232 case AT_OpenCLGenericAddressSpace
:
233 case AT_NeonPolyVectorType
:
234 case AT_NeonVectorType
:
235 case AT_ArmMveStrictPolymorphism
:
245 bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack
; }
247 unsigned ParsedAttr::getSemanticSpelling() const {
248 return getInfo().spellingIndexToSemanticSpelling(*this);
251 bool ParsedAttr::hasVariadicArg() const {
252 // If the attribute has the maximum number of optional arguments, we will
253 // claim that as being variadic. If we someday get an attribute that
254 // legitimately bumps up against that maximum, we can use another bit to track
255 // whether it's truly variadic or not.
256 return getInfo().OptArgs
== 15;
259 bool ParsedAttr::isParamExpr(size_t N
) const {
260 return getInfo().isParamExpr(N
);
263 void ParsedAttr::handleAttrWithDelayedArgs(Sema
&S
, Decl
*D
) const {
264 ::handleAttrWithDelayedArgs(S
, D
, *this);
267 static unsigned getNumAttributeArgs(const ParsedAttr
&AL
) {
268 // FIXME: Include the type in the argument list.
269 return AL
.getNumArgs() + AL
.hasParsedType();
272 template <typename Compare
>
273 static bool checkAttributeNumArgsImpl(Sema
&S
, const ParsedAttr
&AL
,
274 unsigned Num
, unsigned Diag
,
276 if (Comp(getNumAttributeArgs(AL
), Num
)) {
277 S
.Diag(AL
.getLoc(), Diag
) << AL
<< Num
;
283 bool ParsedAttr::checkExactlyNumArgs(Sema
&S
, unsigned Num
) const {
284 return checkAttributeNumArgsImpl(S
, *this, Num
,
285 diag::err_attribute_wrong_number_arguments
,
286 std::not_equal_to
<unsigned>());
288 bool ParsedAttr::checkAtLeastNumArgs(Sema
&S
, unsigned Num
) const {
289 return checkAttributeNumArgsImpl(S
, *this, Num
,
290 diag::err_attribute_too_few_arguments
,
291 std::less
<unsigned>());
293 bool ParsedAttr::checkAtMostNumArgs(Sema
&S
, unsigned Num
) const {
294 return checkAttributeNumArgsImpl(S
, *this, Num
,
295 diag::err_attribute_too_many_arguments
,
296 std::greater
<unsigned>());
299 void clang::takeAndConcatenateAttrs(ParsedAttributes
&First
,
300 ParsedAttributes
&Second
,
301 ParsedAttributes
&Result
) {
302 // Note that takeAllFrom() puts the attributes at the beginning of the list,
303 // so to obtain the correct ordering, we add `Second`, then `First`.
304 Result
.takeAllFrom(Second
);
305 Result
.takeAllFrom(First
);
306 if (First
.Range
.getBegin().isValid())
307 Result
.Range
.setBegin(First
.Range
.getBegin());
309 Result
.Range
.setBegin(Second
.Range
.getBegin());
310 if (Second
.Range
.getEnd().isValid())
311 Result
.Range
.setEnd(Second
.Range
.getEnd());
313 Result
.Range
.setEnd(First
.Range
.getEnd());