Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,7 @@ Bug Fixes to C++ Support
(`LWG3929 <https://wg21.link/LWG3929>`__.) (#GH121278)
- Clang now identifies unexpanded parameter packs within the type constraint on a non-type template parameter. (#GH88866)
- Fixed an issue while resolving type of expression indexing into a pack of values of non-dependent type (#GH121242)
- Fixed incorrect construction of template arguments for CTAD alias guides when type constraints are applied. (#GH122134)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
50 changes: 24 additions & 26 deletions clang/lib/Sema/SemaTemplateDeductionGuide.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
F->getTemplateParameters()->size());

// FIXME: DeduceTemplateArguments stops immediately at the first
// non-deducible template argument. However, this doesn't seem to casue
// non-deducible template argument. However, this doesn't seem to cause
// issues for practice cases, we probably need to extend it to continue
// performing deduction for rest of arguments to align with the C++
// standard.
Expand Down Expand Up @@ -1053,25 +1053,6 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument;
}
unsigned FirstUndeducedParamIdx = FPrimeTemplateParams.size();
// ...followed by the template parameters of f that were not deduced
// (including their default template arguments)
for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
auto *TP = F->getTemplateParameters()->getParam(FTemplateParamIdx);
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
// We take a shortcut here, it is ok to reuse the
// TemplateArgsForBuildingFPrime.
Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
NamedDecl *NewParam = transformTemplateParameter(
SemaRef, F->getDeclContext(), TP, Args, FPrimeTemplateParams.size(),
getDepthAndIndex(TP).first);
FPrimeTemplateParams.push_back(NewParam);

assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() &&
"The argument must be null before setting");
TemplateArgsForBuildingFPrime[FTemplateParamIdx] =
Context.getInjectedTemplateArg(NewParam);
}

// To form a deduction guide f' from f, we leverage clang's instantiation
// mechanism, we construct a template argument list where the template
Expand All @@ -1086,18 +1067,14 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
// 2) non-deduced template parameters of f: rebuild a
// template argument;
//
// 2) has been built already (when rebuilding the new template
// parameters), we now perform 1).
// We now perform 1), as case 2) might refer to substituted 1).
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
Args.addOuterTemplateArguments(TransformedDeducedAliasArgs);
for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
const auto &D = DeduceResults[Index];
if (D.isNull()) {
// 2): Non-deduced template parameter has been built already.
assert(!TemplateArgsForBuildingFPrime[Index].isNull() &&
"template arguments for non-deduced template parameters should "
"be been set!");
// 2): Non-deduced template parameters would be substituted later.
continue;
}
TemplateArgumentLoc Input =
Expand All @@ -1110,6 +1087,27 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
}
}

// Case 2)
// ...followed by the template parameters of f that were not deduced
// (including their default template arguments)
for (unsigned FTemplateParamIdx : NonDeducedTemplateParamsInFIndex) {
auto *TP = F->getTemplateParameters()->getParam(FTemplateParamIdx);
MultiLevelTemplateArgumentList Args;
Args.setKind(TemplateSubstitutionKind::Rewrite);
// We take a shortcut here, it is ok to reuse the
// TemplateArgsForBuildingFPrime.
Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
NamedDecl *NewParam = transformTemplateParameter(
SemaRef, F->getDeclContext(), TP, Args, FPrimeTemplateParams.size(),
getDepthAndIndex(TP).first);
FPrimeTemplateParams.push_back(NewParam);

assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() &&
"The argument must be null before setting");
TemplateArgsForBuildingFPrime[FTemplateParamIdx] =
Context.getInjectedTemplateArg(NewParam);
}

auto *TemplateArgListForBuildingFPrime =
TemplateArgumentList::CreateCopy(Context, TemplateArgsForBuildingFPrime);
// Form the f' by substituting the template arguments into f.
Expand Down
50 changes: 50 additions & 0 deletions clang/test/SemaTemplate/deduction-guide.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,3 +478,53 @@ A a{.f1 = {1}};
// CHECK-NEXT: `-DeclRefExpr {{.+}} <col:10> 'int' NonTypeTemplateParm {{.+}} 'N' 'int'

} // namespace GH83368

namespace GH122134 {

template <class, class>
concept Constraint = true;

template <class T, int> struct Struct {
Struct(Constraint<T> auto) {}
};

template <int N = 0> using Test = Struct<int, N>;

Test test(42);

// CHECK-LABEL: Dumping GH122134::<deduction guide for Test>:
// CHECK-NEXT: FunctionTemplateDecl {{.*}} implicit <deduction guide for Test>
// CHECK-NEXT: |-NonTypeTemplateParmDecl {{.*}} 'int' depth 0 index 0 N
// CHECK-NEXT: | `-TemplateArgument {{.*}} expr '0'
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 0
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} Concept {{.*}} 'Constraint' depth 0 index 1 auto:1
// CHECK-NEXT: | `-ConceptSpecializationExpr {{.*}} 'bool' Concept {{.*}} 'Constraint'
// CHECK-NEXT: | |-ImplicitConceptSpecializationDecl {{.*}}
// CHECK-NEXT: | | |-TemplateArgument type 'type-parameter-0-1'
// CHECK-NEXT: | | | `-TemplateTypeParmType {{.*}} 'type-parameter-0-1' dependent depth 0 index 1
// CHECK-NEXT: | | `-TemplateArgument type 'int'
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: | |-TemplateArgument {{.*}} type 'auto:1':'type-parameter-0-1'
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'auto:1' dependent depth 0 index 1
// CHECK-NEXT: | | `-TemplateTypeParm {{.*}} 'auto:1'
// CHECK-NEXT: | `-TemplateArgument {{.*}} type 'int'
// CHECK-NEXT: | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: |-TypeTraitExpr {{.*}} 'bool' __is_deducible
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.*}} 'GH122134::Test' dependent
// CHECK-NEXT: | | `-name: 'GH122134::Test'
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.*}} Test
// CHECK-NEXT: | `-TemplateSpecializationType {{.*}} 'Struct<int, N>' dependent
// CHECK-NEXT: | |-name: 'Struct':'GH122134::Struct' qualified
// CHECK-NEXT: | | `-ClassTemplateDecl {{.*}} Struct
// CHECK-NEXT: | |-TemplateArgument type 'int'
// CHECK-NEXT: | | `-SubstTemplateTypeParmType {{.*}} 'int' sugar class depth 0 index 0 T
// CHECK-NEXT: | | |-FunctionTemplate {{.*}} '<deduction guide for Struct>'
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: | `-TemplateArgument expr 'N'
// CHECK-NEXT: | `-SubstNonTypeTemplateParmExpr {{.*}} 'int'
// CHECK-NEXT: | |-NonTypeTemplateParmDecl {{.*}} 'int' depth 0 index 1
// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'N' 'int'
// CHECK-NEXT: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for Test> 'auto (auto:1) -> Struct<int, N>'
// CHECK-NEXT: | `-ParmVarDecl {{.*}} 'auto:1'

} // namespace GH122134
Loading