@@ -2744,31 +2744,155 @@ bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext *DC) {
2744
2744
return false ;
2745
2745
}
2746
2746
2747
+ unsigned getTemplateDepth (NamedDecl *TemplateParam) {
2748
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
2749
+ return TTP->getDepth ();
2750
+ if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
2751
+ return TTP->getDepth ();
2752
+ if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TemplateParam))
2753
+ return NTTP->getDepth ();
2754
+ llvm_unreachable (" Unhandled template parameter types" );
2755
+ }
2756
+
2747
2757
NamedDecl *transformTemplateParameter (Sema &SemaRef, DeclContext *DC,
2748
2758
NamedDecl *TemplateParam,
2749
2759
MultiLevelTemplateArgumentList &Args,
2750
- unsigned NewIndex) {
2760
+ unsigned NewIndex, unsigned NewDepth ) {
2751
2761
if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
2752
- return transformTemplateTypeParam (SemaRef, DC, TTP, Args, TTP-> getDepth () ,
2762
+ return transformTemplateTypeParam (SemaRef, DC, TTP, Args, NewDepth ,
2753
2763
NewIndex);
2754
2764
if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
2755
2765
return transformTemplateParam (SemaRef, DC, TTP, Args, NewIndex,
2756
- TTP-> getDepth () );
2766
+ NewDepth );
2757
2767
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TemplateParam))
2758
2768
return transformTemplateParam (SemaRef, DC, NTTP, Args, NewIndex,
2759
- NTTP-> getDepth () );
2769
+ NewDepth );
2760
2770
llvm_unreachable (" Unhandled template parameter types" );
2761
2771
}
2762
2772
2763
- Expr *transformRequireClause (Sema &SemaRef, FunctionTemplateDecl *FTD,
2764
- llvm::ArrayRef<TemplateArgument> TransformedArgs) {
2765
- Expr *RC = FTD->getTemplateParameters ()->getRequiresClause ();
2773
+ // Transform the require-clause of F if any.
2774
+ // The return result is expected to be the require-clause for the synthesized
2775
+ // alias deduction guide.
2776
+ Expr *transformRequireClause (
2777
+ Sema &SemaRef, FunctionTemplateDecl *F,
2778
+ TypeAliasTemplateDecl *AliasTemplate,
2779
+ ArrayRef<DeducedTemplateArgument> DeduceResults) {
2780
+ Expr *RC = F->getTemplateParameters ()->getRequiresClause ();
2766
2781
if (!RC)
2767
2782
return nullptr ;
2783
+
2784
+ auto &Context = SemaRef.Context ;
2785
+ LocalInstantiationScope Scope (SemaRef);
2786
+
2787
+ // In the clang AST, constraint nodes are not instantiated at all unless they
2788
+ // are being evaluated. This means that occurrences of template parameters
2789
+ // in the require-clause expr have subtle differences compared to occurrences
2790
+ // in other places, such as function parameters. When transforming the
2791
+ // require-clause, we must respect these differences, particularly regarding
2792
+ // the 'depth' information:
2793
+ // 1) In the transformed require-clause, occurrences of template parameters
2794
+ // must use the "uninstantiated" depth;
2795
+ // 2) When substituting on the require-clause expr of the underlying
2796
+ // deduction guide, we must use the entire set of template argument lists.
2797
+ //
2798
+ // It's important to note that we're performing this transformation on an
2799
+ // *instantiated* AliasTemplate.
2800
+
2801
+ // For 1), if the alias template is nested within a class template, we
2802
+ // calcualte the 'uninstantiated' depth by adding the substitution level back.
2803
+ unsigned AdjustDepth = 0 ;
2804
+ if (auto *PrimaryTemplate = AliasTemplate->getInstantiatedFromMemberTemplate ())
2805
+ AdjustDepth = PrimaryTemplate->getTemplateDepth ();
2806
+
2807
+ // We rebuild all template parameters with the uninstantiated depth, and
2808
+ // build template arguments refer to them.
2809
+ SmallVector<TemplateArgument> AdjustedAliasTemplateArgs;
2810
+
2811
+ for (auto *TP : *AliasTemplate->getTemplateParameters ()) {
2812
+ // Rebuild any internal references to earlier parameters and reindex
2813
+ // as we go.
2814
+ MultiLevelTemplateArgumentList Args;
2815
+ Args.setKind (TemplateSubstitutionKind::Rewrite);
2816
+ Args.addOuterTemplateArguments (AdjustedAliasTemplateArgs);
2817
+ NamedDecl *NewParam = transformTemplateParameter (
2818
+ SemaRef, AliasTemplate->getDeclContext (), TP, Args,
2819
+ /* NewIndex=*/ AdjustedAliasTemplateArgs.size (),
2820
+ getTemplateDepth (TP) + AdjustDepth);
2821
+
2822
+ auto NewTemplateArgument = Context.getCanonicalTemplateArgument (
2823
+ Context.getInjectedTemplateArg (NewParam));
2824
+ AdjustedAliasTemplateArgs.push_back (NewTemplateArgument);
2825
+ }
2826
+ // Template arguments used to transform the template arguments in
2827
+ // DeducedResults.
2828
+ SmallVector<TemplateArgument> TemplateArgsForBuildingRC (
2829
+ F->getTemplateParameters ()->size ());
2830
+ // Transform the transformed template args
2768
2831
MultiLevelTemplateArgumentList Args;
2769
2832
Args.setKind (TemplateSubstitutionKind::Rewrite);
2770
- Args.addOuterTemplateArguments (TransformedArgs);
2771
- ExprResult E = SemaRef.SubstExpr (RC, Args);
2833
+ Args.addOuterTemplateArguments (AdjustedAliasTemplateArgs);
2834
+
2835
+ for (unsigned Index = 0 ; Index < DeduceResults.size (); ++Index) {
2836
+ const auto &D = DeduceResults[Index];
2837
+ if (D.isNull ())
2838
+ continue ;
2839
+ TemplateArgumentLoc Input =
2840
+ SemaRef.getTrivialTemplateArgumentLoc (D, QualType (), SourceLocation{});
2841
+ TemplateArgumentLoc Output;
2842
+ if (!SemaRef.SubstTemplateArgument (Input, Args, Output)) {
2843
+ assert (TemplateArgsForBuildingRC[Index].isNull () &&
2844
+ " InstantiatedArgs must be null before setting" );
2845
+ TemplateArgsForBuildingRC[Index] = Output.getArgument ();
2846
+ }
2847
+ }
2848
+
2849
+ // A list of template arguments for transforming the require-clause of F.
2850
+ // It must contain the entire set of template argument lists.
2851
+ MultiLevelTemplateArgumentList ArgsForBuildingRC;
2852
+ ArgsForBuildingRC.setKind (clang::TemplateSubstitutionKind::Rewrite);
2853
+ ArgsForBuildingRC.addOuterTemplateArguments (TemplateArgsForBuildingRC);
2854
+ // For 2), if the underlying F is instantiated from a member template, we need
2855
+ // the entire template argument list, as the constraint AST in the
2856
+ // require-clause of F remains completely uninstantiated.
2857
+ //
2858
+ // For example:
2859
+ // template <typename T> // depth 0
2860
+ // struct Outer {
2861
+ // template <typename U>
2862
+ // struct Foo { Foo(U); };
2863
+ //
2864
+ // template <typename U> // depth 1
2865
+ // requires C<U>
2866
+ // Foo(U) -> Foo<int>;
2867
+ // };
2868
+ // template <typename U>
2869
+ // using AFoo = Outer<int>::Foo<U>;
2870
+ //
2871
+ // In this scenario, the deduction guide for `Foo` inside `Outer<int>`:
2872
+ // - The occurrence of U in the require-expression is [depth:1, index:0]
2873
+ // - The occurrence of U in the function parameter is [depth:0, index:0]
2874
+ // - The template parameter of U is [depth:0, index:0]
2875
+ // Particularly, for the `Foo` deduction guide inside the `Outer<int>`:
2876
+ //
2877
+ // - occurrence of U in the require-expression is [depth:1, index:0]
2878
+ // - occurrence of U in the function parameter is [depth:0, index:0]
2879
+ // - the template parameter of U is [depth:0, index:0]
2880
+ //
2881
+ // We add the outer template arguments which is [int] to the multi-level arg
2882
+ // list to ensure that the occurrence U in `C<U>` will be replaced with int
2883
+ // during the substitution.
2884
+ if (F->getInstantiatedFromMemberTemplate ()) {
2885
+ auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs (
2886
+ F, F->getLexicalDeclContext (),
2887
+ /* Final=*/ false , /* Innermost=*/ std::nullopt,
2888
+ /* RelativeToPrimary=*/ true ,
2889
+ /* Pattern=*/ nullptr ,
2890
+ /* ForConstraintInstantiation=*/ true );
2891
+ for (auto It : OuterLevelArgs)
2892
+ ArgsForBuildingRC.addOuterTemplateArguments (It.Args );
2893
+ }
2894
+
2895
+ ExprResult E = SemaRef.SubstExpr (RC, ArgsForBuildingRC);
2772
2896
if (E.isInvalid ())
2773
2897
return nullptr ;
2774
2898
return E.getAs <Expr>();
@@ -2906,7 +3030,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
2906
3030
Args.addOuterTemplateArguments (TransformedDeducedAliasArgs);
2907
3031
NamedDecl *NewParam = transformTemplateParameter (
2908
3032
SemaRef, AliasTemplate->getDeclContext (), TP, Args,
2909
- /* NewIndex=*/ FPrimeTemplateParams.size ());
3033
+ /* NewIndex=*/ FPrimeTemplateParams.size (), getTemplateDepth (TP) );
2910
3034
FPrimeTemplateParams.push_back (NewParam);
2911
3035
2912
3036
auto NewTemplateArgument = Context.getCanonicalTemplateArgument (
@@ -2923,7 +3047,8 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
2923
3047
// TemplateArgsForBuildingFPrime.
2924
3048
Args.addOuterTemplateArguments (TemplateArgsForBuildingFPrime);
2925
3049
NamedDecl *NewParam = transformTemplateParameter (
2926
- SemaRef, F->getDeclContext (), TP, Args, FPrimeTemplateParams.size ());
3050
+ SemaRef, F->getDeclContext (), TP, Args, FPrimeTemplateParams.size (),
3051
+ getTemplateDepth (TP));
2927
3052
FPrimeTemplateParams.push_back (NewParam);
2928
3053
2929
3054
assert (TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull () &&
@@ -2978,8 +3103,8 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
2978
3103
Sema::CodeSynthesisContext::BuildingDeductionGuides)) {
2979
3104
auto *GG = cast<CXXDeductionGuideDecl>(FPrime);
2980
3105
2981
- Expr *RequiresClause =
2982
- transformRequireClause ( SemaRef, F, TemplateArgsForBuildingFPrime );
3106
+ Expr *RequiresClause = transformRequireClause (
3107
+ SemaRef, F, AliasTemplate, DeduceResults );
2983
3108
2984
3109
// FIXME: implement the is_deducible constraint per C++
2985
3110
// [over.match.class.deduct]p3.3:
0 commit comments