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 27using namespace clang; 28 29LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry) 30 31IdentifierLoc *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 39size_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 54AttributeFactory::AttributeFactory() { 55 // Go ahead and configure all the inline capacity. This is just a memset. 56 FreeLists.resize(InlineFreeListsCapacity); 57} 58AttributeFactory::~AttributeFactory() = default; 59 60static 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 66void *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 79void 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 96void AttributeFactory::reclaimPool(AttributePool &cur) { 97 for (ParsedAttr *AL : cur.Attrs) 98 deallocate(AL); 99} 100 101void AttributePool::takePool(AttributePool &pool) { 102 Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end()); 103 pool.Attrs.clear(); 104} 105 106namespace { 107 108#include "clang/Sema/AttrParsedAttrImpl.inc" 109 110} // namespace 111 112const 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 148unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } 149 150unsigned ParsedAttr::getMaxArgs() const { 151 return getMinArgs() + getInfo().OptArgs; 152} 153 154bool ParsedAttr::hasCustomParsing() const { 155 return getInfo().HasCustomParsing; 156} 157 158bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 159 return getInfo().diagAppertainsToDecl(S, *this, D); 160} 161 162bool ParsedAttr::appliesToDecl(const Decl *D, 163 attr::SubjectMatchRule MatchRule) const { 164 return checkAttributeMatchRuleAppliesTo(D, MatchRule); 165} 166 167void ParsedAttr::getMatchRules( 168 const LangOptions &LangOpts, 169 SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules) 170 const { 171 return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts); 172} 173 174bool ParsedAttr::diagnoseLangOpts(Sema &S) const { 175 return getInfo().diagLangOpts(S, *this); 176} 177 178bool ParsedAttr::isTargetSpecificAttr() const { 179 return getInfo().IsTargetSpecific; 180} 181 182bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; } 183 184bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; } 185 186bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { 187 return getInfo().existsInTarget(Target); 188} 189 190bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; } 191 192bool ParsedAttr::isSupportedByPragmaAttribute() const { 193 return getInfo().IsSupportedByPragmaAttribute; 194} 195 196unsigned ParsedAttr::getSemanticSpelling() const { 197 return getInfo().spellingIndexToSemanticSpelling(*this); 198} 199 200bool 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