Skip to content

Commit fd4f94d

Browse files
authored
[Clang] Correct the order of substituted arguments in CTAD alias guides (#123022)
We missed a case of type constraints referencing deduced template parameters when constructing a deduction guide for the type alias. This patch fixes the issue by swapping the order of constructing 'template arguments not appearing in the type alias parameters' and 'template arguments that are not yet deduced'. Fixes #122134
1 parent c23f241 commit fd4f94d

File tree

3 files changed

+82
-31
lines changed

3 files changed

+82
-31
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,8 @@ Bug Fixes to C++ Support
950950
- Clang now identifies unexpanded parameter packs within the type constraint on a non-type template parameter. (#GH88866)
951951
- Fixed an issue while resolving type of expression indexing into a pack of values of non-dependent type (#GH121242)
952952
- Fixed a crash when __PRETTY_FUNCTION__ or __FUNCSIG__ (clang-cl) appears in the trailing return type of the lambda (#GH121274)
953+
- Fixed a crash caused by the incorrect construction of template arguments for CTAD alias guides when type
954+
constraints are applied. (#GH122134)
953955

954956
Bug Fixes to AST Handling
955957
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaTemplateDeductionGuide.cpp

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
996996
F->getTemplateParameters()->size());
997997

998998
// FIXME: DeduceTemplateArguments stops immediately at the first
999-
// non-deducible template argument. However, this doesn't seem to casue
999+
// non-deducible template argument. However, this doesn't seem to cause
10001000
// issues for practice cases, we probably need to extend it to continue
10011001
// performing deduction for rest of arguments to align with the C++
10021002
// standard.
@@ -1053,25 +1053,6 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
10531053
TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument;
10541054
}
10551055
unsigned FirstUndeducedParamIdx = FPrimeTemplateParams.size();
1056-
// ...followed by the template parameters of f that were not deduced
1057-
// (including their default template arguments)
1058-
for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
1059-
auto *TP = F->getTemplateParameters()->getParam(FTemplateParamIdx);
1060-
MultiLevelTemplateArgumentList Args;
1061-
Args.setKind(TemplateSubstitutionKind::Rewrite);
1062-
// We take a shortcut here, it is ok to reuse the
1063-
// TemplateArgsForBuildingFPrime.
1064-
Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
1065-
NamedDecl *NewParam = transformTemplateParameter(
1066-
SemaRef, F->getDeclContext(), TP, Args, FPrimeTemplateParams.size(),
1067-
getDepthAndIndex(TP).first);
1068-
FPrimeTemplateParams.push_back(NewParam);
1069-
1070-
assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() &&
1071-
"The argument must be null before setting");
1072-
TemplateArgsForBuildingFPrime[FTemplateParamIdx] =
1073-
Context.getInjectedTemplateArg(NewParam);
1074-
}
10751056

10761057
// To form a deduction guide f' from f, we leverage clang's instantiation
10771058
// mechanism, we construct a template argument list where the template
@@ -1080,24 +1061,21 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
10801061
// f, this ensures all template parameter occurrences are updated
10811062
// correctly.
10821063
//
1083-
// The template argument list is formed from the `DeducedArgs`, two parts:
1084-
// 1) appeared template parameters of alias: transfrom the deduced
1085-
// template argument;
1086-
// 2) non-deduced template parameters of f: rebuild a
1087-
// template argument;
1064+
// The template argument list is formed, in order, from
1065+
// 1) For the template parameters of the alias, the corresponding deduced
1066+
// template arguments
1067+
// 2) For the non-deduced template parameters of f. the
1068+
// (rebuilt) template arguments corresponding.
10881069
//
1089-
// 2) has been built already (when rebuilding the new template
1090-
// parameters), we now perform 1).
1070+
// Note: the non-deduced template arguments of `f` might refer to arguments
1071+
// deduced in 1), as in a type constraint.
10911072
MultiLevelTemplateArgumentList Args;
10921073
Args.setKind(TemplateSubstitutionKind::Rewrite);
10931074
Args.addOuterTemplateArguments(TransformedDeducedAliasArgs);
10941075
for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
10951076
const auto &D = DeduceResults[Index];
10961077
if (D.isNull()) {
1097-
// 2): Non-deduced template parameter has been built already.
1098-
assert(!TemplateArgsForBuildingFPrime[Index].isNull() &&
1099-
"template arguments for non-deduced template parameters should "
1100-
"be been set!");
1078+
// 2): Non-deduced template parameters would be substituted later.
11011079
continue;
11021080
}
11031081
TemplateArgumentLoc Input =
@@ -1110,6 +1088,27 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
11101088
}
11111089
}
11121090

