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