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