Skip to content

Commit b88d4ce

Browse files
Sirraideyuxuanchen1997Doug Wyatt
authored andcommitted
[Clang] Bugfixes and improved support for AttributedTypes in lambdas (llvm#85325)
This fixes a crash when we attempt to instantiate a lambda with an `AnnotatedType`, refactors the code that handles transforming the function type of a lambda, and improves source fidelity for lambda function types. This fixes llvm#85120 and fixes llvm#85154. --------- Co-authored-by: Yuxuan Chen <[email protected]> Co-authored-by: Doug Wyatt <[email protected]>
1 parent 996c0f3 commit b88d4ce

File tree

7 files changed

+209
-113
lines changed

7 files changed

+209
-113
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
253253
mutable llvm::FoldingSet<BitIntType> BitIntTypes;
254254
mutable llvm::ContextualFoldingSet<DependentBitIntType, ASTContext &>
255255
DependentBitIntTypes;
256-
llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes;
256+
mutable llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes;
257257
llvm::FoldingSet<HLSLAttributedResourceType> HLSLAttributedResourceTypes;
258258

259259
mutable llvm::FoldingSet<CountAttributedType> CountAttributedTypes;
@@ -1369,10 +1369,21 @@ class ASTContext : public RefCountedBase<ASTContext> {
13691369
/// calling T.withConst().
13701370
QualType getConstType(QualType T) const { return T.withConst(); }
13711371

1372+
/// Rebuild a type, preserving any existing type sugar. For function types,
1373+
/// you probably want to just use \c adjustFunctionResultType and friends
1374+
/// instead.
1375+
QualType adjustType(QualType OldType,
1376+
llvm::function_ref<QualType(QualType)> Adjust) const;
1377+
13721378
/// Change the ExtInfo on a function type.
13731379
const FunctionType *adjustFunctionType(const FunctionType *Fn,
13741380
FunctionType::ExtInfo EInfo);
13751381

1382+
/// Change the result type of a function type, preserving sugar such as
1383+
/// attributed types.
1384+
QualType adjustFunctionResultType(QualType FunctionType,
1385+
QualType NewResultType);
1386+
13761387
/// Adjust the given function result type.
13771388
CanQualType getCanonicalFunctionResultType(QualType ResultType) const;
13781389

@@ -1702,7 +1713,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
17021713
QualType equivalentType) const;
17031714

17041715
QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
1705-
QualType Wrapped);
1716+
QualType Wrapped) const;
17061717

