@@ -2758,31 +2758,149 @@ bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext *DC) {
2758
2758
return false;
2759
2759
}
2760
2760
2761
+ unsigned getTemplateParameterDepth(NamedDecl *TemplateParam) {
2762
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
2763
+ return TTP->getDepth();
2764
+ if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
2765
+ return TTP->getDepth();
2766
+ if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TemplateParam))
2767
+ return NTTP->getDepth();
2768
+ llvm_unreachable("Unhandled template parameter types");
2769
+ }
2770
+
2761
2771
NamedDecl *transformTemplateParameter(Sema &SemaRef, DeclContext *DC,
2762
2772
NamedDecl *TemplateParam,
2763
2773
MultiLevelTemplateArgumentList &Args,
2764
- unsigned NewIndex) {
2774
+ unsigned NewIndex, unsigned NewDepth ) {
2765
2775
if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
2766
- return transformTemplateTypeParam (SemaRef, DC, TTP, Args, TTP-> getDepth () ,
2776
+ return transformTemplateTypeParam(SemaRef, DC, TTP, Args, NewDepth ,
2767
2777
NewIndex);
2768
2778
if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
2769
- return transformTemplateParam (SemaRef, DC, TTP, Args, NewIndex,
2770
- TTP->getDepth ());
2779
+ return transformTemplateParam(SemaRef, DC, TTP, Args, NewIndex, NewDepth);
2771
2780
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TemplateParam))
2772
- return transformTemplateParam (SemaRef, DC, NTTP, Args, NewIndex,
2773
- NTTP->getDepth ());
2781
+ return transformTemplateParam(SemaRef, DC, NTTP, Args, NewIndex, NewDepth);
2774
2782
llvm_unreachable("Unhandled template parameter types");
2775
2783
}
2776
2784
2777
- Expr *transformRequireClause (Sema &SemaRef, FunctionTemplateDecl *FTD,
2778
- llvm::ArrayRef<TemplateArgument> TransformedArgs) {
2779
- Expr *RC = FTD->getTemplateParameters ()->getRequiresClause ();
2785
+ // Transform the require-clause of F if any.
2786
+ // The return result is expected to be the require-clause for the synthesized
2787
+ // alias deduction guide.
2788
+ Expr *transformRequireClause(Sema &SemaRef, FunctionTemplateDecl *F,
2789
+ TypeAliasTemplateDecl *AliasTemplate,
2790
+ ArrayRef<DeducedTemplateArgument> DeduceResults) {
2791
+ Expr *RC = F->getTemplateParameters()->getRequiresClause();
2780
2792
if (!RC)
2781
2793
return nullptr;
2794
+
2795
+ auto &Context = SemaRef.Context;
2796
+ LocalInstantiationScope Scope(SemaRef);
2797
+
2798
+ // In the clang AST, constraint nodes are deliberately not instantiated unless
2799
+ // they are actively being evaluated. Consequently, occurrences of template
2800
+ // parameters in the require-clause expression have a subtle "depth"
2801
+ // difference compared to normal occurrences in places, such as function
2802
+ // parameters. When transforming the require-clause, we must take this
2803
+ // distinction into account:
2804
+ //
2805
+ // 1) In the transformed require-clause, occurrences of template parameters
2806
+ // must use the "uninstantiated" depth;
2807
+ // 2) When substituting on the require-clause expr of the underlying
2808
+ // deduction guide, we must use the entire set of template argument lists;
2809
+ //
2810
+ // It's important to note that we're performing this transformation on an
2811
+ // *instantiated* AliasTemplate.
2812
+
2813
+ // For 1), if the alias template is nested within a class template, we
2814
+ // calcualte the 'uninstantiated' depth by adding the substitution level back.
2815
+ unsigned AdjustDepth = 0;
2816
+ if (auto *PrimaryTemplate =
2817
+ AliasTemplate->getInstantiatedFromMemberTemplate())
2818
+ AdjustDepth = PrimaryTemplate->getTemplateDepth();
2819
+
2820
+ // We rebuild all template parameters with the uninstantiated depth, and
2821
+ // build template arguments refer to them.
2822
+ SmallVector<TemplateArgument> AdjustedAliasTemplateArgs;
2823
+
2824
+ for (auto *TP : *AliasTemplate->getTemplateParameters()) {
2825
+ // Rebuild any internal references to earlier parameters and reindex
2826
+ // as we go.
2827
+ MultiLevelTemplateArgumentList Args;
2828
+ Args.setKind(TemplateSubstitutionKind::Rewrite);
2829
+ Args.addOuterTemplateArguments(AdjustedAliasTemplateArgs);
2830
+ NamedDecl *NewParam = transformTemplateParameter(
2831
+ SemaRef, AliasTemplate->getDeclContext(), TP, Args,
2832
+ /*NewIndex=*/AdjustedAliasTemplateArgs.size(),
2833
+ getTemplateParameterDepth(TP) + AdjustDepth);
2834
+
2835
+ auto NewTemplateArgument = Context.getCanonicalTemplateArgument(
2836
+ Context.getInjectedTemplateArg(NewParam));
2837
+ AdjustedAliasTemplateArgs.push_back(NewTemplateArgument);
2838
+ }
2839
+ // Template arguments used to transform the template arguments in
2840
+ // DeducedResults.
2841
+ SmallVector<TemplateArgument> TemplateArgsForBuildingRC(
2842
+ F->getTemplateParameters()->size());
2843
+ // Transform the transformed template args
2782
2844
MultiLevelTemplateArgumentList Args;
2783
2845
Args.setKind(TemplateSubstitutionKind::Rewrite);
2784
- Args.addOuterTemplateArguments (TransformedArgs);
2785
- ExprResult E = SemaRef.SubstExpr (RC, Args);
2846
+ Args.addOuterTemplateArguments(AdjustedAliasTemplateArgs);
2847
+
2848
+ for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
2849
+ const auto &D = DeduceResults[Index];
2850
+ if (D.isNull())
2851
+ continue;
2852
+ TemplateArgumentLoc Input =
2853
+ SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
2854
+ TemplateArgumentLoc Output;
2855
+ if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
2856
+ assert(TemplateArgsForBuildingRC[Index].isNull() &&
2857
+ "InstantiatedArgs must be null before setting");
2858
+ TemplateArgsForBuildingRC[Index] = Output.getArgument();
2859
+ }
2860
+ }
2861
+
2862
+ // A list of template arguments for transforming the require-clause of F.
2863
+ // It must contain the entire set of template argument lists.
2864
+ MultiLevelTemplateArgumentList ArgsForBuildingRC;
2865
+ ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
2866
+ ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC);
2867
+ // For 2), if the underlying F is instantiated from a member template, we need
2868
+ // the entire template argument list, as the constraint AST in the
2869
+ // require-clause of F remains completely uninstantiated.
2870
+ //
2871
+ // For example:
2872
+ // template <typename T> // depth 0
2873
+ // struct Outer {
2874
+ // template <typename U>
2875
+ // struct Foo { Foo(U); };
2876
+ //
2877
+ // template <typename U> // depth 1
2878
+ // requires C<U>
2879
+ // Foo(U) -> Foo<int>;
2880
+ // };
2881
+ // template <typename U>
2882
+ // using AFoo = Outer<int>::Foo<U>;
2883
+ //
2884
+ // In this scenario, the deduction guide for `Foo` inside `Outer<int>`:
2885
+ // - The occurrence of U in the require-expression is [depth:1, index:0]
2886
+ // - The occurrence of U in the function parameter is [depth:0, index:0]
2887
+ // - The template parameter of U is [depth:0, index:0]
2888
+ //
2889
+ // We add the outer template arguments which is [int] to the multi-level arg
2890
+ // list to ensure that the occurrence U in `C<U>` will be replaced with int
2891
+ // during the substitution.
2892
+ if (F->getInstantiatedFromMemberTemplate()) {
2893
+ auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs(
2894
+ F, F->getLexicalDeclContext(),
2895
+ /*Final=*/false, /*Innermost=*/std::nullopt,
2896
+ /*RelativeToPrimary=*/true,
2897
+ /*Pattern=*/nullptr,
2898
+ /*ForConstraintInstantiation=*/true);
2899
+ for (auto It : OuterLevelArgs)
2900
+ ArgsForBuildingRC.addOuterTemplateArguments(It.Args);
2901
+ }
2902
+
2903
+ ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
2786
2904
if (E.isInvalid())
2787
2905
return nullptr;
2788
2906
return E.getAs<Expr>();
@@ -2920,7 +3038,8 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
2920
3038
Args.addOuterTemplateArguments(TransformedDeducedAliasArgs);
2921
3039
NamedDecl *NewParam = transformTemplateParameter(
2922
3040
SemaRef, AliasTemplate->getDeclContext(), TP, Args,
2923
- /* NewIndex=*/ FPrimeTemplateParams.size ());
3041
+ /*NewIndex=*/FPrimeTemplateParams.size(),
3042
+ getTemplateParameterDepth(TP));
2924
3043
FPrimeTemplateParams.push_back(NewParam);
2925
3044
2926
3045
auto NewTemplateArgument = Context.getCanonicalTemplateArgument(
@@ -2937,7 +3056,8 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
2937
3056
// TemplateArgsForBuildingFPrime.
2938
3057
Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime);
2939
3058
NamedDecl *NewParam = transformTemplateParameter(
2940
- SemaRef, F->getDeclContext (), TP, Args, FPrimeTemplateParams.size ());
3059
+ SemaRef, F->getDeclContext(), TP, Args, FPrimeTemplateParams.size(),
3060
+ getTemplateParameterDepth(TP));
2941
3061
FPrimeTemplateParams.push_back(NewParam);
2942
3062
2943
3063
assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() &&
@@ -2993,7 +3113,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
2993
3113
auto *GG = cast<CXXDeductionGuideDecl>(FPrime);
2994
3114
2995
3115
Expr *RequiresClause =
2996
- transformRequireClause (SemaRef, F, TemplateArgsForBuildingFPrime );
3116
+ transformRequireClause(SemaRef, F, AliasTemplate, DeduceResults );
2997
3117
2998
3118
// FIXME: implement the is_deducible constraint per C++
2999
3119
// [over.match.class.deduct]p3.3:
0 commit comments