xref: /openbsd-src/gnu/llvm/clang/lib/Sema/ParsedAttr.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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