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