Skip to content

Commit 833ab46

Browse files
zyn0217tmsri
authored andcommitted
[Clang] Avoid transforming lambdas when rebuilding immediate expressions (llvm#108693)
When rebuilding immediate invocations inside `RemoveNestedImmediateInvocation()`, we employed a `TreeTransform` to exercise the traversal. The transformation has a side effect that, for template specialization types, their default template arguments are substituted separately, and if any lambdas are present, they will be transformed into distinct types than those used to instantiate the templates right before the `consteval` handling. This resulted in `B::func()` getting redundantly instantiated for the case in question. Since we're also in an immediate evaluation context, the body of `foo()` would also get instantiated, so we end up with a spurious friend redefinition error. Like what we have done in `ComplexRemove`, this patch also avoids the lambda's transformation in TemplateInstantiator if we know we're rebuilding immediate calls. In addition, this patch also consolidates the default argument substitution logic in `CheckTemplateArgumentList()`. Fixes llvm#107175
1 parent 26fe3c1 commit 833ab46

File tree

6 files changed

+57
-43
lines changed

6 files changed

+57
-43
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,9 @@ Bug Fixes to C++ Support
395395
- A follow-up fix was added for (#GH61460), as the previous fix was not entirely correct. (#GH86361)
396396
- Fixed a crash in the typo correction of an invalid CTAD guide. (#GH107887)
397397
- Fixed a crash when clang tries to subtitute parameter pack while retaining the parameter
398-
pack. #GH63819, #GH107560
398+
pack. (#GH63819), (#GH107560)
399399
- Fix a crash when a static assert declaration has an invalid close location. (#GH108687)
400+
- Avoided a redundant friend declaration instantiation under a certain ``consteval`` context. (#GH107175)
400401
- Fixed an assertion failure in debug mode, and potential crashes in release mode, when
401402
diagnosing a failed cast caused indirectly by a failed implicit conversion to the type of the constructor parameter.
402403

clang/lib/Sema/SemaExpr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17557,7 +17557,7 @@ static void RemoveNestedImmediateInvocation(
1755717557
else
1755817558
break;
1755917559
}
17560-
/// ConstantExpr are the first layer of implicit node to be removed so if
17560+
/// ConstantExprs are the first layer of implicit node to be removed so if
1756117561
/// Init isn't a ConstantExpr, no ConstantExpr will be skipped.
1756217562
if (auto *CE = dyn_cast<ConstantExpr>(Init);
1756317563
CE && CE->isImmediateInvocation())
@@ -17570,7 +17570,7 @@ static void RemoveNestedImmediateInvocation(
1757017570
}
1757117571
ExprResult TransformLambdaExpr(LambdaExpr *E) {
1757217572
// Do not rebuild lambdas to avoid creating a new type.
17573-
// Lambdas have already been processed inside their eval context.
17573+
// Lambdas have already been processed inside their eval contexts.
1757417574
return E;
1757517575
}
1757617576
bool AlwaysRebuild() { return false; }

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5508,50 +5508,31 @@ bool Sema::CheckTemplateArgumentList(
55085508
}
55095509

55105510
// Check whether we have a default argument.
5511-
TemplateArgumentLoc Arg;
5511+
bool HasDefaultArg;
55125512

55135513
// Retrieve the default template argument from the template
55145514
// parameter. For each kind of template parameter, we substitute the
55155515
// template arguments provided thus far and any "outer" template arguments
55165516
// (when the template parameter was part of a nested template) into
55175517
// the default argument.
5518-
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
5519-
if (!hasReachableDefaultArgument(TTP))
5520-
return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP,
5518+
TemplateArgumentLoc Arg = SubstDefaultTemplateArgumentIfAvailable(
5519+
Template, TemplateLoc, RAngleLoc, *Param, SugaredConverted,
5520+
CanonicalConverted, HasDefaultArg);
5521+
5522+
if (Arg.getArgument().isNull()) {
5523+
if (!HasDefaultArg) {
5524+
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param))
5525+
return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP,
5526+
NewArgs);
5527+
if (NonTypeTemplateParmDecl *NTTP =
5528+
dyn_cast<NonTypeTemplateParmDecl>(*Param))
5529+
return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
5530+
NewArgs);
5531+
return diagnoseMissingArgument(*this, TemplateLoc, Template,
5532+
cast<TemplateTemplateParmDecl>(*Param),
55215533
NewArgs);
5522-
5523-
if (SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc,
5524-
TTP, SugaredConverted,
5525-
CanonicalConverted, Arg))
5526-
return true;
5527-
} else if (NonTypeTemplateParmDecl *NTTP
5528-
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
5529-
if (!hasReachableDefaultArgument(NTTP))
5530-
return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
5531-
NewArgs);
5532-
5533-
if (SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc,
5534-
NTTP, SugaredConverted,
5535-
CanonicalConverted, Arg))
5536-
return true;
5537-
} else {
5538-
TemplateTemplateParmDecl *TempParm
5539-
= cast<TemplateTemplateParmDecl>(*Param);
5540-
5541-
if (!hasReachableDefaultArgument(TempParm))
5542-
return diagnoseMissingArgument(*this, TemplateLoc, Template, TempParm,
5543-
NewArgs);
5544-
5545-
NestedNameSpecifierLoc QualifierLoc;
5546-
TemplateName Name = SubstDefaultTemplateArgument(
5547-
*this, Template, TemplateLoc, RAngleLoc, TempParm, SugaredConverted,
5548-
CanonicalConverted, QualifierLoc);
5549-
if (Name.isNull())
5550-
return true;
5551-
5552-
Arg = TemplateArgumentLoc(
5553-
Context, TemplateArgument(Name), QualifierLoc,
5554-
TempParm->getDefaultArgument().getTemplateNameLoc());
5534+
}
5535+
return true;
55555536
}
55565537

