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