1091+
// Case 2)
1092+
// ...followed by the template parameters of f that were not deduced
1093+
// (including their default template arguments)
1094+
for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
1095+
auto *TP = F->getTemplateParameters()->getParam(FTemplateParamIdx);
1096+
MultiLevelTemplateArgumentList Args;
1097+
Args.setKind(TemplateSubstitutionKind::Rewrite);
1098+
// We take a shortcut here, it is ok to reuse the
1099+
// TemplateArgsForBuildingFPrime.
1100+
Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
1101+
NamedDecl *NewParam = transformTemplateParameter(
1102+
SemaRef, F->getDeclContext(), TP, Args, FPrimeTemplateParams.size(),
1103+
getDepthAndIndex(TP).first);
1104+
FPrimeTemplateParams.push_back(NewParam);
1105+
1106+
assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() &&
1107+
"The argument must be null before setting");
1108+
TemplateArgsForBuildingFPrime[FTemplateParamIdx] =
1109+
Context.getInjectedTemplateArg(NewParam);
1110+
}
1111+
11131112
auto *TemplateArgListForBuildingFPrime =
11141113
TemplateArgumentList::CreateCopy(Context, TemplateArgsForBuildingFPrime);
11151114
// Form the f' by substituting the template arguments into f.

clang/test/SemaTemplate/deduction-guide.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,3 +478,53 @@ A a{.f1 = {1}};
478478
// CHECK-NEXT: `-DeclRefExpr {{.+}} <col:10> 'int' NonTypeTemplateParm {{.+}} 'N' 'int'
479479

480480
} // namespace GH83368
481+
482+
namespace GH122134 {
483+
484+
template <class, class>
485+
concept Constraint = true;
486+
487+
template <class T, int> struct Struct {
488+
Struct(Constraint<T> auto) {}
489+
};
490+
491+
template <int N = 0> using Test = Struct<int, N>;
492+
493+
Test test(42);
494+
495+
// CHECK-LABEL: Dumping GH122134::<deduction guide for Test>:
496+
// CHECK-NEXT: FunctionTemplateDecl {{.*}} implicit <deduction guide for Test>
497+
// CHECK-NEXT: |-NonTypeTemplateParmDecl {{.*}} 'int' depth 0 index 0 N
498+
// CHECK-NEXT: | `-TemplateArgument {{.*}} expr '0'
499+
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 0
500+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} Concept {{.*}} 'Constraint' depth 0 index 1 auto:1
501+
// CHECK-NEXT: | `-ConceptSpecializationExpr {{.*}} 'bool' Concept {{.*}} 'Constraint'
502+
// CHECK-NEXT: | |-ImplicitConceptSpecializationDecl {{.*}}
503+
// CHECK-NEXT: | | |-TemplateArgument type 'type-parameter-0-1'
504+
// CHECK-NEXT: | | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent depth 0 index 1
505+
// CHECK-NEXT: | | `-TemplateArgument type 'int'
506+
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'int'
507+
// CHECK-NEXT: | |-TemplateArgument {{.*}} type 'auto:1':'type-parameter-0-1'
508+
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'auto:1' dependent depth 0 index 1
509+
// CHECK-NEXT: | | `-TemplateTypeParm {{.*}} 'auto:1'
510+
// CHECK-NEXT: | `-TemplateArgument {{.*}} type 'int'
511+
// CHECK-NEXT: | `-BuiltinType {{.*}} 'int'
512+
// CHECK-NEXT: |-TypeTraitExpr {{.*}} 'bool' __is_deducible
513+
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.*}} 'GH122134::Test' dependent
514+
// CHECK-NEXT: | | `-name: 'GH122134::Test'
515+
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.*}} Test
516+
// CHECK-NEXT: | `-TemplateSpecializationType {{.*}} 'Struct<int, N>' dependent
517+
// CHECK-NEXT: | |-name: 'Struct':'GH122134::Struct' qualified
518+
// CHECK-NEXT: | | `-ClassTemplateDecl {{.*}} Struct
519+
// CHECK-NEXT: | |-TemplateArgument type 'int'
520+
// CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} 'int' sugar class depth 0 index 0 T
521+
// CHECK-NEXT: | | |-FunctionTemplate {{.*}} '<deduction guide for Struct>'
522+
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'int'
523+
// CHECK-NEXT: | `-TemplateArgument expr 'N'
524+
// CHECK-NEXT: | `-SubstNonTypeTemplateParmExpr {{.*}} 'int'
525+
// CHECK-NEXT: | |-NonTypeTemplateParmDecl {{.*}} 'int' depth 0 index 1
526+
// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'N' 'int'
527+
// CHECK-NEXT: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for Test> 'auto (auto:1) -> Struct<int, N>'
528+
// CHECK-NEXT: | `-ParmVarDecl {{.*}} 'auto:1'
529+
530+
} // namespace GH122134

0 commit comments

Comments
 (0)