Skip to content

Commit e0eb7c2

Browse files
authored
[Clang] Ensure initialized NTTP expressions when building CTAD for type aliases (llvm#161035)
We missed calling CheckTemplateArgument when building CTAD deduction guides. That ensures some InitExprs are correctly initialized, as in the test that crashed due to incorrect NTTP initialization. I don't use CheckTemplateArguments because, in CTAD synthesis, template parameter packs don't always appear at the end of the parameter list, unlike user-written ones mandated by the standard. This makes it difficult for CheckTemplateArguments to determine how many arguments a pack in middle should match, leading to unnecessary complexity. On the other hand, since we substitute non-deduced template parameters with deduced ones, we need to fold the packs midway through substitution, where CheckTemplateArgument is more convenient. As a drive-by this also removes some dead code in SemaInit. Fixes llvm#131408
1 parent a7016c4 commit e0eb7c2

File tree

4 files changed

+54
-9
lines changed

4 files changed

+54
-9
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ Bug Fixes in This Version
361361
first parameter. (#GH113323).
362362
- Fixed a crash with incompatible pointer to integer conversions in designated
363363
initializers involving string literals. (#GH154046)
364-
- Fix crash on CTAD for alias template. (#GH131342)
364+
- Fix crash on CTAD for alias template. (#GH131342), (#GH131408)
365365
- Clang now emits a frontend error when a function marked with the `flatten` attribute
366366
calls another function that requires target features not enabled in the caller. This
367367
prevents a fatal error in the backend.

clang/lib/Sema/SemaInit.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8219,8 +8219,8 @@ ExprResult InitializationSequence::Perform(Sema &S,
82198219
// InitializeTemporary entity for our target type.
82208220
QualType Ty = Step->Type;
82218221
bool IsTemporary = !S.Context.hasSameType(Entity.getType(), Ty);
8222-
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty);
8223-
InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity;
8222+
InitializedEntity InitEntity =
8223+
IsTemporary ? InitializedEntity::InitializeTemporary(Ty) : Entity;
82248224
InitListChecker PerformInitList(S, InitEntity,
82258225
InitList, Ty, /*VerifyOnly=*/false,
82268226
/*TreatUnavailableAsInvalid=*/false);
@@ -8242,7 +8242,6 @@ ExprResult InitializationSequence::Perform(Sema &S,
82428242

82438243
InitListExpr *StructuredInitList =
82448244
PerformInitList.getFullyStructuredList();
8245-
CurInit.get();
82468245
CurInit = shouldBindAsTemporary(InitEntity)
82478246
? S.MaybeBindToTemporary(StructuredInitList)
82488247
: StructuredInitList;

clang/lib/Sema/SemaTemplateDeductionGuide.cpp

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,17 +1171,46 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
11711171
Args.addOuterTemplateArguments(TransformedDeducedAliasArgs);
11721172
for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
11731173
const auto &D = DeduceResults[Index];
1174+
auto *TP = F->getTemplateParameters()->getParam(Index);
11741175
if (IsNonDeducedArgument(D)) {
11751176
// 2): Non-deduced template parameters would be substituted later.
11761177
continue;
11771178
}
11781179
TemplateArgumentLoc Input =
11791180
SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
1180-
TemplateArgumentLoc Output;
1181-
if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
1182-
assert(TemplateArgsForBuildingFPrime[Index].isNull() &&
1183-
"InstantiatedArgs must be null before setting");
1184-
TemplateArgsForBuildingFPrime[Index] = Output.getArgument();
1181+
TemplateArgumentListInfo Output;
1182+
if (SemaRef.SubstTemplateArguments(Input, Args, Output))
1183+
return nullptr;
1184+
assert(TemplateArgsForBuildingFPrime[Index].isNull() &&
1185+
"InstantiatedArgs must be null before setting");
1186+
// CheckTemplateArgument is necessary for NTTP initializations.
1187+
// FIXME: We may want to call CheckTemplateArguments instead, but we cannot
1188+
// match packs as usual, since packs can appear in the middle of the
1189+
// parameter list of a synthesized CTAD guide. See also the FIXME in
1190+
// test/SemaCXX/cxx20-ctad-type-alias.cpp:test25.
1191+
Sema::CheckTemplateArgumentInfo CTAI;
1192+
if (Input.getArgument().getKind() == TemplateArgument::Pack) {
1193+
for (auto TA : Output.arguments()) {
1194+
if (SemaRef.CheckTemplateArgument(
1195+
TP, TA, F, F->getLocation(), F->getLocation(),
1196+
/*ArgumentPackIndex=*/-1, CTAI,
1197+
Sema::CheckTemplateArgumentKind::CTAK_Specified))
1198+
return nullptr;
1199+
}
1200+
// We will substitute the non-deduced template arguments with these
1201+
// transformed (unpacked at this point) arguments, where that substitution
1202+
// requires a pack for the corresponding parameter packs.
1203+
TemplateArgsForBuildingFPrime[Index] =
1204+
TemplateArgument::CreatePackCopy(Context, CTAI.SugaredConverted);
1205+
} else {
1206+
assert(Output.arguments().size() == 1);
1207+
TemplateArgumentLoc Transformed = Output.arguments()[0];
1208+
if (SemaRef.CheckTemplateArgument(
1209+
TP, Transformed, F, F->getLocation(), F->getLocation(),
1210+
/*ArgumentPackIndex=*/-1, CTAI,
1211+
Sema::CheckTemplateArgumentKind::CTAK_Specified))
1212+
return nullptr;
1213+
TemplateArgsForBuildingFPrime[Index] = CTAI.SugaredConverted[0];
11851214
}
11861215
}
11871216

clang/test/SemaCXX/cxx20-ctad-type-alias.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,23 @@ static_assert(__is_same(decltype(a), A<A<int>>));
587587

588588
} // namespace GH133132
589589

590+
namespace GH131408 {
591+
592+
struct Node {};
593+
594+
template <class T, Node>
595+
struct A {
596+
A(T) {}
597+
};
598+
599+
template <class T>
600+
using AA = A<T, {}>;
601+
602+
AA a{0};
603+
604+
static_assert(__is_same(decltype(a), A<int, Node{}>));
605+
}
606+
590607
namespace GH130604 {
591608
template <typename T> struct A {
592609
A(T);

0 commit comments

Comments
 (0)