xref: /freebsd/contrib/llvm-project/clang/lib/Sema/ParsedAttr.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //======- ParsedAttr.cpp --------------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file defines the ParsedAttr class implementation
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12*0b57cec5SDimitry Andric 
13*0b57cec5SDimitry Andric #include "clang/Sema/ParsedAttr.h"
14*0b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
15*0b57cec5SDimitry Andric #include "clang/Basic/AttrSubjectMatchRules.h"
16*0b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h"
17*0b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h"
18*0b57cec5SDimitry Andric #include "clang/Sema/SemaInternal.h"
19*0b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
20*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
21*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
22*0b57cec5SDimitry Andric #include <cassert>
23*0b57cec5SDimitry Andric #include <cstddef>
24*0b57cec5SDimitry Andric #include <utility>
25*0b57cec5SDimitry Andric 
26*0b57cec5SDimitry Andric using namespace clang;
27*0b57cec5SDimitry Andric 
28*0b57cec5SDimitry Andric IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc,
29*0b57cec5SDimitry Andric                                      IdentifierInfo *Ident) {
30*0b57cec5SDimitry Andric   IdentifierLoc *Result = new (Ctx) IdentifierLoc;
31*0b57cec5SDimitry Andric   Result->Loc = Loc;
32*0b57cec5SDimitry Andric   Result->Ident = Ident;
33*0b57cec5SDimitry Andric   return Result;
34*0b57cec5SDimitry Andric }
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric size_t ParsedAttr::allocated_size() const {
37*0b57cec5SDimitry Andric   if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;
38*0b57cec5SDimitry Andric   else if (IsTypeTagForDatatype)
39*0b57cec5SDimitry Andric     return AttributeFactory::TypeTagForDatatypeAllocSize;
40*0b57cec5SDimitry Andric   else if (IsProperty)
41*0b57cec5SDimitry Andric     return AttributeFactory::PropertyAllocSize;
42*0b57cec5SDimitry Andric   else if (HasParsedType)
43*0b57cec5SDimitry Andric     return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
44*0b57cec5SDimitry Andric                             detail::TypeTagForDatatypeData, ParsedType,
45*0b57cec5SDimitry Andric                             detail::PropertyData>(0, 0, 0, 1, 0);
46*0b57cec5SDimitry Andric   return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
47*0b57cec5SDimitry Andric                           detail::TypeTagForDatatypeData, ParsedType,
48*0b57cec5SDimitry Andric                           detail::PropertyData>(NumArgs, 0, 0, 0, 0);
49*0b57cec5SDimitry Andric }
50*0b57cec5SDimitry Andric 
51*0b57cec5SDimitry Andric AttributeFactory::AttributeFactory() {
52*0b57cec5SDimitry Andric   // Go ahead and configure all the inline capacity.  This is just a memset.
53*0b57cec5SDimitry Andric   FreeLists.resize(InlineFreeListsCapacity);
54*0b57cec5SDimitry Andric }
55*0b57cec5SDimitry Andric AttributeFactory::~AttributeFactory() = default;
56*0b57cec5SDimitry Andric 
57*0b57cec5SDimitry Andric static size_t getFreeListIndexForSize(size_t size) {
58*0b57cec5SDimitry Andric   assert(size >= sizeof(ParsedAttr));
59*0b57cec5SDimitry Andric   assert((size % sizeof(void*)) == 0);
60*0b57cec5SDimitry Andric   return ((size - sizeof(ParsedAttr)) / sizeof(void *));
61*0b57cec5SDimitry Andric }
62*0b57cec5SDimitry Andric 
63*0b57cec5SDimitry Andric void *AttributeFactory::allocate(size_t size) {
64*0b57cec5SDimitry Andric   // Check for a previously reclaimed attribute.
65*0b57cec5SDimitry Andric   size_t index = getFreeListIndexForSize(size);
66*0b57cec5SDimitry Andric   if (index < FreeLists.size() && !FreeLists[index].empty()) {
67*0b57cec5SDimitry Andric     ParsedAttr *attr = FreeLists[index].back();
68*0b57cec5SDimitry Andric     FreeLists[index].pop_back();
69*0b57cec5SDimitry Andric     return attr;
70*0b57cec5SDimitry Andric   }
71*0b57cec5SDimitry Andric 
72*0b57cec5SDimitry Andric   // Otherwise, allocate something new.
73*0b57cec5SDimitry Andric   return Alloc.Allocate(size, alignof(AttributeFactory));
74*0b57cec5SDimitry Andric }
75*0b57cec5SDimitry Andric 
76*0b57cec5SDimitry Andric void AttributeFactory::deallocate(ParsedAttr *Attr) {
77*0b57cec5SDimitry Andric   size_t size = Attr->allocated_size();
78*0b57cec5SDimitry Andric   size_t freeListIndex = getFreeListIndexForSize(size);
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric   // Expand FreeLists to the appropriate size, if required.
81*0b57cec5SDimitry Andric   if (freeListIndex >= FreeLists.size())
82*0b57cec5SDimitry Andric     FreeLists.resize(freeListIndex + 1);
83*0b57cec5SDimitry Andric 
84*0b57cec5SDimitry Andric #ifndef NDEBUG
85*0b57cec5SDimitry Andric   // In debug mode, zero out the attribute to help find memory overwriting.
86*0b57cec5SDimitry Andric   memset(Attr, 0, size);
87*0b57cec5SDimitry Andric #endif
88*0b57cec5SDimitry Andric 
89*0b57cec5SDimitry Andric   // Add 'Attr' to the appropriate free-list.
90*0b57cec5SDimitry Andric   FreeLists[freeListIndex].push_back(Attr);
91*0b57cec5SDimitry Andric }
92*0b57cec5SDimitry Andric 
93*0b57cec5SDimitry Andric void AttributeFactory::reclaimPool(AttributePool &cur) {
94*0b57cec5SDimitry Andric   for (ParsedAttr *AL : cur.Attrs)
95*0b57cec5SDimitry Andric     deallocate(AL);
96*0b57cec5SDimitry Andric }
97*0b57cec5SDimitry Andric 
98*0b57cec5SDimitry Andric void AttributePool::takePool(AttributePool &pool) {
99*0b57cec5SDimitry Andric   Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end());
100*0b57cec5SDimitry Andric   pool.Attrs.clear();
101*0b57cec5SDimitry Andric }
102*0b57cec5SDimitry Andric 
103*0b57cec5SDimitry Andric #include "clang/Sema/AttrParsedAttrKinds.inc"
104*0b57cec5SDimitry Andric 
105*0b57cec5SDimitry Andric static StringRef normalizeAttrScopeName(StringRef ScopeName,
106*0b57cec5SDimitry Andric                                         ParsedAttr::Syntax SyntaxUsed) {
107*0b57cec5SDimitry Andric   // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
108*0b57cec5SDimitry Andric   // to be "clang".
109*0b57cec5SDimitry Andric   if (SyntaxUsed == ParsedAttr::AS_CXX11 ||
110*0b57cec5SDimitry Andric     SyntaxUsed == ParsedAttr::AS_C2x) {
111*0b57cec5SDimitry Andric     if (ScopeName == "__gnu__")
112*0b57cec5SDimitry Andric       ScopeName = "gnu";
113*0b57cec5SDimitry Andric     else if (ScopeName == "_Clang")
114*0b57cec5SDimitry Andric       ScopeName = "clang";
115*0b57cec5SDimitry Andric   }
116*0b57cec5SDimitry Andric   return ScopeName;
117*0b57cec5SDimitry Andric }
118*0b57cec5SDimitry Andric 
119*0b57cec5SDimitry Andric static StringRef normalizeAttrName(StringRef AttrName,
120*0b57cec5SDimitry Andric                                    StringRef NormalizedScopeName,
121*0b57cec5SDimitry Andric                                    ParsedAttr::Syntax SyntaxUsed) {
122*0b57cec5SDimitry Andric   // Normalize the attribute name, __foo__ becomes foo. This is only allowable
123*0b57cec5SDimitry Andric   // for GNU attributes, and attributes using the double square bracket syntax.
124*0b57cec5SDimitry Andric   bool ShouldNormalize =
125*0b57cec5SDimitry Andric       SyntaxUsed == ParsedAttr::AS_GNU ||
126*0b57cec5SDimitry Andric       ((SyntaxUsed == ParsedAttr::AS_CXX11 ||
127*0b57cec5SDimitry Andric         SyntaxUsed == ParsedAttr::AS_C2x) &&
128*0b57cec5SDimitry Andric        (NormalizedScopeName == "gnu" || NormalizedScopeName == "clang"));
129*0b57cec5SDimitry Andric   if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") &&
130*0b57cec5SDimitry Andric       AttrName.endswith("__"))
131*0b57cec5SDimitry Andric     AttrName = AttrName.slice(2, AttrName.size() - 2);
132*0b57cec5SDimitry Andric 
133*0b57cec5SDimitry Andric   return AttrName;
134*0b57cec5SDimitry Andric }
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric ParsedAttr::Kind ParsedAttr::getKind(const IdentifierInfo *Name,
137*0b57cec5SDimitry Andric                                      const IdentifierInfo *ScopeName,
138*0b57cec5SDimitry Andric                                      Syntax SyntaxUsed) {
139*0b57cec5SDimitry Andric   StringRef AttrName = Name->getName();
140*0b57cec5SDimitry Andric 
141*0b57cec5SDimitry Andric   SmallString<64> FullName;
142*0b57cec5SDimitry Andric   if (ScopeName)
143*0b57cec5SDimitry Andric     FullName += normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed);
144*0b57cec5SDimitry Andric 
145*0b57cec5SDimitry Andric   AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed);
146*0b57cec5SDimitry Andric 
147*0b57cec5SDimitry Andric   // Ensure that in the case of C++11 attributes, we look for '::foo' if it is
148*0b57cec5SDimitry Andric   // unscoped.
149*0b57cec5SDimitry Andric   if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x)
150*0b57cec5SDimitry Andric     FullName += "::";
151*0b57cec5SDimitry Andric   FullName += AttrName;
152*0b57cec5SDimitry Andric 
153*0b57cec5SDimitry Andric   return ::getAttrKind(FullName, SyntaxUsed);
154*0b57cec5SDimitry Andric }
155*0b57cec5SDimitry Andric 
156*0b57cec5SDimitry Andric unsigned ParsedAttr::getAttributeSpellingListIndex() const {
157*0b57cec5SDimitry Andric   // Both variables will be used in tablegen generated
158*0b57cec5SDimitry Andric   // attribute spell list index matching code.
159*0b57cec5SDimitry Andric   auto Syntax = static_cast<ParsedAttr::Syntax>(SyntaxUsed);
160*0b57cec5SDimitry Andric   StringRef Scope =
161*0b57cec5SDimitry Andric       ScopeName ? normalizeAttrScopeName(ScopeName->getName(), Syntax) : "";
162*0b57cec5SDimitry Andric   StringRef Name = normalizeAttrName(AttrName->getName(), Scope, Syntax);
163*0b57cec5SDimitry Andric 
164*0b57cec5SDimitry Andric #include "clang/Sema/AttrSpellingListIndex.inc"
165*0b57cec5SDimitry Andric 
166*0b57cec5SDimitry Andric }
167*0b57cec5SDimitry Andric 
168*0b57cec5SDimitry Andric struct ParsedAttrInfo {
169*0b57cec5SDimitry Andric   unsigned NumArgs : 4;
170*0b57cec5SDimitry Andric   unsigned OptArgs : 4;
171*0b57cec5SDimitry Andric   unsigned HasCustomParsing : 1;
172*0b57cec5SDimitry Andric   unsigned IsTargetSpecific : 1;
173*0b57cec5SDimitry Andric   unsigned IsType : 1;
174*0b57cec5SDimitry Andric   unsigned IsStmt : 1;
175*0b57cec5SDimitry Andric   unsigned IsKnownToGCC : 1;
176*0b57cec5SDimitry Andric   unsigned IsSupportedByPragmaAttribute : 1;
177*0b57cec5SDimitry Andric 
178*0b57cec5SDimitry Andric   bool (*DiagAppertainsToDecl)(Sema &S, const ParsedAttr &Attr, const Decl *);
179*0b57cec5SDimitry Andric   bool (*DiagLangOpts)(Sema &S, const ParsedAttr &Attr);
180*0b57cec5SDimitry Andric   bool (*ExistsInTarget)(const TargetInfo &Target);
181*0b57cec5SDimitry Andric   unsigned (*SpellingIndexToSemanticSpelling)(const ParsedAttr &Attr);
182*0b57cec5SDimitry Andric   void (*GetPragmaAttributeMatchRules)(
183*0b57cec5SDimitry Andric       llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules,
184*0b57cec5SDimitry Andric       const LangOptions &LangOpts);
185*0b57cec5SDimitry Andric };
186*0b57cec5SDimitry Andric 
187*0b57cec5SDimitry Andric namespace {
188*0b57cec5SDimitry Andric 
189*0b57cec5SDimitry Andric #include "clang/Sema/AttrParsedAttrImpl.inc"
190*0b57cec5SDimitry Andric 
191*0b57cec5SDimitry Andric } // namespace
192*0b57cec5SDimitry Andric 
193*0b57cec5SDimitry Andric static const ParsedAttrInfo &getInfo(const ParsedAttr &A) {
194*0b57cec5SDimitry Andric   return AttrInfoMap[A.getKind()];
195*0b57cec5SDimitry Andric }
196*0b57cec5SDimitry Andric 
197*0b57cec5SDimitry Andric unsigned ParsedAttr::getMinArgs() const { return getInfo(*this).NumArgs; }
198*0b57cec5SDimitry Andric 
199*0b57cec5SDimitry Andric unsigned ParsedAttr::getMaxArgs() const {
200*0b57cec5SDimitry Andric   return getMinArgs() + getInfo(*this).OptArgs;
201*0b57cec5SDimitry Andric }
202*0b57cec5SDimitry Andric 
203*0b57cec5SDimitry Andric bool ParsedAttr::hasCustomParsing() const {
204*0b57cec5SDimitry Andric   return getInfo(*this).HasCustomParsing;
205*0b57cec5SDimitry Andric }
206*0b57cec5SDimitry Andric 
207*0b57cec5SDimitry Andric bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
208*0b57cec5SDimitry Andric   return getInfo(*this).DiagAppertainsToDecl(S, *this, D);
209*0b57cec5SDimitry Andric }
210*0b57cec5SDimitry Andric 
211*0b57cec5SDimitry Andric bool ParsedAttr::appliesToDecl(const Decl *D,
212*0b57cec5SDimitry Andric                                attr::SubjectMatchRule MatchRule) const {
213*0b57cec5SDimitry Andric   return checkAttributeMatchRuleAppliesTo(D, MatchRule);
214*0b57cec5SDimitry Andric }
215*0b57cec5SDimitry Andric 
216*0b57cec5SDimitry Andric void ParsedAttr::getMatchRules(
217*0b57cec5SDimitry Andric     const LangOptions &LangOpts,
218*0b57cec5SDimitry Andric     SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
219*0b57cec5SDimitry Andric     const {
220*0b57cec5SDimitry Andric   return getInfo(*this).GetPragmaAttributeMatchRules(MatchRules, LangOpts);
221*0b57cec5SDimitry Andric }
222*0b57cec5SDimitry Andric 
223*0b57cec5SDimitry Andric bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
224*0b57cec5SDimitry Andric   return getInfo(*this).DiagLangOpts(S, *this);
225*0b57cec5SDimitry Andric }
226*0b57cec5SDimitry Andric 
227*0b57cec5SDimitry Andric bool ParsedAttr::isTargetSpecificAttr() const {
228*0b57cec5SDimitry Andric   return getInfo(*this).IsTargetSpecific;
229*0b57cec5SDimitry Andric }
230*0b57cec5SDimitry Andric 
231*0b57cec5SDimitry Andric bool ParsedAttr::isTypeAttr() const { return getInfo(*this).IsType; }
232*0b57cec5SDimitry Andric 
233*0b57cec5SDimitry Andric bool ParsedAttr::isStmtAttr() const { return getInfo(*this).IsStmt; }
234*0b57cec5SDimitry Andric 
235*0b57cec5SDimitry Andric bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {
236*0b57cec5SDimitry Andric   return getInfo(*this).ExistsInTarget(Target);
237*0b57cec5SDimitry Andric }
238*0b57cec5SDimitry Andric 
239*0b57cec5SDimitry Andric bool ParsedAttr::isKnownToGCC() const { return getInfo(*this).IsKnownToGCC; }
240*0b57cec5SDimitry Andric 
241*0b57cec5SDimitry Andric bool ParsedAttr::isSupportedByPragmaAttribute() const {
242*0b57cec5SDimitry Andric   return getInfo(*this).IsSupportedByPragmaAttribute;
243*0b57cec5SDimitry Andric }
244*0b57cec5SDimitry Andric 
245*0b57cec5SDimitry Andric unsigned ParsedAttr::getSemanticSpelling() const {
246*0b57cec5SDimitry Andric   return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
247*0b57cec5SDimitry Andric }
248*0b57cec5SDimitry Andric 
249*0b57cec5SDimitry Andric bool ParsedAttr::hasVariadicArg() const {
250*0b57cec5SDimitry Andric   // If the attribute has the maximum number of optional arguments, we will
251*0b57cec5SDimitry Andric   // claim that as being variadic. If we someday get an attribute that
252*0b57cec5SDimitry Andric   // legitimately bumps up against that maximum, we can use another bit to track
253*0b57cec5SDimitry Andric   // whether it's truly variadic or not.
254*0b57cec5SDimitry Andric   return getInfo(*this).OptArgs == 15;
255*0b57cec5SDimitry Andric }
256