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 ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() { 149 return llvm::makeArrayRef(AttrInfoMap); 150 } 151 152 unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } 153 154 unsigned ParsedAttr::getMaxArgs() const { 155 return getMinArgs() + getInfo().OptArgs; 156 } 157 158 bool ParsedAttr::hasCustomParsing() const { 159 return getInfo().HasCustomParsing; 160 } 161 162 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 163 return getInfo().diagAppertainsToDecl(S, *this, D); 164 } 165 166 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const { 167 return getInfo().diagAppertainsToStmt(S, *this, St); 168 } 169 170 bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const { 171 return getInfo().diagMutualExclusion(S, *this, D); 172 } 173 174 bool ParsedAttr::appliesToDecl(const Decl *D, 175 attr::SubjectMatchRule MatchRule) const { 176 return checkAttributeMatchRuleAppliesTo(D, MatchRule); 177 } 178 179 void ParsedAttr::getMatchRules( 180 const LangOptions &LangOpts, 181 SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules) 182 const { 183 return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts); 184 } 185 186 bool ParsedAttr::diagnoseLangOpts(Sema &S) const { 187 if (getInfo().acceptsLangOpts(S.getLangOpts())) 188 return true; 189 S.Diag(getLoc(), diag::warn_attribute_ignored) << *this; 190 return false; 191 } 192 193 bool ParsedAttr::isTargetSpecificAttr() const { 194 return getInfo().IsTargetSpecific; 195 } 196 197 bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; } 198 199 bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; } 200 201 bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { 202 return getInfo().existsInTarget(Target); 203 } 204 205 bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; } 206 207 bool ParsedAttr::isSupportedByPragmaAttribute() const { 208 return getInfo().IsSupportedByPragmaAttribute; 209 } 210 211 unsigned ParsedAttr::getSemanticSpelling() const { 212 return getInfo().spellingIndexToSemanticSpelling(*this); 213 } 214 215 bool ParsedAttr::hasVariadicArg() const { 216 // If the attribute has the maximum number of optional arguments, we will 217 // claim that as being variadic. If we someday get an attribute that 218 // legitimately bumps up against that maximum, we can use another bit to track 219 // whether it's truly variadic or not. 220 return getInfo().OptArgs == 15; 221 } 222 223 static unsigned getNumAttributeArgs(const ParsedAttr &AL) { 224 // FIXME: Include the type in the argument list. 225 return AL.getNumArgs() + AL.hasParsedType(); 226 } 227 228 template <typename Compare> 229 static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, 230 unsigned Num, unsigned Diag, 231 Compare Comp) { 232 if (Comp(getNumAttributeArgs(AL), Num)) { 233 S.Diag(AL.getLoc(), Diag) << AL << Num; 234 return false; 235 } 236 return true; 237 } 238 239 bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const { 240 return checkAttributeNumArgsImpl(S, *this, Num, 241 diag::err_attribute_wrong_number_arguments, 242 std::not_equal_to<unsigned>()); 243 } 244 bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const { 245 return checkAttributeNumArgsImpl(S, *this, Num, 246 diag::err_attribute_too_few_arguments, 247 std::less<unsigned>()); 248 } 249 bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const { 250 return checkAttributeNumArgsImpl(S, *this, Num, 251 diag::err_attribute_too_many_arguments, 252 std::greater<unsigned>()); 253 } 254