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 "llvm/Support/ManagedStatic.h" 23 #include <cassert> 24 #include <cstddef> 25 #include <utility> 26 27 using namespace clang; 28 29 LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry) 30 31 IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc, 32 IdentifierInfo *Ident) { 33 IdentifierLoc *Result = new (Ctx) IdentifierLoc; 34 Result->Loc = Loc; 35 Result->Ident = Ident; 36 return Result; 37 } 38 39 size_t ParsedAttr::allocated_size() const { 40 if (IsAvailability) return AttributeFactory::AvailabilityAllocSize; 41 else if (IsTypeTagForDatatype) 42 return AttributeFactory::TypeTagForDatatypeAllocSize; 43 else if (IsProperty) 44 return AttributeFactory::PropertyAllocSize; 45 else if (HasParsedType) 46 return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, 47 detail::TypeTagForDatatypeData, ParsedType, 48 detail::PropertyData>(0, 0, 0, 1, 0); 49 return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, 50 detail::TypeTagForDatatypeData, ParsedType, 51 detail::PropertyData>(NumArgs, 0, 0, 0, 0); 52 } 53 54 AttributeFactory::AttributeFactory() { 55 // Go ahead and configure all the inline capacity. This is just a memset. 56 FreeLists.resize(InlineFreeListsCapacity); 57 } 58 AttributeFactory::~AttributeFactory() = default; 59 60 static size_t getFreeListIndexForSize(size_t size) { 61 assert(size >= sizeof(ParsedAttr)); 62 assert((size % sizeof(void*)) == 0); 63 return ((size - sizeof(ParsedAttr)) / sizeof(void *)); 64 } 65 66 void *AttributeFactory::allocate(size_t size) { 67 // Check for a previously reclaimed attribute. 68 size_t index = getFreeListIndexForSize(size); 69 if (index < FreeLists.size() && !FreeLists[index].empty()) { 70 ParsedAttr *attr = FreeLists[index].back(); 71 FreeLists[index].pop_back(); 72 return attr; 73 } 74 75 // Otherwise, allocate something new. 76 return Alloc.Allocate(size, alignof(AttributeFactory)); 77 } 78 79 void AttributeFactory::deallocate(ParsedAttr *Attr) { 80 size_t size = Attr->allocated_size(); 81 size_t freeListIndex = getFreeListIndexForSize(size); 82 83 // Expand FreeLists to the appropriate size, if required. 84 if (freeListIndex >= FreeLists.size()) 85 FreeLists.resize(freeListIndex + 1); 86 87 #ifndef NDEBUG 88 // In debug mode, zero out the attribute to help find memory overwriting. 89 memset(Attr, 0, size); 90 #endif 91 92 // Add 'Attr' to the appropriate free-list. 93 FreeLists[freeListIndex].push_back(Attr); 94 } 95 96 void AttributeFactory::reclaimPool(AttributePool &cur) { 97 for (ParsedAttr *AL : cur.Attrs) 98 deallocate(AL); 99 } 100 101 void AttributePool::takePool(AttributePool &pool) { 102 Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end()); 103 pool.Attrs.clear(); 104 } 105 106 namespace { 107 108 #include "clang/Sema/AttrParsedAttrImpl.inc" 109 110 } // namespace 111 112 const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { 113 // If we have a ParsedAttrInfo for this ParsedAttr then return that. 114 if ((size_t)A.getParsedKind() < llvm::array_lengthof(AttrInfoMap)) 115 return *AttrInfoMap[A.getParsedKind()]; 116 117 // If this is an ignored attribute then return an appropriate ParsedAttrInfo. 118 static const ParsedAttrInfo IgnoredParsedAttrInfo( 119 AttributeCommonInfo::IgnoredAttribute); 120 if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute) 121 return IgnoredParsedAttrInfo; 122 123 // Otherwise this may be an attribute defined by a plugin. First instantiate 124 // all plugin attributes if we haven't already done so. 125 static llvm::ManagedStatic<std::list<std::unique_ptr<ParsedAttrInfo>>> 126 PluginAttrInstances; 127 if (PluginAttrInstances->empty()) 128 for (auto It : ParsedAttrInfoRegistry::entries()) 129 PluginAttrInstances->emplace_back(It.instantiate()); 130 131 // Search for a ParsedAttrInfo whose name and syntax match. 132 std::string FullName = A.getNormalizedFullName(); 133 AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax(); 134 if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword) 135 SyntaxUsed = AttributeCommonInfo::AS_Keyword; 136 137 for (auto &Ptr : *PluginAttrInstances) 138 for (auto &S : Ptr->Spellings) 139 if (S.Syntax == SyntaxUsed && S.NormalizedFullName == FullName) 140 return *Ptr; 141 142 // If we failed to find a match then return a default ParsedAttrInfo. 143 static const ParsedAttrInfo DefaultParsedAttrInfo( 144 AttributeCommonInfo::UnknownAttribute); 145 return DefaultParsedAttrInfo; 146 } 147 148 unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } 149 150 unsigned ParsedAttr::getMaxArgs() const { 151 return getMinArgs() + getInfo().OptArgs; 152 } 153 154 bool ParsedAttr::hasCustomParsing() const { 155 return getInfo().HasCustomParsing; 156 } 157 158 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 159 return getInfo().diagAppertainsToDecl(S, *this, D); 160 } 161 162 bool ParsedAttr::appliesToDecl(const Decl *D, 163 attr::SubjectMatchRule MatchRule) const { 164 return checkAttributeMatchRuleAppliesTo(D, MatchRule); 165 } 166 167 void ParsedAttr::getMatchRules( 168 const LangOptions &LangOpts, 169 SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules) 170 const { 171 return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts); 172 } 173 174 bool ParsedAttr::diagnoseLangOpts(Sema &S) const { 175 return getInfo().diagLangOpts(S, *this); 176 } 177 178 bool ParsedAttr::isTargetSpecificAttr() const { 179 return getInfo().IsTargetSpecific; 180 } 181 182 bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; } 183 184 bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; } 185 186 bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { 187 return getInfo().existsInTarget(Target); 188 } 189 190 bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; } 191 192 bool ParsedAttr::isSupportedByPragmaAttribute() const { 193 return getInfo().IsSupportedByPragmaAttribute; 194 } 195 196 unsigned ParsedAttr::getSemanticSpelling() const { 197 return getInfo().spellingIndexToSemanticSpelling(*this); 198 } 199 200 bool ParsedAttr::hasVariadicArg() const { 201 // If the attribute has the maximum number of optional arguments, we will 202 // claim that as being variadic. If we someday get an attribute that 203 // legitimately bumps up against that maximum, we can use another bit to track 204 // whether it's truly variadic or not. 205 return getInfo().OptArgs == 15; 206 } 207