================ @@ -2612,44 +2671,309 @@ struct ConvertConstructorToDeductionGuideTransform { SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParam, NewParam); return NewParam; } +}; - FunctionTemplateDecl *buildDeductionGuide( - TemplateParameterList *TemplateParams, CXXConstructorDecl *Ctor, - ExplicitSpecifier ES, TypeSourceInfo *TInfo, SourceLocation LocStart, - SourceLocation Loc, SourceLocation LocEnd, - llvm::ArrayRef<TypedefNameDecl *> MaterializedTypedefs = {}) { - DeclarationNameInfo Name(DeductionGuideName, Loc); - ArrayRef<ParmVarDecl *> Params = - TInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(); +// Find all template parameters of the AliasTemplate that appear in the +// given DeducedArgs. +SmallVector<unsigned> +FindAppearedTemplateParamsInAlias(ArrayRef<TemplateArgument> DeducedArgs, + TypeAliasTemplateDecl *AliasTemplate) { + struct FindAppearedTemplateParams + : public RecursiveASTVisitor<FindAppearedTemplateParams> { + llvm::DenseSet<NamedDecl *> TemplateParamsInAlias; + llvm::DenseSet<const NamedDecl *> AppearedTemplateParams; + + FindAppearedTemplateParams(ArrayRef<NamedDecl *> TemplateParamsInAlias) + : TemplateParamsInAlias(TemplateParamsInAlias.begin(), + TemplateParamsInAlias.end()) {} + + bool VisitTemplateTypeParmType(TemplateTypeParmType *TTP) { + TTP->getIndex(); + MarkAppeared(TTP->getDecl()); + return true; + } + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + MarkAppeared(DRE->getFoundDecl()); + return true; + } - // Build the implicit deduction guide template. - auto *Guide = - CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, ES, Name, - TInfo->getType(), TInfo, LocEnd, Ctor); - Guide->setImplicit(); - Guide->setParams(Params); + void MarkAppeared(NamedDecl *ND) { + if (TemplateParamsInAlias.contains(ND)) + AppearedTemplateParams.insert(ND); + } + }; + ArrayRef<NamedDecl *> TemplateParamsInAlias = + AliasTemplate->getTemplateParameters()->asArray(); + FindAppearedTemplateParams MarkAppeared(TemplateParamsInAlias); + MarkAppeared.TraverseTemplateArguments(DeducedArgs); - for (auto *Param : Params) - Param->setDeclContext(Guide); - for (auto *TD : MaterializedTypedefs) - TD->setDeclContext(Guide); + SmallVector<unsigned> Results; + for (unsigned Index = 0; Index < TemplateParamsInAlias.size(); ++Index) { + if (MarkAppeared.AppearedTemplateParams.contains( + TemplateParamsInAlias[Index])) + Results.push_back(Index); + } + return Results; +} - auto *GuideTemplate = FunctionTemplateDecl::Create( - SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide); - GuideTemplate->setImplicit(); - Guide->setDescribedFunctionTemplate(GuideTemplate); +bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext* DC) { + // Check whether we've already declared deduction guides for this template. + // FIXME: Consider storing a flag on the template to indicate this. + auto Existing = DC->lookup(Name); + for (auto *D : Existing) + if (D->isImplicit()) + return true; + return false; +} - if (isa<CXXRecordDecl>(DC)) { - Guide->setAccess(AS_public); - GuideTemplate->setAccess(AS_public); +// Build deduction guides for a type alias template. +void DeclareImplicitDeductionGuidesForTypeAlias( + Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, SourceLocation Loc) { + auto &Context = SemaRef.Context; + // FIXME: if there is an explicit deduction guide after the first use of the + // type alias usage, we will not cover this explicit deduction guide. fix this + // case. + if (hasDeclaredDeductionGuides( + Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate), + AliasTemplate->getDeclContext())) + return; + // Unrap the sugar ElaboratedType. + auto RhsType = AliasTemplate->getTemplatedDecl() + ->getUnderlyingType() + .getSingleStepDesugaredType(Context); + TemplateDecl *Template = nullptr; + llvm::ArrayRef<TemplateArgument> AliasRhsTemplateArgs; + if (const auto *TST = RhsType->getAs<TemplateSpecializationType>()) { + // TemplateName in TEST can be a TypeAliasTemplateDecl if + // the right hand side of the alias is also a type alias, e.g. + // + // template<typename T> + // using AliasFoo1 = Foo<T>; // Foo<T> is a class template + // specialization + // + // template<typename T> + // using AliasFoo2 = AliasFoo1<T>; // AliasFoo1<T> is a type alias + Template = TST->getTemplateName().getAsTemplateDecl(); + AliasRhsTemplateArgs = TST->template_arguments(); + } else if (const auto *RT = RhsType->getAs<RecordType>()) { + // Cases where template arguments in the RHS of the alias are not + // dependent. e.g. + // using AliasFoo = Foo<bool>; + if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>( + RT->getAsCXXRecordDecl())) { + Template = CTSD->getSpecializedTemplate(); + AliasRhsTemplateArgs = CTSD->getTemplateArgs().asArray(); + } + } + if (!Template) + return; + DeclarationNameInfo NameInfo( + Context.DeclarationNames.getCXXDeductionGuideName(Template), Loc); + LookupResult Guides(SemaRef, NameInfo, clang::Sema::LookupOrdinaryName); + SemaRef.LookupQualifiedName(Guides, Template->getDeclContext()); + Guides.suppressDiagnostics(); + + for (auto *G : Guides) { + FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(G); + if (!F) + continue; + 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); + // 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 parameter, extend it to continue performing + // deduction for rest of parameters. + 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 = + FindAppearedTemplateParamsInAlias(DeducedArgs, AliasTemplate); + // All template arguments null by default. + SmallVector<TemplateArgument> TemplateArgsForBuildingFPrime( + F->getTemplateParameters()->size()); + + Sema::InstantiatingTemplate BuildingDeductionGuides( + SemaRef, AliasTemplate->getLocation(), F, + Sema::InstantiatingTemplate::BuildingDeductionGuidesTag{}); + if (BuildingDeductionGuides.isInvalid()) + return; + LocalInstantiationScope Scope(SemaRef); + + // 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()); + auto TransformTemplateParameter = + [&SemaRef](DeclContext *DC, NamedDecl *TemplateParam, + MultiLevelTemplateArgumentList &Args, + unsigned NewIndex) -> NamedDecl * { + if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam)) + return transformTemplateTypeParam(SemaRef, DC, TTP, Args, + TTP->getDepth(), NewIndex); + if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam)) + return transformTemplateParam(SemaRef, DC, TTP, Args, NewIndex, + TTP->getDepth()); + if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TemplateParam)) + return transformTemplateParam(SemaRef, DC, NTTP, Args, NewIndex, + NTTP->getDepth()); ---------------- cor3ntin wrote:
Can we put that in a function? https://github.com/llvm/llvm-project/pull/77890 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits