@@ -2755,23 +2755,42 @@ bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext *DC) {
2755
2755
return false ;
2756
2756
}
2757
2757
2758
- // Build deduction guides for a type alias template.
2759
- void DeclareImplicitDeductionGuidesForTypeAlias (
2760
- Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc) {
2761
- if (AliasTemplate->isInvalidDecl ())
2762
- return ;
2763
- auto &Context = SemaRef.Context ;
2764
- // FIXME: if there is an explicit deduction guide after the first use of the
2765
- // type alias usage, we will not cover this explicit deduction guide. fix this
2766
- // case.
2767
- if (hasDeclaredDeductionGuides (
2768
- Context.DeclarationNames .getCXXDeductionGuideName (AliasTemplate),
2769
- AliasTemplate->getDeclContext ()))
2770
- return ;
2758
+ NamedDecl *transformTemplateParameter (Sema &SemaRef, DeclContext *DC,
2759
+ NamedDecl *TemplateParam,
2760
+ MultiLevelTemplateArgumentList &Args,
2761
+ unsigned NewIndex) {
2762
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
2763
+ return transformTemplateTypeParam (SemaRef, DC, TTP, Args, TTP->getDepth (),
2764
+ NewIndex);
2765
+ if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
2766
+ return transformTemplateParam (SemaRef, DC, TTP, Args, NewIndex,
2767
+ TTP->getDepth ());
2768
+ if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TemplateParam))
2769
+ return transformTemplateParam (SemaRef, DC, NTTP, Args, NewIndex,
2770
+ NTTP->getDepth ());
2771
+ return nullptr ;
2772
+ }
2773
+
2774
+ Expr *transformRequireClause (Sema &SemaRef, FunctionTemplateDecl *FTD,
2775
+ llvm::ArrayRef<TemplateArgument> TransformedArgs) {
2776
+ Expr *RC = FTD->getTemplateParameters ()->getRequiresClause ();
2777
+ if (!RC)
2778
+ return nullptr ;
2779
+ MultiLevelTemplateArgumentList Args;
2780
+ Args.setKind (TemplateSubstitutionKind::Rewrite);
2781
+ Args.addOuterTemplateArguments (TransformedArgs);
2782
+ ExprResult E = SemaRef.SubstExpr (RC, Args);
2783
+ if (E.isInvalid ())
2784
+ return nullptr ;
2785
+ return E.getAs <Expr>();
2786
+ }
2787
+
2788
+ std::pair<TemplateDecl *, llvm::ArrayRef<TemplateArgument>>
2789
+ getRHSTemplateDeclAndArgs (Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) {
2771
2790
// Unwrap the sugared ElaboratedType.
2772
2791
auto RhsType = AliasTemplate->getTemplatedDecl ()
2773
2792
->getUnderlyingType ()
2774
- .getSingleStepDesugaredType (Context);
2793
+ .getSingleStepDesugaredType (SemaRef. Context );
2775
2794
TemplateDecl *Template = nullptr ;
2776
2795
llvm::ArrayRef<TemplateArgument> AliasRhsTemplateArgs;
2777
2796
if (const auto *TST = RhsType->getAs <TemplateSpecializationType>()) {
@@ -2792,6 +2811,24 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
2792
2811
} else {
2793
2812
assert (false && " unhandled RHS type of the alias" );
2794
2813
}
2814
+ return {Template, AliasRhsTemplateArgs};
2815
+ }
2816
+
2817
+ // Build deduction guides for a type alias template.
2818
+ void DeclareImplicitDeductionGuidesForTypeAlias (
2819
+ Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc) {
2820
+ if (AliasTemplate->isInvalidDecl ())
2821
+ return ;
2822
+ auto &Context = SemaRef.Context ;
2823
+ // FIXME: if there is an explicit deduction guide after the first use of the
2824
+ // type alias usage, we will not cover this explicit deduction guide. fix this
2825
+ // case.
2826
+ if (hasDeclaredDeductionGuides (
2827
+ Context.DeclarationNames .getCXXDeductionGuideName (AliasTemplate),
2828
+ AliasTemplate->getDeclContext ()))
2829
+ return ;
2830
+ auto [Template, AliasRhsTemplateArgs] =
2831
+ getRHSTemplateDeclAndArgs (SemaRef, AliasTemplate);
2795
2832
if (!Template)
2796
2833
return ;
2797
2834
DeclarationNameInfo NameInfo (
@@ -2804,6 +2841,13 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
2804
2841
FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(G);
2805
2842
if (!F)
2806
2843
continue ;
2844
+ // The **aggregate** deduction guides are handled in a different code path
2845
+ // (DeclareImplicitDeductionGuideFromInitList), which involves the tricky
2846
+ // cache.
2847
+ if (cast<CXXDeductionGuideDecl>(F->getTemplatedDecl ())
2848
+ ->getDeductionCandidateKind () == DeductionCandidate::Aggregate)
2849
+ continue ;
2850
+
2807
2851
auto RType = F->getTemplatedDecl ()->getReturnType ();
2808
2852
// The (trailing) return type of the deduction guide.
2809
2853
const TemplateSpecializationType *FReturnType =
@@ -2886,21 +2930,6 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
2886
2930
// parameters, used for building `TemplateArgsForBuildingFPrime`.
2887
2931
SmallVector<TemplateArgument, 16 > TransformedDeducedAliasArgs (
2888
2932
AliasTemplate->getTemplateParameters ()->size ());
2889
- auto TransformTemplateParameter =
2890
- [&SemaRef](DeclContext *DC, NamedDecl *TemplateParam,
2891
- MultiLevelTemplateArgumentList &Args,
2892
- unsigned NewIndex) -> NamedDecl * {
2893
- if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam))
2894
- return transformTemplateTypeParam (SemaRef, DC, TTP, Args,
2895
- TTP->getDepth (), NewIndex);
2896
- if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
2897
- return transformTemplateParam (SemaRef, DC, TTP, Args, NewIndex,
2898
- TTP->getDepth ());
2899
- if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TemplateParam))
2900
- return transformTemplateParam (SemaRef, DC, NTTP, Args, NewIndex,
2901
- NTTP->getDepth ());
2902
- return nullptr ;
2903
- };
2904
2933
2905
2934
for (unsigned AliasTemplateParamIdx : DeducedAliasTemplateParams) {
2906
2935
auto *TP = AliasTemplate->getTemplateParameters ()->getParam (
@@ -2910,9 +2939,9 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
2910
2939
MultiLevelTemplateArgumentList Args;
2911
2940
Args.setKind (TemplateSubstitutionKind::Rewrite);
2912
2941
Args.addOuterTemplateArguments (TransformedDeducedAliasArgs);
2913
- NamedDecl *NewParam =
2914
- TransformTemplateParameter ( AliasTemplate->getDeclContext (), TP, Args,
2915
- /* NewIndex*/ FPrimeTemplateParams.size ());
2942
+ NamedDecl *NewParam = transformTemplateParameter (
2943
+ SemaRef, AliasTemplate->getDeclContext (), TP, Args,
2944
+ /* NewIndex*/ FPrimeTemplateParams.size ());
2916
2945
FPrimeTemplateParams.push_back (NewParam);
2917
2946
2918
2947
auto NewTemplateArgument = Context.getCanonicalTemplateArgument (
@@ -2928,8 +2957,8 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
2928
2957
// We take a shortcut here, it is ok to reuse the
2929
2958
// TemplateArgsForBuildingFPrime.
2930
2959
Args.addOuterTemplateArguments (TemplateArgsForBuildingFPrime);
2931
- NamedDecl *NewParam = TransformTemplateParameter (
2932
- F->getDeclContext (), TP, Args, FPrimeTemplateParams.size ());
2960
+ NamedDecl *NewParam = transformTemplateParameter (
2961
+ SemaRef, F->getDeclContext (), TP, Args, FPrimeTemplateParams.size ());
2933
2962
FPrimeTemplateParams.push_back (NewParam);
2934
2963
2935
2964
assert (TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull () &&
@@ -2939,16 +2968,8 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
2939
2968
Context.getInjectedTemplateArg (NewParam));
2940
2969
}
2941
2970
// Substitute new template parameters into requires-clause if present.
2942
- Expr *RequiresClause = nullptr ;
2943
- if (Expr *InnerRC = F->getTemplateParameters ()->getRequiresClause ()) {
2944
- MultiLevelTemplateArgumentList Args;
2945
- Args.setKind (TemplateSubstitutionKind::Rewrite);
2946
- Args.addOuterTemplateArguments (TemplateArgsForBuildingFPrime);
2947
- ExprResult E = SemaRef.SubstExpr (InnerRC, Args);
2948
- if (E.isInvalid ())
2949
- return ;
2950
- RequiresClause = E.getAs <Expr>();
2951
- }
2971
+ Expr *RequiresClause =
2972
+ transformRequireClause (SemaRef, F, TemplateArgsForBuildingFPrime);
2952
2973
// FIXME: implement the is_deducible constraint per C++
2953
2974
// [over.match.class.deduct]p3.3:
2954
2975
// ... and a constraint that is satisfied if and only if the arguments
@@ -3014,8 +3035,79 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
3014
3035
}
3015
3036
}
3016
3037
3038
+ // Build an aggregate deduction guide for a type alias template.
3039
+ FunctionTemplateDecl *DeclareAggrecateDeductionGuideForTypeAlias (
3040
+ Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate,
3041
+ MutableArrayRef<QualType> ParamTypes, SourceLocation Loc) {
3042
+ TemplateDecl *RHSTemplate =
3043
+ getRHSTemplateDeclAndArgs (SemaRef, AliasTemplate).first ;
3044
+ if (!RHSTemplate)
3045
+ return nullptr ;
3046
+ auto *RHSDeductionGuide =
3047
+ SemaRef.DeclareImplicitDeductionGuideFromInitList (RHSTemplate, ParamTypes,
3048
+ Loc);
3049
+ if (!RHSDeductionGuide)
3050
+ return nullptr ;
3051
+
3052
+ LocalInstantiationScope Scope (SemaRef);
3053
+
3054
+ // Build a new template parameter list for the synthesized aggregate deduction
3055
+ // guide by transforming the one from RHSDeductionGuide.
3056
+ SmallVector<NamedDecl *> TransformedTemplateParams;
3057
+ // Template args that refer to the rebuilt template parameters.
3058
+ // All template arguments must be initialized in advance.
3059
+ SmallVector<TemplateArgument> TransformedTemplateArgs (
3060
+ RHSDeductionGuide->getTemplateParameters ()->size ());
3061
+ for (auto *TP : *RHSDeductionGuide->getTemplateParameters ()) {
3062
+ // Rebuild any internal references to earlier parameters and reindex as
3063
+ // we go.
3064
+ MultiLevelTemplateArgumentList Args;
3065
+ Args.setKind (TemplateSubstitutionKind::Rewrite);
3066
+ Args.addOuterTemplateArguments (TransformedTemplateArgs);
3067
+ NamedDecl *NewParam = transformTemplateParameter (
3068
+ SemaRef, AliasTemplate->getDeclContext (), TP, Args,
3069
+ /* NewIndex=*/ TransformedTemplateParams.size ());
3070
+
3071
+ TransformedTemplateArgs[TransformedTemplateParams.size ()] =
3072
+ SemaRef.Context .getCanonicalTemplateArgument (
3073
+ SemaRef.Context .getInjectedTemplateArg (NewParam));
3074
+ TransformedTemplateParams.push_back (NewParam);
3075
+ }
3076
+ // FIXME: implement the is_deducible constraint per C++
3077
+ // [over.match.class.deduct]p3.3.
3078
+ Expr *TransformedRequiresClause = transformRequireClause (
3079
+ SemaRef, RHSDeductionGuide, TransformedTemplateArgs);
3080
+ auto *TransformedTemplateParameterList = TemplateParameterList::Create (
3081
+ SemaRef.Context , AliasTemplate->getTemplateParameters ()->getTemplateLoc (),
3082
+ AliasTemplate->getTemplateParameters ()->getLAngleLoc (),
3083
+ TransformedTemplateParams,
3084
+ AliasTemplate->getTemplateParameters ()->getRAngleLoc (),
3085
+ TransformedRequiresClause);
3086
+ auto *TransformedTemplateArgList = TemplateArgumentList::CreateCopy (
3087
+ SemaRef.Context , TransformedTemplateArgs);
3088
+
3089
+ if (auto *TransformedDeductionGuide = SemaRef.InstantiateFunctionDeclaration (
3090
+ RHSDeductionGuide, TransformedTemplateArgList,
3091
+ AliasTemplate->getLocation (),
3092
+ Sema::CodeSynthesisContext::BuildingDeductionGuides)) {
3093
+ auto *GD =
3094
+ llvm::dyn_cast<clang::CXXDeductionGuideDecl>(TransformedDeductionGuide);
3095
+ FunctionTemplateDecl *Result = buildDeductionGuide (
3096
+ SemaRef, AliasTemplate, TransformedTemplateParameterList,
3097
+ GD->getCorrespondingConstructor (), GD->getExplicitSpecifier (),
3098
+ GD->getTypeSourceInfo (), AliasTemplate->getBeginLoc (),
3099
+ AliasTemplate->getLocation (), AliasTemplate->getEndLoc (),
3100
+ GD->isImplicit ());
3101
+ cast<CXXDeductionGuideDecl>(Result->getTemplatedDecl ())
3102
+ ->setDeductionCandidateKind (DeductionCandidate::Aggregate);
3103
+ return Result;
3104
+ }
3105
+ return nullptr ;
3106
+ }
3107
+
3017
3108
} // namespace
3018
3109
3110
+ // FIXME: rename to DeclareAggrecateDeductionGuide.
3019
3111
FunctionTemplateDecl *Sema::DeclareImplicitDeductionGuideFromInitList (
3020
3112
TemplateDecl *Template, MutableArrayRef<QualType> ParamTypes,
3021
3113
SourceLocation Loc) {
@@ -3024,17 +3116,22 @@ FunctionTemplateDecl *Sema::DeclareImplicitDeductionGuideFromInitList(
3024
3116
for (auto &T : ParamTypes)
3025
3117
T.getCanonicalType ().Profile (ID);
3026
3118
unsigned Hash = ID.ComputeHash ();
3027
-
3119
+
3028
3120
auto Found = AggregateDeductionCandidates.find (Hash);
3029
3121
if (Found != AggregateDeductionCandidates.end ()) {
3030
3122
CXXDeductionGuideDecl *GD = Found->getSecond ();
3031
3123
return GD->getDescribedFunctionTemplate ();
3032
3124
}
3033
-
3034
- // if (auto *AliasTemplate = llvm::dyn_cast<TypeAliasTemplateDecl>(Template)) {
3035
- // DeclareImplicitDeductionGuidesForTypeAlias(*this, AliasTemplate, Loc);
3036
- // return;
3037
- // }
3125
+
3126
+ if (auto *AliasTemplate = llvm::dyn_cast<TypeAliasTemplateDecl>(Template)) {
3127
+ if (auto *FTD = DeclareAggrecateDeductionGuideForTypeAlias (
3128
+ *this , AliasTemplate, ParamTypes, Loc)) {
3129
+ auto *GD = cast<CXXDeductionGuideDecl>(FTD->getTemplatedDecl ());
3130
+ GD->setDeductionCandidateKind (DeductionCandidate::Aggregate);
3131
+ AggregateDeductionCandidates[Hash] = GD;
3132
+ return FTD;
3133
+ }
3134
+ }
3038
3135
3039
3136
if (CXXRecordDecl *DefRecord =
3040
3137
cast<CXXRecordDecl>(Template->getTemplatedDecl ())->getDefinition ()) {
0 commit comments