Skip to content

Commit

Permalink
[Clang] Fix ICE where C++ Template Instantiation failed to handle att…
Browse files Browse the repository at this point in the history
…ributed lambdas (#76523)

This PR is proposing a fix for
#76521.

Clang used to assume that during template instantiation, Lambda
expressions can only have `FunctionProtoTypeLoc`s. However, this is not
true for certain attributes like `__attribute__((pcs("aapcs-vfp")))`,
whose interpretation happens after template instantiation. This PR
changes the transformation logic for lambdas.
  • Loading branch information
yuxuanchen1997 committed Jan 3, 2024
1 parent cba217a commit a8f4397
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 17 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,9 @@ Bug Fixes to AST Handling
- Fixed a bug where RecursiveASTVisitor fails to visit the
initializer of a bitfield.
`Issue 64916 <https://github.com/llvm/llvm-project/issues/64916>`_
- Fixed a bug where Template Instantiation failed to handle Lambda Expressions
with certain types of Attributes.
(`#76521 <https://github.com/llvm/llvm-project/issues/76521>`_)

Miscellaneous Bug Fixes
^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
71 changes: 54 additions & 17 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,10 @@ class TreeTransform {
Qualifiers ThisTypeQuals,
Fn TransformExceptionSpec);

template <typename Fn>
QualType TransformAttributedType(TypeLocBuilder &TLB, AttributedTypeLoc TL,
Fn TransformModifiedType);

bool TransformExceptionSpec(SourceLocation Loc,
FunctionProtoType::ExceptionSpecInfo &ESI,
SmallVectorImpl<QualType> &Exceptions,
Expand Down Expand Up @@ -7050,12 +7054,12 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
return Result;
}

template<typename Derived>
template <typename Derived>
template <typename Fn>
QualType TreeTransform<Derived>::TransformAttributedType(
TypeLocBuilder &TLB,
AttributedTypeLoc TL) {
TypeLocBuilder &TLB, AttributedTypeLoc TL, Fn TransformModifiedTypeFn) {
const AttributedType *oldType = TL.getTypePtr();
QualType modifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc());
QualType modifiedType = TransformModifiedTypeFn(TLB, TL.getModifiedLoc());
if (modifiedType.isNull())
return QualType();

Expand Down Expand Up @@ -7099,6 +7103,15 @@ QualType TreeTransform<Derived>::TransformAttributedType(
return result;
}

template <typename Derived>
QualType TreeTransform<Derived>::TransformAttributedType(TypeLocBuilder &TLB,
AttributedTypeLoc TL) {
return getDerived().TransformAttributedType(
TLB, TL, [&](TypeLocBuilder &TLB, TypeLoc ModifiedLoc) -> QualType {
return getDerived().TransformType(TLB, ModifiedLoc);
});
}

template <typename Derived>
QualType TreeTransform<Derived>::TransformBTFTagAttributedType(
TypeLocBuilder &TLB, BTFTagAttributedTypeLoc TL) {
Expand Down Expand Up @@ -13600,32 +13613,56 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// transformed parameters.
TypeSourceInfo *NewCallOpTSI = nullptr;
{
TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
auto OldCallOpFPTL =
OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
auto OldCallOpTypeLoc =
E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();

auto TransformFunctionProtoTypeLoc =
[this](TypeLocBuilder &TLB, FunctionProtoTypeLoc FPTL) -> QualType {
SmallVector<QualType, 4> ExceptionStorage;
TreeTransform *This = this; // Work around gcc.gnu.org/PR56135.
return this->TransformFunctionProtoType(
TLB, FPTL, nullptr, Qualifiers(),
[&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) {
return This->TransformExceptionSpec(FPTL.getBeginLoc(), ESI,
ExceptionStorage, Changed);
});
};

QualType NewCallOpType;
TypeLocBuilder NewCallOpTLBuilder;
SmallVector<QualType, 4> ExceptionStorage;
TreeTransform *This = this; // Work around gcc.gnu.org/PR56135.
QualType NewCallOpType = TransformFunctionProtoType(
NewCallOpTLBuilder, OldCallOpFPTL, nullptr, Qualifiers(),
[&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) {
return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI,
ExceptionStorage, Changed);
});

if (auto ATL = OldCallOpTypeLoc.getAs<AttributedTypeLoc>()) {
NewCallOpType = this->TransformAttributedType(
NewCallOpTLBuilder, ATL,
[&](TypeLocBuilder &TLB, TypeLoc TL) -> QualType {
return TransformFunctionProtoTypeLoc(
TLB, TL.castAs<FunctionProtoTypeLoc>());
});
} else {
auto FPTL = OldCallOpTypeLoc.castAs<FunctionProtoTypeLoc>();
NewCallOpType = TransformFunctionProtoTypeLoc(NewCallOpTLBuilder, FPTL);
}

if (NewCallOpType.isNull())
return ExprError();
NewCallOpTSI =
NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
}

ArrayRef<ParmVarDecl *> Params;
if (auto ATL = NewCallOpTSI->getTypeLoc().getAs<AttributedTypeLoc>()) {
Params = ATL.getModifiedLoc().castAs<FunctionProtoTypeLoc>().getParams();
} else {
auto FPTL = NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
Params = FPTL.getParams();
}

getSema().CompleteLambdaCallOperator(
NewCallOperator, E->getCallOperator()->getLocation(),
E->getCallOperator()->getInnerLocStart(),
E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI,
E->getCallOperator()->getConstexprKind(),
E->getCallOperator()->getStorageClass(),
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
E->getCallOperator()->getStorageClass(), Params,
E->hasExplicitResultType());

getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
Expand Down
15 changes: 15 additions & 0 deletions clang/test/SemaCXX/template-instantiation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: %clang_cc1 -verify -fsyntax-only -Wno-ignored-attributes %s
// expected-no-diagnostics

namespace GH76521 {

template <typename T>
void foo() {
auto l = []() __attribute__((pcs("aapcs-vfp"))) {};
}

void bar() {
foo<int>();
}

}

0 comments on commit a8f4397

Please sign in to comment.