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/SmallVector.h"
24 using namespace clang
;
26 IdentifierLoc
*IdentifierLoc::create(ASTContext
&Ctx
, SourceLocation Loc
,
27 IdentifierInfo
*Ident
) {
28 IdentifierLoc
*Result
= new (Ctx
) IdentifierLoc
;
30 Result
->Ident
= Ident
;
34 size_t ParsedAttr::allocated_size() const {
35 if (IsAvailability
) return AttributeFactory::AvailabilityAllocSize
;
36 else if (IsTypeTagForDatatype
)
37 return AttributeFactory::TypeTagForDatatypeAllocSize
;
39 return AttributeFactory::PropertyAllocSize
;
40 else if (HasParsedType
)
41 return totalSizeToAlloc
<ArgsUnion
, detail::AvailabilityData
,
42 detail::TypeTagForDatatypeData
, ParsedType
,
43 detail::PropertyData
>(0, 0, 0, 1, 0);
44 return totalSizeToAlloc
<ArgsUnion
, detail::AvailabilityData
,
45 detail::TypeTagForDatatypeData
, ParsedType
,
46 detail::PropertyData
>(NumArgs
, 0, 0, 0, 0);
49 AttributeFactory::AttributeFactory() {
50 // Go ahead and configure all the inline capacity. This is just a memset.
51 FreeLists
.resize(InlineFreeListsCapacity
);
53 AttributeFactory::~AttributeFactory() = default;
55 static size_t getFreeListIndexForSize(size_t size
) {
56 assert(size
>= sizeof(ParsedAttr
));
57 assert((size
% sizeof(void*)) == 0);
58 return ((size
- sizeof(ParsedAttr
)) / sizeof(void *));
61 void *AttributeFactory::allocate(size_t size
) {
62 // Check for a previously reclaimed attribute.
63 size_t index
= getFreeListIndexForSize(size
);
64 if (index
< FreeLists
.size() && !FreeLists
[index
].empty()) {
65 ParsedAttr
*attr
= FreeLists
[index
].back();
66 FreeLists
[index
].pop_back();
70 // Otherwise, allocate something new.
71 return Alloc
.Allocate(size
, alignof(AttributeFactory
));
74 void AttributeFactory::deallocate(ParsedAttr
*Attr
) {
75 size_t size
= Attr
->allocated_size();
76 size_t freeListIndex
= getFreeListIndexForSize(size
);
78 // Expand FreeLists to the appropriate size, if required.
79 if (freeListIndex
>= FreeLists
.size())
80 FreeLists
.resize(freeListIndex
+ 1);
83 // In debug mode, zero out the attribute to help find memory overwriting.
84 memset(Attr
, 0, size
);
87 // Add 'Attr' to the appropriate free-list.
88 FreeLists
[freeListIndex
].push_back(Attr
);
91 void AttributeFactory::reclaimPool(AttributePool
&cur
) {
92 for (ParsedAttr
*AL
: cur
.Attrs
)
96 void AttributePool::takePool(AttributePool
&pool
) {
97 Attrs
.insert(Attrs
.end(), pool
.Attrs
.begin(), pool
.Attrs
.end());
101 void AttributePool::takeFrom(ParsedAttributesView
&List
, AttributePool
&Pool
) {
102 assert(&Pool
!= this && "AttributePool can't take attributes from itself");
103 llvm::for_each(List
.AttrList
, [&Pool
](ParsedAttr
*A
) { Pool
.remove(A
); });
104 Attrs
.insert(Attrs
.end(), List
.AttrList
.begin(), List
.AttrList
.end());
109 #include "clang/Sema/AttrParsedAttrImpl.inc"
113 const ParsedAttrInfo
&ParsedAttrInfo::get(const AttributeCommonInfo
&A
) {
114 // If we have a ParsedAttrInfo for this ParsedAttr then return that.
115 if ((size_t)A
.getParsedKind() < std::size(AttrInfoMap
))
116 return *AttrInfoMap
[A
.getParsedKind()];
118 // If this is an ignored attribute then return an appropriate ParsedAttrInfo.
119 static const ParsedAttrInfo
IgnoredParsedAttrInfo(
120 AttributeCommonInfo::IgnoredAttribute
);
121 if (A
.getParsedKind() == AttributeCommonInfo::IgnoredAttribute
)
122 return IgnoredParsedAttrInfo
;
124 // Otherwise this may be an attribute defined by a plugin.
126 // Search for a ParsedAttrInfo whose name and syntax match.
127 std::string FullName
= A
.getNormalizedFullName();
128 AttributeCommonInfo::Syntax SyntaxUsed
= A
.getSyntax();
129 if (SyntaxUsed
== AttributeCommonInfo::AS_ContextSensitiveKeyword
)
130 SyntaxUsed
= AttributeCommonInfo::AS_Keyword
;
132 for (auto &Ptr
: getAttributePluginInstances())
133 if (Ptr
->hasSpelling(SyntaxUsed
, FullName
))
136 // If we failed to find a match then return a default ParsedAttrInfo.
137 static const ParsedAttrInfo
DefaultParsedAttrInfo(
138 AttributeCommonInfo::UnknownAttribute
);
139 return DefaultParsedAttrInfo
;
142 ArrayRef
<const ParsedAttrInfo
*> ParsedAttrInfo::getAllBuiltin() {
143 return llvm::ArrayRef(AttrInfoMap
);
146 unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs
; }
148 unsigned ParsedAttr::getMaxArgs() const {
149 return getMinArgs() + getInfo().OptArgs
;
152 unsigned ParsedAttr::getNumArgMembers() const {
153 return getInfo().NumArgMembers
;
156 bool ParsedAttr::hasCustomParsing() const {
157 return getInfo().HasCustomParsing
;
160 bool ParsedAttr::diagnoseAppertainsTo(Sema
&S
, const Decl
*D
) const {
161 return getInfo().diagAppertainsToDecl(S
, *this, D
);
164 bool ParsedAttr::diagnoseAppertainsTo(Sema
&S
, const Stmt
*St
) const {
165 return getInfo().diagAppertainsToStmt(S
, *this, St
);
168 bool ParsedAttr::diagnoseMutualExclusion(Sema
&S
, const Decl
*D
) const {
169 return getInfo().diagMutualExclusion(S
, *this, D
);
172 bool ParsedAttr::appliesToDecl(const Decl
*D
,
173 attr::SubjectMatchRule MatchRule
) const {
174 return checkAttributeMatchRuleAppliesTo(D
, MatchRule
);
177 void ParsedAttr::getMatchRules(
178 const LangOptions
&LangOpts
,
179 SmallVectorImpl
<std::pair
<attr::SubjectMatchRule
, bool>> &MatchRules
)
181 return getInfo().getPragmaAttributeMatchRules(MatchRules
, LangOpts
);
184 bool ParsedAttr::diagnoseLangOpts(Sema
&S
) const {
185 if (getInfo().acceptsLangOpts(S
.getLangOpts()))
187 S
.Diag(getLoc(), diag::warn_attribute_ignored
) << *this;
191 bool ParsedAttr::isTargetSpecificAttr() const {
192 return getInfo().IsTargetSpecific
;
195 bool ParsedAttr::isTypeAttr() const { return getInfo().IsType
; }
197 bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt
; }
199 bool ParsedAttr::existsInTarget(const TargetInfo
&Target
) const {
200 Kind K
= getParsedKind();
202 // If the attribute has a target-specific spelling, check that it exists.
203 // Only call this if the attr is not ignored/unknown. For most targets, this
204 // function just returns true.
205 bool HasSpelling
= K
!= IgnoredAttribute
&& K
!= UnknownAttribute
&&
206 K
!= NoSemaHandlerAttribute
;
207 bool TargetSpecificSpellingExists
=
209 getInfo().spellingExistsInTarget(Target
, getAttributeSpellingListIndex());
211 return getInfo().existsInTarget(Target
) && TargetSpecificSpellingExists
;
214 bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC
; }
216 bool ParsedAttr::isSupportedByPragmaAttribute() const {
217 return getInfo().IsSupportedByPragmaAttribute
;
220 bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {
221 if (isRegularKeywordAttribute())
222 // The appurtenance rules are applied strictly for all regular keyword
226 assert(isStandardAttributeSyntax() || isAlignas());
228 // We have historically allowed some type attributes with standard attribute
229 // syntax to slide to the decl-specifier-seq, so we have to keep supporting
230 // it. This property is consciously not defined as a flag in Attr.td because
231 // we don't want new attributes to specify it.
233 // Note: No new entries should be added to this list. Entries should be
234 // removed from this list after a suitable deprecation period, provided that
235 // there are no compatibility considerations with other compilers. If
236 // possible, we would like this list to go away entirely.
237 switch (getParsedKind()) {
238 case AT_AddressSpace
:
239 case AT_OpenCLPrivateAddressSpace
:
240 case AT_OpenCLGlobalAddressSpace
:
241 case AT_OpenCLGlobalDeviceAddressSpace
:
242 case AT_OpenCLGlobalHostAddressSpace
:
243 case AT_OpenCLLocalAddressSpace
:
244 case AT_OpenCLConstantAddressSpace
:
245 case AT_OpenCLGenericAddressSpace
:
246 case AT_NeonPolyVectorType
:
247 case AT_NeonVectorType
:
248 case AT_ArmMveStrictPolymorphism
:
258 bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack
; }
260 unsigned ParsedAttr::getSemanticSpelling() const {
261 return getInfo().spellingIndexToSemanticSpelling(*this);
264 bool ParsedAttr::hasVariadicArg() const {
265 // If the attribute has the maximum number of optional arguments, we will
266 // claim that as being variadic. If we someday get an attribute that
267 // legitimately bumps up against that maximum, we can use another bit to track
268 // whether it's truly variadic or not.
269 return getInfo().OptArgs
== 15;
272 bool ParsedAttr::isParamExpr(size_t N
) const {
273 return getInfo().isParamExpr(N
);
276 void ParsedAttr::handleAttrWithDelayedArgs(Sema
&S
, Decl
*D
) const {
277 ::handleAttrWithDelayedArgs(S
, D
, *this);
280 static unsigned getNumAttributeArgs(const ParsedAttr
&AL
) {
281 // FIXME: Include the type in the argument list.
282 return AL
.getNumArgs() + AL
.hasParsedType();
285 template <typename Compare
>
286 static bool checkAttributeNumArgsImpl(Sema
&S
, const ParsedAttr
&AL
,
287 unsigned Num
, unsigned Diag
,
289 if (Comp(getNumAttributeArgs(AL
), Num
)) {
290 S
.Diag(AL
.getLoc(), Diag
) << AL
<< Num
;
296 bool ParsedAttr::checkExactlyNumArgs(Sema
&S
, unsigned Num
) const {
297 return checkAttributeNumArgsImpl(S
, *this, Num
,
298 diag::err_attribute_wrong_number_arguments
,
299 std::not_equal_to
<unsigned>());
301 bool ParsedAttr::checkAtLeastNumArgs(Sema
&S
, unsigned Num
) const {
302 return checkAttributeNumArgsImpl(S
, *this, Num
,
303 diag::err_attribute_too_few_arguments
,
304 std::less
<unsigned>());
306 bool ParsedAttr::checkAtMostNumArgs(Sema
&S
, unsigned Num
) const {
307 return checkAttributeNumArgsImpl(S
, *this, Num
,
308 diag::err_attribute_too_many_arguments
,
309 std::greater
<unsigned>());
312 void clang::takeAndConcatenateAttrs(ParsedAttributes
&First
,
313 ParsedAttributes
&Second
,
314 ParsedAttributes
&Result
) {
315 // Note that takeAllFrom() puts the attributes at the beginning of the list,
316 // so to obtain the correct ordering, we add `Second`, then `First`.
317 Result
.takeAllFrom(Second
);
318 Result
.takeAllFrom(First
);
319 if (First
.Range
.getBegin().isValid())
320 Result
.Range
.setBegin(First
.Range
.getBegin());
322 Result
.Range
.setBegin(Second
.Range
.getBegin());
323 if (Second
.Range
.getEnd().isValid())
324 Result
.Range
.setEnd(Second
.Range
.getEnd());
326 Result
.Range
.setEnd(First
.Range
.getEnd());