17071718
QualType getHLSLAttributedResourceType(
17081719
QualType Wrapped, QualType Contained,

clang/include/clang/Sema/Template.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,11 @@ enum class TemplateSubstitutionKind : char {
411411
/// lookup will search our outer scope.
412412
bool CombineWithOuterScope;
413413

414+
/// Whether this scope is being used to instantiate a lambda expression,
415+
/// in which case it should be reused for instantiating the lambda's
416+
/// FunctionProtoType.
417+
bool InstantiatingLambda = false;
418+
414419
/// If non-NULL, the template parameter pack that has been
415420
/// partially substituted per C++0x [temp.arg.explicit]p9.
416421
NamedDecl *PartiallySubstitutedPack = nullptr;
@@ -425,9 +430,11 @@ enum class TemplateSubstitutionKind : char {
425430
unsigned NumArgsInPartiallySubstitutedPack;
426431

427432
public:
428-
LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
433+
LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false,
434+
bool InstantiatingLambda = false)
429435
: SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
430-
CombineWithOuterScope(CombineWithOuterScope) {
436+
CombineWithOuterScope(CombineWithOuterScope),
437+
InstantiatingLambda(InstantiatingLambda) {
431438
SemaRef.CurrentInstantiationScope = this;
432439
}
433440

@@ -553,6 +560,9 @@ enum class TemplateSubstitutionKind : char {
553560

554561
/// Determine whether D is a pack expansion created in this scope.
555562
bool isLocalPackExpansion(const Decl *D);
563+
564+
/// Determine whether this scope is for instantiating a lambda.
565+
bool isLambda() const { return InstantiatingLambda; }
556566
};
557567

558568
class TemplateDeclInstantiator

clang/lib/AST/ASTContext.cpp

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3535,6 +3535,50 @@ QualType ASTContext::getCountAttributedType(
35353535
return QualType(CATy, 0);
35363536
}
35373537

3538+
QualType
3539+
ASTContext::adjustType(QualType Orig,
3540+
llvm::function_ref<QualType(QualType)> Adjust) const {
3541+
switch (Orig->getTypeClass()) {
3542+
case Type::Attributed: {
3543+
const auto *AT = dyn_cast<AttributedType>(Orig);
3544+
return getAttributedType(AT->getAttrKind(),
3545+
adjustType(AT->getModifiedType(), Adjust),
3546+
adjustType(AT->getEquivalentType(), Adjust));
3547+
}
3548+
3549+
case Type::BTFTagAttributed: {
3550+
const auto *BTFT = dyn_cast<BTFTagAttributedType>(Orig);
3551+
return getBTFTagAttributedType(BTFT->getAttr(),
3552+
adjustType(BTFT->getWrappedType(), Adjust));
3553+
}
3554+
3555+
case Type::Elaborated: {
3556+
const auto *ET = cast<ElaboratedType>(Orig);
3557+
return getElaboratedType(ET->getKeyword(), ET->getQualifier(),
3558+
adjustType(ET->getNamedType(), Adjust));
3559+
}
3560+
3561+
case Type::Paren:
3562+
return getParenType(
3563+
adjustType(cast<ParenType>(Orig)->getInnerType(), Adjust));
3564+
3565+
case Type::Adjusted: {
3566+
const auto *AT = cast<AdjustedType>(Orig);
3567+
return getAdjustedType(AT->getOriginalType(),
3568+
adjustType(AT->getAdjustedType(), Adjust));
3569+
}
3570+
3571+
case Type::MacroQualified: {
3572+
const auto *MQT = cast<MacroQualifiedType>(Orig);
3573+
return getMacroQualifiedType(adjustType(MQT->getUnderlyingType(), Adjust),
3574+
MQT->getMacroIdentifier());
3575+
}
3576+
3577+
default:
3578+
return Adjust(Orig);
3579+
}
3580+
}
3581+
35383582
const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
35393583
FunctionType::ExtInfo Info) {
35403584
if (T->getExtInfo() == Info)
@@ -3553,13 +3597,23 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
35533597
return cast<FunctionType>(Result.getTypePtr());
35543598
}
35553599

3600+
QualType ASTContext::adjustFunctionResultType(QualType FunctionType,
3601+
QualType ResultType) {
3602+
return adjustType(FunctionType, [&](QualType Orig) {
3603+
if (const auto *FNPT = Orig->getAs<FunctionNoProtoType>())
3604+
return getFunctionNoProtoType(ResultType, FNPT->getExtInfo());
3605+
3606+
const auto *FPT = Orig->castAs<FunctionProtoType>();
3607+
return getFunctionType(ResultType, FPT->getParamTypes(),
3608+
FPT->getExtProtoInfo());
3609+
});
3610+
}
3611+
35563612
void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
35573613
QualType ResultType) {
35583614
FD = FD->getMostRecentDecl();
35593615
while (true) {
3560-
const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
3561-
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
3562-
FD->setType(getFunctionType(ResultType, FPT->getParamTypes(), EPI));
3616+
FD->setType(adjustFunctionResultType(FD->getType(), ResultType));
35633617
if (FunctionDecl *Next = FD->getPreviousDecl())
35643618
FD = Next;
35653619
else
@@ -3575,30 +3629,11 @@ void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
35753629
/// and preserved. Other type sugar (for instance, typedefs) is not.
35763630
QualType ASTContext::getFunctionTypeWithExceptionSpec(
35773631
QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI) const {
3578-
// Might have some parens.
3579-
if (const auto *PT = dyn_cast<ParenType>(Orig))
3580-
return getParenType(
3581-
getFunctionTypeWithExceptionSpec(PT->getInnerType(), ESI));
3582-
3583-
// Might be wrapped in a macro qualified type.
3584-
if (const auto *MQT = dyn_cast<MacroQualifiedType>(Orig))
3585-
return getMacroQualifiedType(
3586-
getFunctionTypeWithExceptionSpec(MQT->getUnderlyingType(), ESI),
3587-
MQT->getMacroIdentifier());
3588-
3589-
// Might have a calling-convention attribute.
3590-
if (const auto *AT = dyn_cast<AttributedType>(Orig))
3591-
return getAttributedType(
3592-
AT->getAttrKind(),
3593-
getFunctionTypeWithExceptionSpec(AT->getModifiedType(), ESI),
3594-
getFunctionTypeWithExceptionSpec(AT->getEquivalentType(), ESI));
3595-
3596-
// Anything else must be a function type. Rebuild it with the new exception
3597-
// specification.
3598-
const auto *Proto = Orig->castAs<FunctionProtoType>();
3599-
return getFunctionType(
3600-
Proto->getReturnType(), Proto->getParamTypes(),
3601-
Proto->getExtProtoInfo().withExceptionSpec(ESI));
3632+
return adjustType(Orig, [&](QualType Ty) {
3633+
const auto *Proto = Ty->castAs<FunctionProtoType>();
3634+
return getFunctionType(Proto->getReturnType(), Proto->getParamTypes(),
3635+
Proto->getExtProtoInfo().withExceptionSpec(ESI));
3636+
});
36023637
}
36033638

36043639
bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T,
@@ -5165,7 +5200,7 @@ QualType ASTContext::getAttributedType(attr::Kind attrKind,
51655200
}
51665201

51675202
QualType ASTContext::getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
5168-
QualType Wrapped) {
5203+
QualType Wrapped) const {
51695204
llvm::FoldingSetNodeID ID;
51705205
BTFTagAttributedType::Profile(ID, Wrapped, BTFAttr);
51715206

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,7 +1677,8 @@ namespace {
16771677
// Lambdas have already been processed inside their eval contexts.
16781678
if (SemaRef.RebuildingImmediateInvocation)
16791679
return E;
1680-
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
1680+
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
1681+
/*InstantiatingLambda=*/true);
16811682
Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
16821683

16831684
return inherited::TransformLambdaExpr(E);
@@ -2432,8 +2433,18 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
24322433
CXXRecordDecl *ThisContext,
24332434
Qualifiers ThisTypeQuals,
24342435
Fn TransformExceptionSpec) {
2435-
// We need a local instantiation scope for this function prototype.
2436-
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
2436+
// If this is a lambda, the transformation MUST be done in the
2437+
// CurrentInstantiationScope since it introduces a mapping of
2438+
// the original to the newly created transformed parameters.
2439+
//
2440+
// In that case, TemplateInstantiator::TransformLambdaExpr will
2441+
// have already pushed a scope for this prototype, so don't create
2442+
// a second one.
2443+
LocalInstantiationScope *Current = getSema().CurrentInstantiationScope;
2444+
std::optional<LocalInstantiationScope> Scope;
2445+
if (!Current || !Current->isLambda())
2446+
Scope.emplace(SemaRef, /*CombineWithOuterScope=*/true);
2447+
24372448
return inherited::TransformFunctionProtoType(
24382449
TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec);
24392450
}

clang/lib/Sema/TreeTransform.h

Lines changed: 40 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -684,10 +684,6 @@ class TreeTransform {
684684
Qualifiers ThisTypeQuals,
685685
Fn TransformExceptionSpec);
686686

687-
template <typename Fn>
688-
QualType TransformAttributedType(TypeLocBuilder &TLB, AttributedTypeLoc TL,
689-
Fn TransformModifiedType);
690-
691687
bool TransformExceptionSpec(SourceLocation Loc,
692688
FunctionProtoType::ExceptionSpecInfo &ESI,
693689
SmallVectorImpl<QualType> &Exceptions,
@@ -7373,11 +7369,10 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
73737369
}
73747370

73757371
template <typename Derived>
7376-
template <typename Fn>
7377-
QualType TreeTransform<Derived>::TransformAttributedType(
7378-
TypeLocBuilder &TLB, AttributedTypeLoc TL, Fn TransformModifiedTypeFn) {
7372+
QualType TreeTransform<Derived>::TransformAttributedType(TypeLocBuilder &TLB,
7373+
AttributedTypeLoc TL) {
73797374
const AttributedType *oldType = TL.getTypePtr();
7380-
QualType modifiedType = TransformModifiedTypeFn(TLB, TL.getModifiedLoc());
7375+
QualType modifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc());
73817376
if (modifiedType.isNull())
73827377
return QualType();
73837378

@@ -7392,12 +7387,27 @@ QualType TreeTransform<Derived>::TransformAttributedType(
73927387
// FIXME: dependent operand expressions?
73937388
if (getDerived().AlwaysRebuild() ||
73947389
modifiedType != oldType->getModifiedType()) {
7395-
TypeLocBuilder AuxiliaryTLB;
7396-
AuxiliaryTLB.reserve(TL.getFullDataSize());
7397-
QualType equivalentType =
7398-
getDerived().TransformType(AuxiliaryTLB, TL.getEquivalentTypeLoc());
7399-
if (equivalentType.isNull())
7400-
return QualType();
7390+
// If the equivalent type is equal to the modified type, we don't want to
7391+
// transform it as well because:
7392+
//
7393+
// 1. The transformation would yield the same result and is therefore
7394+
// superfluous, and
7395+
//
7396+
// 2. Transforming the same type twice can cause problems, e.g. if it
7397+
// is a FunctionProtoType, we may end up instantiating the function
7398+
// parameters twice, which causes an assertion since the parameters
7399+
// are already bound to their counterparts in the template for this
7400+
// instantiation.
7401+
//
7402+
QualType equivalentType = modifiedType;
7403+
if (TL.getModifiedLoc().getType() != TL.getEquivalentTypeLoc().getType()) {
7404+
TypeLocBuilder AuxiliaryTLB;
7405+
AuxiliaryTLB.reserve(TL.getFullDataSize());
7406+
equivalentType =
7407+
getDerived().TransformType(AuxiliaryTLB, TL.getEquivalentTypeLoc());
7408+
if (equivalentType.isNull())
7409+
return QualType();
7410+
}
74017411

74027412
// Check whether we can add nullability; it is only represented as
74037413
// type sugar, and therefore cannot be diagnosed in any other way.
@@ -7421,15 +7431,6 @@ QualType TreeTransform<Derived>::TransformAttributedType(
74217431
return result;
74227432
}
74237433

7424-
template <typename Derived>
7425-
QualType TreeTransform<Derived>::TransformAttributedType(TypeLocBuilder &TLB,
7426-
AttributedTypeLoc TL) {
7427-
return getDerived().TransformAttributedType(
7428-
TLB, TL, [&](TypeLocBuilder &TLB, TypeLoc ModifiedLoc) -> QualType {
7429-
return getDerived().TransformType(TLB, ModifiedLoc);
7430-
});
7431-
}
7432-
74337434
template <typename Derived>
74347435
QualType TreeTransform<Derived>::TransformCountAttributedType(
74357436
TypeLocBuilder &TLB, CountAttributedTypeLoc TL) {
@@ -14774,63 +14775,29 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
1477414775
TPL->containsUnexpandedParameterPack();
1477514776
}
1477614777

14777-
// Transform the type of the original lambda's call operator.
14778-
// The transformation MUST be done in the CurrentInstantiationScope since
14779-
// it introduces a mapping of the original to the newly created
14780-
// transformed parameters.
14781-
TypeSourceInfo *NewCallOpTSI = nullptr;
14782-
{
14783-
auto OldCallOpTypeLoc =
14784-
E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
14785-
14786-
auto TransformFunctionProtoTypeLoc =
14787-
[this](TypeLocBuilder &TLB, FunctionProtoTypeLoc FPTL) -> QualType {
14788-
SmallVector<QualType, 4> ExceptionStorage;
14789-
return this->TransformFunctionProtoType(
14790-
TLB, FPTL, nullptr, Qualifiers(),
14791-
[&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) {
14792-
return TransformExceptionSpec(FPTL.getBeginLoc(), ESI,
14793-
ExceptionStorage, Changed);
14794-
});
14795-
};
14796-
14797-
QualType NewCallOpType;
14798-
TypeLocBuilder NewCallOpTLBuilder;
14799-
14800-
if (auto ATL = OldCallOpTypeLoc.getAs<AttributedTypeLoc>()) {
14801-
NewCallOpType = this->TransformAttributedType(
14802-
NewCallOpTLBuilder, ATL,
14803-
[&](TypeLocBuilder &TLB, TypeLoc TL) -> QualType {
14804-
return TransformFunctionProtoTypeLoc(
14805-
TLB, TL.castAs<FunctionProtoTypeLoc>());
14806-
});
14807-
} else {
14808-
auto FPTL = OldCallOpTypeLoc.castAs<FunctionProtoTypeLoc>();
14809-
NewCallOpType = TransformFunctionProtoTypeLoc(NewCallOpTLBuilder, FPTL);
14810-
}
14811-
14812-
if (NewCallOpType.isNull())
14813-
return ExprError();
14814-
LSI->ContainsUnexpandedParameterPack |=
14815-
NewCallOpType->containsUnexpandedParameterPack();
14816-
NewCallOpTSI =
14817-
NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
14818-
}
14778+
TypeLocBuilder NewCallOpTLBuilder;
14779+
TypeLoc OldCallOpTypeLoc =
14780+
E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
14781+
QualType NewCallOpType =
14782+
getDerived().TransformType(NewCallOpTLBuilder, OldCallOpTypeLoc);
14783+
if (NewCallOpType.isNull())
14784+
return ExprError();
14785+
LSI->ContainsUnexpandedParameterPack |=
14786+
NewCallOpType->containsUnexpandedParameterPack();
14787+
TypeSourceInfo *NewCallOpTSI =
14788+
NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
1481914789

14820-
ArrayRef<ParmVarDecl *> Params;
14821-
if (auto ATL = NewCallOpTSI->getTypeLoc().getAs<AttributedTypeLoc>()) {
14822-
Params = ATL.getModifiedLoc().castAs<FunctionProtoTypeLoc>().getParams();
14823-
} else {
14824-
auto FPTL = NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
14825-
Params = FPTL.getParams();
14826-
}
14790+
// The type may be an AttributedType or some other kind of sugar;
14791+
// get the actual underlying FunctionProtoType.
14792+
auto FPTL = NewCallOpTSI->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>();
14793+
assert(FPTL && "Not a FunctionProtoType?");
1482714794

1482814795
getSema().CompleteLambdaCallOperator(
1482914796
NewCallOperator, E->getCallOperator()->getLocation(),
1483014797
E->getCallOperator()->getInnerLocStart(),
1483114798
E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI,
1483214799
E->getCallOperator()->getConstexprKind(),
14833-
E->getCallOperator()->getStorageClass(), Params,
14800+
E->getCallOperator()->getStorageClass(), FPTL.getParams(),
1483414801
E->hasExplicitResultType());
1483514802

1483614803
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);

0 commit comments

Comments
 (0)