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" 22*5ffd83dbSDimitry 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 29*5ffd83dbSDimitry Andric LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry) 30*5ffd83dbSDimitry 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 112*5ffd83dbSDimitry Andric const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { 113*5ffd83dbSDimitry Andric // If we have a ParsedAttrInfo for this ParsedAttr then return that. 114*5ffd83dbSDimitry Andric if ((size_t)A.getParsedKind() < llvm::array_lengthof(AttrInfoMap)) 115*5ffd83dbSDimitry Andric return *AttrInfoMap[A.getParsedKind()]; 116*5ffd83dbSDimitry Andric 117*5ffd83dbSDimitry Andric // If this is an ignored attribute then return an appropriate ParsedAttrInfo. 118*5ffd83dbSDimitry Andric static const ParsedAttrInfo IgnoredParsedAttrInfo( 119*5ffd83dbSDimitry Andric AttributeCommonInfo::IgnoredAttribute); 120*5ffd83dbSDimitry Andric if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute) 121*5ffd83dbSDimitry Andric return IgnoredParsedAttrInfo; 122*5ffd83dbSDimitry Andric 123*5ffd83dbSDimitry Andric // Otherwise this may be an attribute defined by a plugin. First instantiate 124*5ffd83dbSDimitry Andric // all plugin attributes if we haven't already done so. 125*5ffd83dbSDimitry Andric static llvm::ManagedStatic<std::list<std::unique_ptr<ParsedAttrInfo>>> 126*5ffd83dbSDimitry Andric PluginAttrInstances; 127*5ffd83dbSDimitry Andric if (PluginAttrInstances->empty()) 128*5ffd83dbSDimitry Andric for (auto It : ParsedAttrInfoRegistry::entries()) 129*5ffd83dbSDimitry Andric PluginAttrInstances->emplace_back(It.instantiate()); 130*5ffd83dbSDimitry Andric 131*5ffd83dbSDimitry Andric // Search for a ParsedAttrInfo whose name and syntax match. 132*5ffd83dbSDimitry Andric std::string FullName = A.getNormalizedFullName(); 133*5ffd83dbSDimitry Andric AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax(); 134*5ffd83dbSDimitry Andric if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword) 135*5ffd83dbSDimitry Andric SyntaxUsed = AttributeCommonInfo::AS_Keyword; 136*5ffd83dbSDimitry Andric 137*5ffd83dbSDimitry Andric for (auto &Ptr : *PluginAttrInstances) 138*5ffd83dbSDimitry Andric for (auto &S : Ptr->Spellings) 139*5ffd83dbSDimitry Andric if (S.Syntax == SyntaxUsed && S.NormalizedFullName == FullName) 140*5ffd83dbSDimitry Andric return *Ptr; 141*5ffd83dbSDimitry Andric 142*5ffd83dbSDimitry Andric // If we failed to find a match then return a default ParsedAttrInfo. 143*5ffd83dbSDimitry Andric static const ParsedAttrInfo DefaultParsedAttrInfo( 144*5ffd83dbSDimitry Andric AttributeCommonInfo::UnknownAttribute); 145*5ffd83dbSDimitry Andric return DefaultParsedAttrInfo; 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 148*5ffd83dbSDimitry Andric unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric unsigned ParsedAttr::getMaxArgs() const { 151*5ffd83dbSDimitry Andric return getMinArgs() + getInfo().OptArgs; 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric bool ParsedAttr::hasCustomParsing() const { 155*5ffd83dbSDimitry Andric return getInfo().HasCustomParsing; 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 159*5ffd83dbSDimitry Andric return getInfo().diagAppertainsToDecl(S, *this, D); 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric bool ParsedAttr::appliesToDecl(const Decl *D, 1630b57cec5SDimitry Andric attr::SubjectMatchRule MatchRule) const { 1640b57cec5SDimitry Andric return checkAttributeMatchRuleAppliesTo(D, MatchRule); 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric void ParsedAttr::getMatchRules( 1680b57cec5SDimitry Andric const LangOptions &LangOpts, 1690b57cec5SDimitry Andric SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules) 1700b57cec5SDimitry Andric const { 171*5ffd83dbSDimitry Andric return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric bool ParsedAttr::diagnoseLangOpts(Sema &S) const { 175*5ffd83dbSDimitry Andric return getInfo().diagLangOpts(S, *this); 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric bool ParsedAttr::isTargetSpecificAttr() const { 179*5ffd83dbSDimitry Andric return getInfo().IsTargetSpecific; 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 182*5ffd83dbSDimitry Andric bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; } 1830b57cec5SDimitry Andric 184*5ffd83dbSDimitry Andric bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { 187*5ffd83dbSDimitry Andric return getInfo().existsInTarget(Target); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 190*5ffd83dbSDimitry Andric bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; } 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric bool ParsedAttr::isSupportedByPragmaAttribute() const { 193*5ffd83dbSDimitry Andric return getInfo().IsSupportedByPragmaAttribute; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric unsigned ParsedAttr::getSemanticSpelling() const { 197*5ffd83dbSDimitry Andric return getInfo().spellingIndexToSemanticSpelling(*this); 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric bool ParsedAttr::hasVariadicArg() const { 2010b57cec5SDimitry Andric // If the attribute has the maximum number of optional arguments, we will 2020b57cec5SDimitry Andric // claim that as being variadic. If we someday get an attribute that 2030b57cec5SDimitry Andric // legitimately bumps up against that maximum, we can use another bit to track 2040b57cec5SDimitry Andric // whether it's truly variadic or not. 205*5ffd83dbSDimitry Andric return getInfo().OptArgs == 15; 2060b57cec5SDimitry Andric } 207