================ @@ -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()); ---------------- shafik wrote:
```suggestion /*NewIndex=*/FPrimeTemplateParams.size()); ``` nitpick https://github.com/llvm/llvm-project/pull/90894 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits