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"
220b57cec5SDimitry Andric #include <cassert>
230b57cec5SDimitry Andric #include <cstddef>
240b57cec5SDimitry Andric #include <utility>
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric using namespace clang;
270b57cec5SDimitry Andric
create(ASTContext & Ctx,SourceLocation Loc,IdentifierInfo * Ident)280b57cec5SDimitry Andric IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc,
290b57cec5SDimitry Andric IdentifierInfo *Ident) {
300b57cec5SDimitry Andric IdentifierLoc *Result = new (Ctx) IdentifierLoc;
310b57cec5SDimitry Andric Result->Loc = Loc;
320b57cec5SDimitry Andric Result->Ident = Ident;
330b57cec5SDimitry Andric return Result;
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric
allocated_size() const360b57cec5SDimitry Andric size_t ParsedAttr::allocated_size() const {
370b57cec5SDimitry Andric if (IsAvailability) return AttributeFactory::AvailabilityAllocSize;
380b57cec5SDimitry Andric else if (IsTypeTagForDatatype)
390b57cec5SDimitry Andric return AttributeFactory::TypeTagForDatatypeAllocSize;
400b57cec5SDimitry Andric else if (IsProperty)
410b57cec5SDimitry Andric return AttributeFactory::PropertyAllocSize;
420b57cec5SDimitry Andric else if (HasParsedType)
430b57cec5SDimitry Andric return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
440b57cec5SDimitry Andric detail::TypeTagForDatatypeData, ParsedType,
450b57cec5SDimitry Andric detail::PropertyData>(0, 0, 0, 1, 0);
460b57cec5SDimitry Andric return totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
470b57cec5SDimitry Andric detail::TypeTagForDatatypeData, ParsedType,
480b57cec5SDimitry Andric detail::PropertyData>(NumArgs, 0, 0, 0, 0);
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric
AttributeFactory()510b57cec5SDimitry Andric AttributeFactory::AttributeFactory() {
520b57cec5SDimitry Andric // Go ahead and configure all the inline capacity. This is just a memset.
530b57cec5SDimitry Andric FreeLists.resize(InlineFreeListsCapacity);
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric AttributeFactory::~AttributeFactory() = default;
560b57cec5SDimitry Andric
getFreeListIndexForSize(size_t size)570b57cec5SDimitry Andric static size_t getFreeListIndexForSize(size_t size) {
580b57cec5SDimitry Andric assert(size >= sizeof(ParsedAttr));
590b57cec5SDimitry Andric assert((size % sizeof(void*)) == 0);
600b57cec5SDimitry Andric return ((size - sizeof(ParsedAttr)) / sizeof(void *));
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric
allocate(size_t size)630b57cec5SDimitry Andric void *AttributeFactory::allocate(size_t size) {
640b57cec5SDimitry Andric // Check for a previously reclaimed attribute.
650b57cec5SDimitry Andric size_t index = getFreeListIndexForSize(size);
660b57cec5SDimitry Andric if (index < FreeLists.size() && !FreeLists[index].empty()) {
670b57cec5SDimitry Andric ParsedAttr *attr = FreeLists[index].back();
680b57cec5SDimitry Andric FreeLists[index].pop_back();
690b57cec5SDimitry Andric return attr;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric // Otherwise, allocate something new.
730b57cec5SDimitry Andric return Alloc.Allocate(size, alignof(AttributeFactory));
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric
deallocate(ParsedAttr * Attr)760b57cec5SDimitry Andric void AttributeFactory::deallocate(ParsedAttr *Attr) {
770b57cec5SDimitry Andric size_t size = Attr->allocated_size();
780b57cec5SDimitry Andric size_t freeListIndex = getFreeListIndexForSize(size);
790b57cec5SDimitry Andric
800b57cec5SDimitry Andric // Expand FreeLists to the appropriate size, if required.
810b57cec5SDimitry Andric if (freeListIndex >= FreeLists.size())
820b57cec5SDimitry Andric FreeLists.resize(freeListIndex + 1);
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric #ifndef NDEBUG
850b57cec5SDimitry Andric // In debug mode, zero out the attribute to help find memory overwriting.
860b57cec5SDimitry Andric memset(Attr, 0, size);
870b57cec5SDimitry Andric #endif
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric // Add 'Attr' to the appropriate free-list.
900b57cec5SDimitry Andric FreeLists[freeListIndex].push_back(Attr);
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric
reclaimPool(AttributePool & cur)930b57cec5SDimitry Andric void AttributeFactory::reclaimPool(AttributePool &cur) {
940b57cec5SDimitry Andric for (ParsedAttr *AL : cur.Attrs)
950b57cec5SDimitry Andric deallocate(AL);
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric
takePool(AttributePool & pool)980b57cec5SDimitry Andric void AttributePool::takePool(AttributePool &pool) {
990b57cec5SDimitry Andric Attrs.insert(Attrs.end(), pool.Attrs.begin(), pool.Attrs.end());
1000b57cec5SDimitry Andric pool.Attrs.clear();
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric
takeFrom(ParsedAttributesView & List,AttributePool & Pool)103*0fca6ea1SDimitry Andric void AttributePool::takeFrom(ParsedAttributesView &List, AttributePool &Pool) {
104*0fca6ea1SDimitry Andric assert(&Pool != this && "AttributePool can't take attributes from itself");
105*0fca6ea1SDimitry Andric llvm::for_each(List.AttrList, [&Pool](ParsedAttr *A) { Pool.remove(A); });
106*0fca6ea1SDimitry Andric Attrs.insert(Attrs.end(), List.AttrList.begin(), List.AttrList.end());
107*0fca6ea1SDimitry Andric }
108*0fca6ea1SDimitry Andric
1090b57cec5SDimitry Andric namespace {
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric #include "clang/Sema/AttrParsedAttrImpl.inc"
1120b57cec5SDimitry Andric
1130b57cec5SDimitry Andric } // namespace
1140b57cec5SDimitry Andric
get(const AttributeCommonInfo & A)1155ffd83dbSDimitry Andric const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
1165ffd83dbSDimitry Andric // If we have a ParsedAttrInfo for this ParsedAttr then return that.
117bdd1243dSDimitry Andric if ((size_t)A.getParsedKind() < std::size(AttrInfoMap))
1185ffd83dbSDimitry Andric return *AttrInfoMap[A.getParsedKind()];
1195ffd83dbSDimitry Andric
1205ffd83dbSDimitry Andric // If this is an ignored attribute then return an appropriate ParsedAttrInfo.
1215ffd83dbSDimitry Andric static const ParsedAttrInfo IgnoredParsedAttrInfo(
1225ffd83dbSDimitry Andric AttributeCommonInfo::IgnoredAttribute);
1235ffd83dbSDimitry Andric if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute)
1245ffd83dbSDimitry Andric return IgnoredParsedAttrInfo;
1255ffd83dbSDimitry Andric
12606c3fb27SDimitry Andric // Otherwise this may be an attribute defined by a plugin.
1275ffd83dbSDimitry Andric
1285ffd83dbSDimitry Andric // Search for a ParsedAttrInfo whose name and syntax match.
1295ffd83dbSDimitry Andric std::string FullName = A.getNormalizedFullName();
1305ffd83dbSDimitry Andric AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax();
1315ffd83dbSDimitry Andric if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword)
1325ffd83dbSDimitry Andric SyntaxUsed = AttributeCommonInfo::AS_Keyword;
1335ffd83dbSDimitry Andric
13406c3fb27SDimitry Andric for (auto &Ptr : getAttributePluginInstances())
13506c3fb27SDimitry Andric if (Ptr->hasSpelling(SyntaxUsed, FullName))
1365ffd83dbSDimitry Andric return *Ptr;
1375ffd83dbSDimitry Andric
1385ffd83dbSDimitry Andric // If we failed to find a match then return a default ParsedAttrInfo.
1395ffd83dbSDimitry Andric static const ParsedAttrInfo DefaultParsedAttrInfo(
1405ffd83dbSDimitry Andric AttributeCommonInfo::UnknownAttribute);
1415ffd83dbSDimitry Andric return DefaultParsedAttrInfo;
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric
getAllBuiltin()144349cc55cSDimitry Andric ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() {
145bdd1243dSDimitry Andric return llvm::ArrayRef(AttrInfoMap);
146349cc55cSDimitry Andric }
147349cc55cSDimitry Andric
getMinArgs() const1485ffd83dbSDimitry Andric unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
1490b57cec5SDimitry Andric
getMaxArgs() const1500b57cec5SDimitry Andric unsigned ParsedAttr::getMaxArgs() const {
1515ffd83dbSDimitry Andric return getMinArgs() + getInfo().OptArgs;
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric
getNumArgMembers() const15481ad6265SDimitry Andric unsigned ParsedAttr::getNumArgMembers() const {
15581ad6265SDimitry Andric return getInfo().NumArgMembers;
15681ad6265SDimitry Andric }
15781ad6265SDimitry Andric
hasCustomParsing() const1580b57cec5SDimitry Andric bool ParsedAttr::hasCustomParsing() const {
1595ffd83dbSDimitry Andric return getInfo().HasCustomParsing;
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric
diagnoseAppertainsTo(Sema & S,const Decl * D) const1620b57cec5SDimitry Andric bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
1635ffd83dbSDimitry Andric return getInfo().diagAppertainsToDecl(S, *this, D);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric
diagnoseAppertainsTo(Sema & S,const Stmt * St) const166fe6060f1SDimitry Andric bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const {
167fe6060f1SDimitry Andric return getInfo().diagAppertainsToStmt(S, *this, St);
168fe6060f1SDimitry Andric }
169fe6060f1SDimitry Andric
diagnoseMutualExclusion(Sema & S,const Decl * D) const170fe6060f1SDimitry Andric bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const {
171fe6060f1SDimitry Andric return getInfo().diagMutualExclusion(S, *this, D);
172fe6060f1SDimitry Andric }
173fe6060f1SDimitry Andric
appliesToDecl(const Decl * D,attr::SubjectMatchRule MatchRule) const1740b57cec5SDimitry Andric bool ParsedAttr::appliesToDecl(const Decl *D,
1750b57cec5SDimitry Andric attr::SubjectMatchRule MatchRule) const {
1760b57cec5SDimitry Andric return checkAttributeMatchRuleAppliesTo(D, MatchRule);
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric
getMatchRules(const LangOptions & LangOpts,SmallVectorImpl<std::pair<attr::SubjectMatchRule,bool>> & MatchRules) const1790b57cec5SDimitry 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
diagnoseLangOpts(Sema & S) const1860b57cec5SDimitry Andric bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
187349cc55cSDimitry Andric if (getInfo().acceptsLangOpts(S.getLangOpts()))
188349cc55cSDimitry Andric return true;
189349cc55cSDimitry Andric S.Diag(getLoc(), diag::warn_attribute_ignored) << *this;
190349cc55cSDimitry Andric return false;
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric
isTargetSpecificAttr() const1930b57cec5SDimitry Andric bool ParsedAttr::isTargetSpecificAttr() const {
1945ffd83dbSDimitry Andric return getInfo().IsTargetSpecific;
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric
isTypeAttr() const1975ffd83dbSDimitry Andric bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; }
1980b57cec5SDimitry Andric
isStmtAttr() const1995ffd83dbSDimitry Andric bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; }
2000b57cec5SDimitry Andric
existsInTarget(const TargetInfo & Target) const2010b57cec5SDimitry Andric bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {
2025f757f3fSDimitry Andric Kind K = getParsedKind();
2035f757f3fSDimitry Andric
2045f757f3fSDimitry Andric // If the attribute has a target-specific spelling, check that it exists.
2055f757f3fSDimitry Andric // Only call this if the attr is not ignored/unknown. For most targets, this
2065f757f3fSDimitry Andric // function just returns true.
2075f757f3fSDimitry Andric bool HasSpelling = K != IgnoredAttribute && K != UnknownAttribute &&
2085f757f3fSDimitry Andric K != NoSemaHandlerAttribute;
2095f757f3fSDimitry Andric bool TargetSpecificSpellingExists =
2105f757f3fSDimitry Andric !HasSpelling ||
2115f757f3fSDimitry Andric getInfo().spellingExistsInTarget(Target, getAttributeSpellingListIndex());
2125f757f3fSDimitry Andric
2135f757f3fSDimitry Andric return getInfo().existsInTarget(Target) && TargetSpecificSpellingExists;
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric
isKnownToGCC() const2165ffd83dbSDimitry Andric bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; }
2170b57cec5SDimitry Andric
isSupportedByPragmaAttribute() const2180b57cec5SDimitry Andric bool ParsedAttr::isSupportedByPragmaAttribute() const {
2195ffd83dbSDimitry Andric return getInfo().IsSupportedByPragmaAttribute;
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric
slidesFromDeclToDeclSpecLegacyBehavior() const22281ad6265SDimitry Andric bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {
22306c3fb27SDimitry Andric if (isRegularKeywordAttribute())
22406c3fb27SDimitry Andric // The appurtenance rules are applied strictly for all regular keyword
22506c3fb27SDimitry Andric // atributes.
22606c3fb27SDimitry Andric return false;
22706c3fb27SDimitry Andric
228*0fca6ea1SDimitry Andric assert(isStandardAttributeSyntax() || isAlignas());
22981ad6265SDimitry Andric
23081ad6265SDimitry Andric // We have historically allowed some type attributes with standard attribute
23181ad6265SDimitry Andric // syntax to slide to the decl-specifier-seq, so we have to keep supporting
23281ad6265SDimitry Andric // it. This property is consciously not defined as a flag in Attr.td because
23381ad6265SDimitry Andric // we don't want new attributes to specify it.
23481ad6265SDimitry Andric //
23581ad6265SDimitry Andric // Note: No new entries should be added to this list. Entries should be
23681ad6265SDimitry Andric // removed from this list after a suitable deprecation period, provided that
23781ad6265SDimitry Andric // there are no compatibility considerations with other compilers. If
23881ad6265SDimitry Andric // possible, we would like this list to go away entirely.
23981ad6265SDimitry Andric switch (getParsedKind()) {
24081ad6265SDimitry Andric case AT_AddressSpace:
24181ad6265SDimitry Andric case AT_OpenCLPrivateAddressSpace:
24281ad6265SDimitry Andric case AT_OpenCLGlobalAddressSpace:
24381ad6265SDimitry Andric case AT_OpenCLGlobalDeviceAddressSpace:
24481ad6265SDimitry Andric case AT_OpenCLGlobalHostAddressSpace:
24581ad6265SDimitry Andric case AT_OpenCLLocalAddressSpace:
24681ad6265SDimitry Andric case AT_OpenCLConstantAddressSpace:
24781ad6265SDimitry Andric case AT_OpenCLGenericAddressSpace:
24881ad6265SDimitry Andric case AT_NeonPolyVectorType:
24981ad6265SDimitry Andric case AT_NeonVectorType:
25081ad6265SDimitry Andric case AT_ArmMveStrictPolymorphism:
25181ad6265SDimitry Andric case AT_BTFTypeTag:
25281ad6265SDimitry Andric case AT_ObjCGC:
25381ad6265SDimitry Andric case AT_MatrixType:
25481ad6265SDimitry Andric return true;
25581ad6265SDimitry Andric default:
25681ad6265SDimitry Andric return false;
25781ad6265SDimitry Andric }
25881ad6265SDimitry Andric }
25981ad6265SDimitry Andric
acceptsExprPack() const26081ad6265SDimitry Andric bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
26181ad6265SDimitry Andric
getSemanticSpelling() const2620b57cec5SDimitry Andric unsigned ParsedAttr::getSemanticSpelling() const {
2635ffd83dbSDimitry Andric return getInfo().spellingIndexToSemanticSpelling(*this);
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric
hasVariadicArg() const2660b57cec5SDimitry Andric bool ParsedAttr::hasVariadicArg() const {
2670b57cec5SDimitry Andric // If the attribute has the maximum number of optional arguments, we will
2680b57cec5SDimitry Andric // claim that as being variadic. If we someday get an attribute that
2690b57cec5SDimitry Andric // legitimately bumps up against that maximum, we can use another bit to track
2700b57cec5SDimitry Andric // whether it's truly variadic or not.
2715ffd83dbSDimitry Andric return getInfo().OptArgs == 15;
2720b57cec5SDimitry Andric }
273fe6060f1SDimitry Andric
isParamExpr(size_t N) const27481ad6265SDimitry Andric bool ParsedAttr::isParamExpr(size_t N) const {
27581ad6265SDimitry Andric return getInfo().isParamExpr(N);
27681ad6265SDimitry Andric }
27781ad6265SDimitry Andric
handleAttrWithDelayedArgs(Sema & S,Decl * D) const27881ad6265SDimitry Andric void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const {
27981ad6265SDimitry Andric ::handleAttrWithDelayedArgs(S, D, *this);
28081ad6265SDimitry Andric }
28181ad6265SDimitry Andric
getNumAttributeArgs(const ParsedAttr & AL)282fe6060f1SDimitry Andric static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
283fe6060f1SDimitry Andric // FIXME: Include the type in the argument list.
284fe6060f1SDimitry Andric return AL.getNumArgs() + AL.hasParsedType();
285fe6060f1SDimitry Andric }
286fe6060f1SDimitry Andric
287fe6060f1SDimitry Andric template <typename Compare>
checkAttributeNumArgsImpl(Sema & S,const ParsedAttr & AL,unsigned Num,unsigned Diag,Compare Comp)288fe6060f1SDimitry Andric static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL,
289fe6060f1SDimitry Andric unsigned Num, unsigned Diag,
290fe6060f1SDimitry Andric Compare Comp) {
291fe6060f1SDimitry Andric if (Comp(getNumAttributeArgs(AL), Num)) {
292fe6060f1SDimitry Andric S.Diag(AL.getLoc(), Diag) << AL << Num;
293fe6060f1SDimitry Andric return false;
294fe6060f1SDimitry Andric }
295fe6060f1SDimitry Andric return true;
296fe6060f1SDimitry Andric }
297fe6060f1SDimitry Andric
checkExactlyNumArgs(Sema & S,unsigned Num) const298fe6060f1SDimitry Andric bool ParsedAttr::checkExactlyNumArgs(Sema &S, unsigned Num) const {
299fe6060f1SDimitry Andric return checkAttributeNumArgsImpl(S, *this, Num,
300fe6060f1SDimitry Andric diag::err_attribute_wrong_number_arguments,
301fe6060f1SDimitry Andric std::not_equal_to<unsigned>());
302fe6060f1SDimitry Andric }
checkAtLeastNumArgs(Sema & S,unsigned Num) const303fe6060f1SDimitry Andric bool ParsedAttr::checkAtLeastNumArgs(Sema &S, unsigned Num) const {
304fe6060f1SDimitry Andric return checkAttributeNumArgsImpl(S, *this, Num,
305fe6060f1SDimitry Andric diag::err_attribute_too_few_arguments,
306fe6060f1SDimitry Andric std::less<unsigned>());
307fe6060f1SDimitry Andric }
checkAtMostNumArgs(Sema & S,unsigned Num) const308fe6060f1SDimitry Andric bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const {
309fe6060f1SDimitry Andric return checkAttributeNumArgsImpl(S, *this, Num,
310fe6060f1SDimitry Andric diag::err_attribute_too_many_arguments,
311fe6060f1SDimitry Andric std::greater<unsigned>());
312fe6060f1SDimitry Andric }
31381ad6265SDimitry Andric
takeAndConcatenateAttrs(ParsedAttributes & First,ParsedAttributes & Second,ParsedAttributes & Result)31481ad6265SDimitry Andric void clang::takeAndConcatenateAttrs(ParsedAttributes &First,
31581ad6265SDimitry Andric ParsedAttributes &Second,
31681ad6265SDimitry Andric ParsedAttributes &Result) {
31781ad6265SDimitry Andric // Note that takeAllFrom() puts the attributes at the beginning of the list,
31881ad6265SDimitry Andric // so to obtain the correct ordering, we add `Second`, then `First`.
31981ad6265SDimitry Andric Result.takeAllFrom(Second);
32081ad6265SDimitry Andric Result.takeAllFrom(First);
32181ad6265SDimitry Andric if (First.Range.getBegin().isValid())
32281ad6265SDimitry Andric Result.Range.setBegin(First.Range.getBegin());
32381ad6265SDimitry Andric else
32481ad6265SDimitry Andric Result.Range.setBegin(Second.Range.getBegin());
32581ad6265SDimitry Andric if (Second.Range.getEnd().isValid())
32681ad6265SDimitry Andric Result.Range.setEnd(Second.Range.getEnd());
32781ad6265SDimitry Andric else
32881ad6265SDimitry Andric Result.Range.setEnd(First.Range.getEnd());
32981ad6265SDimitry Andric }
330