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 148*349cc55cSDimitry Andric ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() { 149*349cc55cSDimitry Andric return llvm::makeArrayRef(AttrInfoMap); 150*349cc55cSDimitry Andric } 151*349cc55cSDimitry Andric 1525ffd83dbSDimitry Andric unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric unsigned ParsedAttr::getMaxArgs() const { 1555ffd83dbSDimitry Andric return getMinArgs() + getInfo().OptArgs; 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric bool ParsedAttr::hasCustomParsing() const { 1595ffd83dbSDimitry Andric return getInfo().HasCustomParsing; 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { 1635ffd83dbSDimitry Andric return getInfo().diagAppertainsToDecl(S, *this, D); 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric 166fe6060f1SDimitry Andric bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const { 167fe6060f1SDimitry Andric return getInfo().diagAppertainsToStmt(S, *this, St); 168fe6060f1SDimitry Andric } 169fe6060f1SDimitry Andric 170fe6060f1SDimitry Andric bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const { 171fe6060f1SDimitry Andric return getInfo().diagMutualExclusion(S, *this, D); 172fe6060f1SDimitry Andric } 173fe6060f1SDimitry Andric 1740b57cec5SDimitry Andric bool ParsedAttr::appliesToDecl(const Decl *D, 1750b57cec5SDimitry Andric attr::SubjectMatchRule MatchRule) const { 1760b57cec5SDimitry Andric return checkAttributeMatchRuleAppliesTo(D, MatchRule); 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric void ParsedAttr::getMatchRules( 1800b57cec5SDimitry Andric const LangOptions &LangOpts, 1810b57cec5SDimitry Andric SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules) 1820b57cec5SDimitry Andric const { 1835ffd83dbSDimitry Andric return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts); 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric bool ParsedAttr::diagnoseLangOpts(Sema &S) const { 187*349cc55cSDimitry Andric if (getInfo().acceptsLangOpts(S.getLangOpts())) 188*349cc55cSDimitry Andric return true; 189*349cc55cSDimitry Andric S.Diag(getLoc(), diag::warn_attribute_ignored) << *this; 190*349cc55cSDimitry Andric return false; 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric bool ParsedAttr::isTargetSpecificAttr() const { 1945ffd83dbSDimitry Andric return getInfo().IsTargetSpecific; 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric 1975ffd83dbSDimitry Andric bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; } 1980b57cec5SDimitry Andric 1995ffd83dbSDimitry Andric bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; } 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { 2025ffd83dbSDimitry Andric return getInfo().existsInTarget(Target); 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric 2055ffd83dbSDimitry Andric bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; } 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric bool ParsedAttr::isSupportedByPragmaAttribute() const { 2085ffd83dbSDimitry Andric return getInfo().IsSupportedByPragmaAttribute; 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric unsigned ParsedAttr::getSemanticSpelling() const { 2125ffd83dbSDimitry Andric return getInfo().spellingIndexToSemanticSpelling(*this); 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric bool ParsedAttr::hasVariadicArg() const { 2160b57cec5SDimitry Andric // If the attribute has the maximum number of optional arguments, we will 2170b57cec5SDimitry Andric // claim that as being variadic. If we someday get an attribute that 2180b57cec5SDimitry Andric // legitimately bumps up against that maximum, we can use another bit to track 2190b57cec5SDimitry Andric // whether it's truly variadic or not. 2205ffd83dbSDimitry Andric return getInfo().OptArgs == 15; 2210b57cec5SDimitry Andric } 222fe6060f1SDimitry Andric 223fe6060f1SDimitry Andric static unsigned getNumAttributeArgs(const ParsedAttr &AL) { 224fe6060f1SDimitry Andric // FIXME: Include the type in the argument list. 225fe6060f1SDimitry Andric return AL.getNumArgs() + AL.hasParsedType(); 226fe6060f1SDimitry Andric } 227fe6060f1SDimitry Andric 228fe6060f1SDimitry Andric template <typename Compare> 229fe6060f1SDimitry Andric static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL, 230fe6060f1SDimitry Andric unsigned Num, unsigned Diag, 231fe6060f1SDimitry Andric Compare Comp) { 232fe6060f1SDimitry Andric if (Comp(getNumAttributeArgs(AL), Num)) { 233fe6060f1SDimitry Andric S.Diag(AL.getLoc(), Diag) << AL << Num; 234fe6060f1SDimitry Andric return false; 235fe6060f1SDimitry Andric } 236fe6060f1SDimitry Andric return true; 237fe6060f1SDimitry Andric } 238fe6060f1SDimitry Andric 239fe6060f1SDimitry Andric bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const { 240fe6060f1SDimitry Andric return checkAttributeNumArgsImpl(S, *this, Num, 241fe6060f1SDimitry Andric diag::err_attribute_wrong_number_arguments, 242fe6060f1SDimitry Andric std::not_equal_to<unsigned>()); 243fe6060f1SDimitry Andric } 244fe6060f1SDimitry Andric bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const { 245fe6060f1SDimitry Andric return checkAttributeNumArgsImpl(S, *this, Num, 246fe6060f1SDimitry Andric diag::err_attribute_too_few_arguments, 247fe6060f1SDimitry Andric std::less<unsigned>()); 248fe6060f1SDimitry Andric } 249fe6060f1SDimitry Andric bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const { 250fe6060f1SDimitry Andric return checkAttributeNumArgsImpl(S, *this, Num, 251fe6060f1SDimitry Andric diag::err_attribute_too_many_arguments, 252fe6060f1SDimitry Andric std::greater<unsigned>()); 253fe6060f1SDimitry Andric } 254