55575538
// Introduce an instantiation record that describes where we are using

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,6 +1673,10 @@ namespace {
16731673
}
16741674

16751675
ExprResult TransformLambdaExpr(LambdaExpr *E) {
1676+
// Do not rebuild lambdas to avoid creating a new type.
1677+
// Lambdas have already been processed inside their eval contexts.
1678+
if (SemaRef.RebuildingImmediateInvocation)
1679+
return E;
16761680
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
16771681
Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
16781682

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6294,9 +6294,13 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
62946294

62956295
if (!SubstRecord) {
62966296
// T can be a dependent TemplateSpecializationType when performing a
6297-
// substitution for building a deduction guide.
6298-
assert(CodeSynthesisContexts.back().Kind ==
6299-
CodeSynthesisContext::BuildingDeductionGuides);
6297+
// substitution for building a deduction guide or for template
6298+
// argument deduction in the process of rebuilding immediate
6299+
// expressions. (Because the default argument that involves a lambda
6300+
// is untransformed and thus could be dependent at this point.)
6301+
assert(SemaRef.RebuildingImmediateInvocation ||
6302+
CodeSynthesisContexts.back().Kind ==
6303+
CodeSynthesisContext::BuildingDeductionGuides);
63006304
// Return a nullptr as a sentinel value, we handle it properly in
63016305
// the TemplateInstantiator::TransformInjectedClassNameType
63026306
// override, which we transform it to a TemplateSpecializationType.

clang/test/SemaCXX/cxx2a-consteval.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,3 +1248,27 @@ void test() {
12481248
}
12491249

12501250
}
1251+
1252+
// Test that we don't redundantly instantiate the friend declaration in
1253+
// RemoveNestedImmediateInvocation(). Otherwise, we would end up with spurious
1254+
// redefinition errors.
1255+
namespace GH107175 {
1256+
1257+
consteval void consteval_func() {}
1258+
1259+
template <auto> struct define_f {
1260+
friend void foo() {}
1261+
};
1262+
1263+
template <auto = [] {}> struct A {};
1264+
1265+
struct B {
1266+
template <auto T> consteval void func() { (void)define_f<T>{}; }
1267+
};
1268+
1269+
int main() {
1270+
B{}.func<A{}>();
1271+
consteval_func();
1272+
}
1273+
1274+
} // namespace GH107175

0 commit comments

Comments
 (0)