10b57cec5SDimitry Andric //======- ParsedAttr.cpp --------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines the ParsedAttr class implementation 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "clang/Sema/ParsedAttr.h" 140b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 150b57cec5SDimitry Andric #include "clang/Basic/AttrSubjectMatchRules.h" 160b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h" 170b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h" 180b57cec5SDimitry Andric #include "clang/Sema/SemaInternal.h" 190b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 210b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 225ffd83dbSDimitry Andric #include "llvm/Support/ManagedStatic.h" 230b57cec5SDimitry Andric #include <cassert> 240b57cec5SDimitry Andric #include <cstddef> 250b57cec5SDimitry Andric #include <utility> 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric using namespace clang; 280b57cec5SDimitry Andric 295ffd83dbSDimitry Andric LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry) 305ffd83dbSDimitry Andric 310b57cec5SDimitry Andric IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc, 320b57cec5SDimitry Andric IdentifierInfo *Ident) { 330b57cec5SDimitry Andric IdentifierLoc *Result = new (Ctx) IdentifierLoc; 340b57cec5SDimitry Andric Result->Loc = Loc; 350b57cec5SDimitry Andric Result->Ident = Ident; 360b57cec5SDimitry Andric return Result; 370b57cec5SDimitry Andric } 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric size_t ParsedAttr::allocated_size() const { 400b57cec5SDimitry Andric if (IsAvailability) return AttributeFactory::AvailabilityAllocSize; 410b57cec5SDimitry Andric else if (IsTypeTagForDatatype) 420b57cec5SDimitry Andric return AttributeFactory::TypeTagForDatatypeAllocSize; 430b57cec5SDimitry Andric else if (IsProperty) 440b57cec5SDimitry Andric return AttributeFactory::PropertyAllocSize; 450b57cec5SDimitry Andric else if (HasParsedType) 460b57cec5SDimitry Andric return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, 470b57cec5SDimitry Andric detail::TypeTagForDatatypeData, ParsedType, 480b57cec5SDimitry Andric detail::PropertyData>(0, 0, 0, 1, 0); 490b57cec5SDimitry Andric return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData, 500b57cec5SDimitry Andric detail::TypeTagForDatatypeData, ParsedType, 510b57cec5SDimitry Andric detail::PropertyData>(NumArgs, 0, 0, 0, 0); 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric AttributeFactory::AttributeFactory() { 550b57cec5SDimitry Andric // Go ahead and configure all the inline capacity. This is just a memset. 560b57cec5SDimitry Andric FreeLists.resize(InlineFreeListsCapacity); 570b57cec5SDimitry Andric } 580b57cec5SDimitry Andric AttributeFactory::~AttributeFactory() = default; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric static size_t getFreeListIndexForSize(size_t size) { 610b57cec5SDimitry Andric assert(size >= sizeof(ParsedAttr)); 620b57cec5SDimitry Andric assert((size % sizeof(void*)) == 0); 630b57cec5SDimitry Andric return ((size - sizeof(ParsedAttr)) / sizeof(void *)); 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric void *AttributeFactory::allocate(size_t size) { 670b57cec5SDimitry Andric // Check for a previously reclaimed attribute. 680b57cec5SDimitry Andric size_t index = getFreeListIndexForSize(size); 690b57cec5SDimitry Andric if (index < FreeLists.size() && !FreeLists[index].empty()) { 700b57cec5SDimitry Andric ParsedAttr *attr = FreeLists[index].back(); 710b57cec5SDimitry Andric FreeLists[index].pop_back(); 720b57cec5SDimitry Andric return attr; 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric // Otherwise, allocate something new. 760b57cec5SDimitry Andric return Alloc.Allocate(size, alignof(AttributeFactory)); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric void AttributeFactory::deallocate(ParsedAttr *Attr) { 800b57cec5SDimitry Andric size_t size = Attr->allocated_size(); 810b57cec5SDimitry Andric size_t freeListIndex = getFreeListIndexForSize(size); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric // Expand FreeLists to the appropriate size, if required. 840b57cec5SDimitry Andric if (freeListIndex >= FreeLists.size()) 850b57cec5SDimitry Andric FreeLists.resize(freeListIndex + 1); 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric #ifndef NDEBUG 880b57cec5SDimitry Andric // In debug mode, zero out the attribute to help find memory overwriting. 890b57cec5SDimitry Andric memset(Attr, 0, size); 900b57cec5SDimitry Andric #endif 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric // Add 'Attr' to the appropriate free-list. 930b57cec5SDimitry Andric FreeLists[freeListIndex].push_back(Attr); 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric void AttributeFactory::reclaimPool(AttributePool &cur) { 970b57cec5SDimitry Andric for (ParsedAttr *AL : cur.Attrs) 980b57cec5SDimitry Andric deallocate(AL); 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric void AttributePool::takePool(AttributePool &pool) { 1020b57cec5SDimitry Andric Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end()); 1030b57cec5SDimitry Andric pool.Attrs.clear(); 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric namespace { 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric #include "clang/Sema/AttrParsedAttrImpl.inc" 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric } // namespace 1110b57cec5SDimitry Andric 1125ffd83dbSDimitry Andric const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { 1135ffd83dbSDimitry Andric // If we have a ParsedAttrInfo for this ParsedAttr then return that. 1145ffd83dbSDimitry Andric if ((size_t)A.getParsedKind() < llvm::array_lengthof(AttrInfoMap)) 1155ffd83dbSDimitry Andric return *AttrInfoMap[A.getParsedKind()]; 1165ffd83dbSDimitry Andric 1175ffd83dbSDimitry Andric // If this is an ignored attribute then return an appropriate ParsedAttrInfo. 1185ffd83dbSDimitry Andric static const ParsedAttrInfo IgnoredParsedAttrInfo( 1195ffd83dbSDimitry Andric AttributeCommonInfo::IgnoredAttribute); 1205ffd83dbSDimitry Andric if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute) 1215ffd83dbSDimitry Andric return IgnoredParsedAttrInfo; 1225ffd83dbSDimitry Andric 1235ffd83dbSDimitry Andric // Otherwise this may be an attribute defined by a plugin. First instantiate 1245ffd83dbSDimitry Andric // all plugin attributes if we haven't already done so. 1255ffd83dbSDimitry Andric static llvm::ManagedStatic<std::list<std::unique_ptr<ParsedAttrInfo>>> 1265ffd83dbSDimitry Andric PluginAttrInstances; 1275ffd83dbSDimitry Andric if (PluginAttrInstances->empty()) 1285ffd83dbSDimitry Andric for (auto It : ParsedAttrInfoRegistry::entries()) 1295ffd83dbSDimitry Andric PluginAttrInstances->emplace_back(It.instantiate()); 1305ffd83dbSDimitry Andric 1315ffd83dbSDimitry Andric // Search for a ParsedAttrInfo whose name and syntax match. 1325ffd83dbSDimitry Andric std::string FullName = A.getNormalizedFullName(); 1335ffd83dbSDimitry Andric AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax(); 1345ffd83dbSDimitry Andric if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword) 1355ffd83dbSDimitry Andric SyntaxUsed = AttributeCommonInfo::AS_Keyword; 1365ffd83dbSDimitry Andric 1375ffd83dbSDimitry Andric for (auto &Ptr : *PluginAttrInstances) 1385ffd83dbSDimitry Andric for (auto &S : Ptr->Spellings) 1395ffd83dbSDimitry Andric if (S.Syntax == SyntaxUsed && S.NormalizedFullName == FullName) 1405ffd83dbSDimitry Andric return *Ptr; 1415ffd83dbSDimitry Andric 1425ffd83dbSDimitry Andric // If we failed to find a match then return a default ParsedAttrInfo. 1435ffd83dbSDimitry Andric static const ParsedAttrInfo DefaultParsedAttrInfo( 1445ffd83dbSDimitry Andric AttributeCommonInfo::UnknownAttribute); 1455ffd83dbSDimitry Andric return DefaultParsedAttrInfo; 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1485ffd83dbSDimitry Andric unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric unsigned ParsedAttr::getMaxArgs() const { 1515ffd83dbSDimitry Andric return getMinArgs() + getInfo().OptArgs; 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric bool ParsedAttr::hasCustomParsing() const { 1555ffd83dbSDimitry Andric return getInfo().HasCustomParsing; 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 1595ffd83dbSDimitry Andric return getInfo().diagAppertainsToDecl(S, *this, D); 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 162*fe6060f1SDimitry Andric bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const { 163*fe6060f1SDimitry Andric return getInfo().diagAppertainsToStmt(S, *this, St); 164*fe6060f1SDimitry Andric } 165*fe6060f1SDimitry Andric 166*fe6060f1SDimitry Andric bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const { 167*fe6060f1SDimitry Andric return getInfo().diagMutualExclusion(S, *this, D); 168*fe6060f1SDimitry Andric } 169*fe6060f1SDimitry Andric 1700b57cec5SDimitry Andric bool ParsedAttr::appliesToDecl(const Decl *D, 1710b57cec5SDimitry Andric attr::SubjectMatchRule MatchRule) const { 1720b57cec5SDimitry Andric return checkAttributeMatchRuleAppliesTo(D, MatchRule); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric void ParsedAttr::getMatchRules( 1760b57cec5SDimitry Andric const LangOptions &LangOpts, 1770b57cec5SDimitry Andric SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules) 1780b57cec5SDimitry Andric const { 1795ffd83dbSDimitry Andric return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric bool ParsedAttr::diagnoseLangOpts(Sema &S) const { 1835ffd83dbSDimitry Andric return getInfo().diagLangOpts(S, *this); 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric bool ParsedAttr::isTargetSpecificAttr() const { 1875ffd83dbSDimitry Andric return getInfo().IsTargetSpecific; 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1905ffd83dbSDimitry Andric bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; } 1910b57cec5SDimitry Andric 1925ffd83dbSDimitry Andric bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; } 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { 1955ffd83dbSDimitry Andric return getInfo().existsInTarget(Target); 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 1985ffd83dbSDimitry Andric bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; } 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric bool ParsedAttr::isSupportedByPragmaAttribute() const { 2015ffd83dbSDimitry Andric return getInfo().IsSupportedByPragmaAttribute; 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric unsigned ParsedAttr::getSemanticSpelling() const { 2055ffd83dbSDimitry Andric return getInfo().spellingIndexToSemanticSpelling(*this); 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric bool ParsedAttr::hasVariadicArg() const { 2090b57cec5SDimitry Andric // If the attribute has the maximum number of optional arguments, we will 2100b57cec5SDimitry Andric // claim that as being variadic. If we someday get an attribute that 2110b57cec5SDimitry Andric // legitimately bumps up against that maximum, we can use another bit to track 2120b57cec5SDimitry Andric // whether it's truly variadic or not. 2135ffd83dbSDimitry Andric return getInfo().OptArgs == 15; 2140b57cec5SDimitry Andric } 215*fe6060f1SDimitry Andric 216*fe6060f1SDimitry Andric static unsigned getNumAttributeArgs(const ParsedAttr &AL) { 217*fe6060f1SDimitry Andric // FIXME: Include the type in the argument list. 218*fe6060f1SDimitry Andric return AL.getNumArgs() + AL.hasParsedType(); 219*fe6060f1SDimitry Andric } 220*fe6060f1SDimitry Andric 221*fe6060f1SDimitry Andric template <typename Compare> 222*fe6060f1SDimitry Andric static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, 223*fe6060f1SDimitry Andric unsigned Num, unsigned Diag, 224*fe6060f1SDimitry Andric Compare Comp) { 225*fe6060f1SDimitry Andric if (Comp(getNumAttributeArgs(AL), Num)) { 226*fe6060f1SDimitry Andric S.Diag(AL.getLoc(), Diag) << AL << Num; 227*fe6060f1SDimitry Andric return false; 228*fe6060f1SDimitry Andric } 229*fe6060f1SDimitry Andric return true; 230*fe6060f1SDimitry Andric } 231*fe6060f1SDimitry Andric 232*fe6060f1SDimitry Andric bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const { 233*fe6060f1SDimitry Andric return checkAttributeNumArgsImpl(S, *this, Num, 234*fe6060f1SDimitry Andric diag::err_attribute_wrong_number_arguments, 235*fe6060f1SDimitry Andric std::not_equal_to<unsigned>()); 236*fe6060f1SDimitry Andric } 237*fe6060f1SDimitry Andric bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const { 238*fe6060f1SDimitry Andric return checkAttributeNumArgsImpl(S, *this, Num, 239*fe6060f1SDimitry Andric diag::err_attribute_too_few_arguments, 240*fe6060f1SDimitry Andric std::less<unsigned>()); 241*fe6060f1SDimitry Andric } 242*fe6060f1SDimitry Andric bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const { 243*fe6060f1SDimitry Andric return checkAttributeNumArgsImpl(S, *this, Num, 244*fe6060f1SDimitry Andric diag::err_attribute_too_many_arguments, 245*fe6060f1SDimitry Andric std::greater<unsigned>()); 246*fe6060f1SDimitry Andric } 247