[clang] [clang] CTAD: fix the aggregate deduction guide for alias templates. (PR #90894)
Haojian Wu via cfe-commits
cfe-commits at lists.llvm.org
Fri May 3 02:14:08 PDT 2024
================
@@ -2803,7 +2803,207 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) {
return {Template, AliasRhsTemplateArgs};
}
-// Build deduction guides for a type alias template.
+// Build deduction guides for a type alias template from the given underlying
+// deduction guide F.
+FunctionTemplateDecl *
+BuildDeductionGuideForTypeAlias(Sema &SemaRef,
+ TypeAliasTemplateDecl *AliasTemplate,
+ FunctionTemplateDecl *F, SourceLocation Loc) {
+ LocalInstantiationScope Scope(SemaRef);
+ Sema::InstantiatingTemplate BuildingDeductionGuides(
+ SemaRef, AliasTemplate->getLocation(), F,
+ Sema::InstantiatingTemplate::BuildingDeductionGuidesTag{});
+ if (BuildingDeductionGuides.isInvalid())
+ return nullptr;
+
+ auto &Context = SemaRef.Context;
+ auto [Template, AliasRhsTemplateArgs] =
+ getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate);
+
+ auto RType = F->getTemplatedDecl()->getReturnType();
+ // The (trailing) return type of the deduction guide.
+ const TemplateSpecializationType *FReturnType =
+ RType->getAs<TemplateSpecializationType>();
+ if (const auto *InjectedCNT = RType->getAs<InjectedClassNameType>())
+ // implicitly-generated deduction guide.
+ FReturnType = InjectedCNT->getInjectedTST();
+ else if (const auto *ET = RType->getAs<ElaboratedType>())
+ // explicit deduction guide.
+ FReturnType = ET->getNamedType()->getAs<TemplateSpecializationType>();
+ assert(FReturnType && "expected to see a return type");
+ // Deduce template arguments of the deduction guide f from the RHS of
+ // the alias.
+ //
+ // C++ [over.match.class.deduct]p3: ...For each function or function
+ // template f in the guides of the template named by the
+ // simple-template-id of the defining-type-id, the template arguments
+ // of the return type of f are deduced from the defining-type-id of A
+ // according to the process in [temp.deduct.type] with the exception
+ // that deduction does not fail if not all template arguments are
+ // deduced.
+ //
+ //
+ // template<typename X, typename Y>
+ // f(X, Y) -> f<Y, X>;
+ //
+ // template<typename U>
+ // using alias = f<int, U>;
+ //
+ // The RHS of alias is f<int, U>, we deduced the template arguments of
+ // the return type of the deduction guide from it: Y->int, X->U
+ sema::TemplateDeductionInfo TDeduceInfo(Loc);
+ // Must initialize n elements, this is required by DeduceTemplateArguments.
+ SmallVector<DeducedTemplateArgument> DeduceResults(
+ F->getTemplateParameters()->size());
+
+ // FIXME: DeduceTemplateArguments stops immediately at the first
+ // non-deducible template argument. However, this doesn't seem to casue
+ // issues for practice cases, we probably need to extend it to continue
+ // performing deduction for rest of arguments to align with the C++
+ // standard.
+ SemaRef.DeduceTemplateArguments(
+ F->getTemplateParameters(), FReturnType->template_arguments(),
+ AliasRhsTemplateArgs, TDeduceInfo, DeduceResults,
+ /*NumberOfArgumentsMustMatch=*/false);
+
+ SmallVector<TemplateArgument> DeducedArgs;
+ SmallVector<unsigned> NonDeducedTemplateParamsInFIndex;
+ // !!NOTE: DeduceResults respects the sequence of template parameters of
+ // the deduction guide f.
+ for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) {
+ if (const auto &D = DeduceResults[Index]; !D.isNull()) // Deduced
+ DeducedArgs.push_back(D);
+ else
+ NonDeducedTemplateParamsInFIndex.push_back(Index);
+ }
+ auto DeducedAliasTemplateParams =
+ TemplateParamsReferencedInTemplateArgumentList(
+ AliasTemplate->getTemplateParameters()->asArray(), DeducedArgs);
+ // All template arguments null by default.
+ SmallVector<TemplateArgument> TemplateArgsForBuildingFPrime(
+ F->getTemplateParameters()->size());
+
+ // Create a template parameter list for the synthesized deduction guide f'.
+ //
+ // C++ [over.match.class.deduct]p3.2:
+ // If f is a function template, f' is a function template whose template
+ // parameter list consists of all the template parameters of A
+ // (including their default template arguments) that appear in the above
+ // deductions or (recursively) in their default template arguments
+ SmallVector<NamedDecl *> FPrimeTemplateParams;
+ // Store template arguments that refer to the newly-created template
+ // parameters, used for building `TemplateArgsForBuildingFPrime`.
+ SmallVector<TemplateArgument, 16> TransformedDeducedAliasArgs(
+ AliasTemplate->getTemplateParameters()->size());
+
+ for (unsigned AliasTemplateParamIdx : DeducedAliasTemplateParams) {
+ auto *TP =
+ AliasTemplate->getTemplateParameters()->getParam(AliasTemplateParamIdx);
+ // Rebuild any internal references to earlier parameters and reindex as
+ // we go.
+ MultiLevelTemplateArgumentList Args;
+ Args.setKind(TemplateSubstitutionKind::Rewrite);
+ Args.addOuterTemplateArguments(TransformedDeducedAliasArgs);
+ NamedDecl *NewParam = transformTemplateParameter(
+ SemaRef, AliasTemplate->getDeclContext(), TP, Args,
+ /*NewIndex*/ FPrimeTemplateParams.size());
----------------
hokein wrote:
Done.
https://github.com/llvm/llvm-project/pull/90894
More information about the cfe-commits
mailing list