Path: blob/main/contrib/llvm-project/clang/lib/Sema/ParsedAttr.cpp
35233 views
//======- ParsedAttr.cpp --------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the ParsedAttr class implementation9//10//===----------------------------------------------------------------------===//1112#include "clang/Sema/ParsedAttr.h"13#include "clang/AST/ASTContext.h"14#include "clang/Basic/AttrSubjectMatchRules.h"15#include "clang/Basic/IdentifierTable.h"16#include "clang/Basic/TargetInfo.h"17#include "clang/Sema/SemaInternal.h"18#include "llvm/ADT/SmallString.h"19#include "llvm/ADT/SmallVector.h"20#include "llvm/ADT/StringRef.h"21#include <cassert>22#include <cstddef>23#include <utility>2425using namespace clang;2627IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc,28IdentifierInfo *Ident) {29IdentifierLoc *Result = new (Ctx) IdentifierLoc;30Result->Loc = Loc;31Result->Ident = Ident;32return Result;33}3435size_t ParsedAttr::allocated_size() const {36if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;37else if (IsTypeTagForDatatype)38return AttributeFactory::TypeTagForDatatypeAllocSize;39else if (IsProperty)40return AttributeFactory::PropertyAllocSize;41else if (HasParsedType)42return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,43detail::TypeTagForDatatypeData, ParsedType,44detail::PropertyData>(0, 0, 0, 1, 0);45return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,46detail::TypeTagForDatatypeData, ParsedType,47detail::PropertyData>(NumArgs, 0, 0, 0, 0);48}4950AttributeFactory::AttributeFactory() {51// Go ahead and configure all the inline capacity. This is just a memset.52FreeLists.resize(InlineFreeListsCapacity);53}54AttributeFactory::~AttributeFactory() = default;5556static size_t getFreeListIndexForSize(size_t size) {57assert(size >= sizeof(ParsedAttr));58assert((size % sizeof(void*)) == 0);59return ((size - sizeof(ParsedAttr)) / sizeof(void *));60}6162void *AttributeFactory::allocate(size_t size) {63// Check for a previously reclaimed attribute.64size_t index = getFreeListIndexForSize(size);65if (index < FreeLists.size() && !FreeLists[index].empty()) {66ParsedAttr *attr = FreeLists[index].back();67FreeLists[index].pop_back();68return attr;69}7071// Otherwise, allocate something new.72return Alloc.Allocate(size, alignof(AttributeFactory));73}7475void AttributeFactory::deallocate(ParsedAttr *Attr) {76size_t size = Attr->allocated_size();77size_t freeListIndex = getFreeListIndexForSize(size);7879// Expand FreeLists to the appropriate size, if required.80if (freeListIndex >= FreeLists.size())81FreeLists.resize(freeListIndex + 1);8283#ifndef NDEBUG84// In debug mode, zero out the attribute to help find memory overwriting.85memset(Attr, 0, size);86#endif8788// Add 'Attr' to the appropriate free-list.89FreeLists[freeListIndex].push_back(Attr);90}9192void AttributeFactory::reclaimPool(AttributePool &cur) {93for (ParsedAttr *AL : cur.Attrs)94deallocate(AL);95}9697void AttributePool::takePool(AttributePool &pool) {98Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end());99pool.Attrs.clear();100}101102void AttributePool::takeFrom(ParsedAttributesView &List, AttributePool &Pool) {103assert(&Pool != this && "AttributePool can't take attributes from itself");104llvm::for_each(List.AttrList, [&Pool](ParsedAttr *A) { Pool.remove(A); });105Attrs.insert(Attrs.end(), List.AttrList.begin(), List.AttrList.end());106}107108namespace {109110#include "clang/Sema/AttrParsedAttrImpl.inc"111112} // namespace113114const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {115// If we have a ParsedAttrInfo for this ParsedAttr then return that.116if ((size_t)A.getParsedKind() < std::size(AttrInfoMap))117return *AttrInfoMap[A.getParsedKind()];118119// If this is an ignored attribute then return an appropriate ParsedAttrInfo.120static const ParsedAttrInfo IgnoredParsedAttrInfo(121AttributeCommonInfo::IgnoredAttribute);122if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute)123return IgnoredParsedAttrInfo;124125// Otherwise this may be an attribute defined by a plugin.126127// Search for a ParsedAttrInfo whose name and syntax match.128std::string FullName = A.getNormalizedFullName();129AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax();130if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword)131SyntaxUsed = AttributeCommonInfo::AS_Keyword;132133for (auto &Ptr : getAttributePluginInstances())134if (Ptr->hasSpelling(SyntaxUsed, FullName))135return *Ptr;136137// If we failed to find a match then return a default ParsedAttrInfo.138static const ParsedAttrInfo DefaultParsedAttrInfo(139AttributeCommonInfo::UnknownAttribute);140return DefaultParsedAttrInfo;141}142143ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() {144return llvm::ArrayRef(AttrInfoMap);145}146147unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }148149unsigned ParsedAttr::getMaxArgs() const {150return getMinArgs() + getInfo().OptArgs;151}152153unsigned ParsedAttr::getNumArgMembers() const {154return getInfo().NumArgMembers;155}156157bool ParsedAttr::hasCustomParsing() const {158return getInfo().HasCustomParsing;159}160161bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {162return getInfo().diagAppertainsToDecl(S, *this, D);163}164165bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const {166return getInfo().diagAppertainsToStmt(S, *this, St);167}168169bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const {170return getInfo().diagMutualExclusion(S, *this, D);171}172173bool ParsedAttr::appliesToDecl(const Decl *D,174attr::SubjectMatchRule MatchRule) const {175return checkAttributeMatchRuleAppliesTo(D, MatchRule);176}177178void ParsedAttr::getMatchRules(179const LangOptions &LangOpts,180SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)181const {182return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts);183}184185bool ParsedAttr::diagnoseLangOpts(Sema &S) const {186if (getInfo().acceptsLangOpts(S.getLangOpts()))187return true;188S.Diag(getLoc(), diag::warn_attribute_ignored) << *this;189return false;190}191192bool ParsedAttr::isTargetSpecificAttr() const {193return getInfo().IsTargetSpecific;194}195196bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; }197198bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; }199200bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {201Kind K = getParsedKind();202203// If the attribute has a target-specific spelling, check that it exists.204// Only call this if the attr is not ignored/unknown. For most targets, this205// function just returns true.206bool HasSpelling = K != IgnoredAttribute && K != UnknownAttribute &&207K != NoSemaHandlerAttribute;208bool TargetSpecificSpellingExists =209!HasSpelling ||210getInfo().spellingExistsInTarget(Target, getAttributeSpellingListIndex());211212return getInfo().existsInTarget(Target) && TargetSpecificSpellingExists;213}214215bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; }216217bool ParsedAttr::isSupportedByPragmaAttribute() const {218return getInfo().IsSupportedByPragmaAttribute;219}220221bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {222if (isRegularKeywordAttribute())223// The appurtenance rules are applied strictly for all regular keyword224// atributes.225return false;226227assert(isStandardAttributeSyntax() || isAlignas());228229// We have historically allowed some type attributes with standard attribute230// syntax to slide to the decl-specifier-seq, so we have to keep supporting231// it. This property is consciously not defined as a flag in Attr.td because232// we don't want new attributes to specify it.233//234// Note: No new entries should be added to this list. Entries should be235// removed from this list after a suitable deprecation period, provided that236// there are no compatibility considerations with other compilers. If237// possible, we would like this list to go away entirely.238switch (getParsedKind()) {239case AT_AddressSpace:240case AT_OpenCLPrivateAddressSpace:241case AT_OpenCLGlobalAddressSpace:242case AT_OpenCLGlobalDeviceAddressSpace:243case AT_OpenCLGlobalHostAddressSpace:244case AT_OpenCLLocalAddressSpace:245case AT_OpenCLConstantAddressSpace:246case AT_OpenCLGenericAddressSpace:247case AT_NeonPolyVectorType:248case AT_NeonVectorType:249case AT_ArmMveStrictPolymorphism:250case AT_BTFTypeTag:251case AT_ObjCGC:252case AT_MatrixType:253return true;254default:255return false;256}257}258259bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }260261unsigned ParsedAttr::getSemanticSpelling() const {262return getInfo().spellingIndexToSemanticSpelling(*this);263}264265bool ParsedAttr::hasVariadicArg() const {266// If the attribute has the maximum number of optional arguments, we will267// claim that as being variadic. If we someday get an attribute that268// legitimately bumps up against that maximum, we can use another bit to track269// whether it's truly variadic or not.270return getInfo().OptArgs == 15;271}272273bool ParsedAttr::isParamExpr(size_t N) const {274return getInfo().isParamExpr(N);275}276277void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const {278::handleAttrWithDelayedArgs(S, D, *this);279}280281static unsigned getNumAttributeArgs(const ParsedAttr &AL) {282// FIXME: Include the type in the argument list.283return AL.getNumArgs() + AL.hasParsedType();284}285286template <typename Compare>287static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL,288unsigned Num, unsigned Diag,289Compare Comp) {290if (Comp(getNumAttributeArgs(AL), Num)) {291S.Diag(AL.getLoc(), Diag) << AL << Num;292return false;293}294return true;295}296297bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const {298return checkAttributeNumArgsImpl(S, *this, Num,299diag::err_attribute_wrong_number_arguments,300std::not_equal_to<unsigned>());301}302bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const {303return checkAttributeNumArgsImpl(S, *this, Num,304diag::err_attribute_too_few_arguments,305std::less<unsigned>());306}307bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const {308return checkAttributeNumArgsImpl(S, *this, Num,309diag::err_attribute_too_many_arguments,310std::greater<unsigned>());311}312313void clang::takeAndConcatenateAttrs(ParsedAttributes &First,314ParsedAttributes &Second,315ParsedAttributes &Result) {316// Note that takeAllFrom() puts the attributes at the beginning of the list,317// so to obtain the correct ordering, we add `Second`, then `First`.318Result.takeAllFrom(Second);319Result.takeAllFrom(First);320if (First.Range.getBegin().isValid())321Result.Range.setBegin(First.Range.getBegin());322else323Result.Range.setBegin(Second.Range.getBegin());324if (Second.Range.getEnd().isValid())325Result.Range.setEnd(Second.Range.getEnd());326else327Result.Range.setEnd(First.Range.getEnd());328}329330331