================ @@ -1203,10 +1333,291 @@ void DeclareImplicitDeductionGuidesForTypeAlias( ->getDeductionCandidateKind() == DeductionCandidate::Aggregate) continue; - BuildDeductionGuideForTypeAlias(SemaRef, AliasTemplate, F, Loc); + BuildDeductionGuideForTypeAlias(SemaRef, AliasTemplate, F, Loc, + FromInheritedCtor); } } +// Check if a template is deducible as per [dcl.type.simple]p3 +static bool IsDeducibleTemplate(TemplateDecl *TD) { + while (TD) { + // [dcl.type.simple]p3: A deducible template is either a class template ... + if (isa<ClassTemplateDecl>(TD)) + return true; + + // ... or is an alias template ... + auto *Alias = dyn_cast<TypeAliasTemplateDecl>(TD); + if (!Alias) + return false; + + QualType AliasType = + Alias->getTemplatedDecl()->getUnderlyingType().getCanonicalType(); + + // ... whose defining-type-id is of the form + // [typename] [nested-name-specifier] [template] simple-template-id ... + if (const auto *TST = AliasType->getAs<TemplateSpecializationType>()) { + // ... and the template-name of the simple-template-id names a deducible + // template + TD = TST->getTemplateName().getAsTemplateDecl(); + continue; + } + + // Handle the case that the RHS of the alias is not dependent + // e.g. using AliasFoo = Foo<bool>; + if (const auto *RT = AliasType->getAs<RecordType>()) + return isa<ClassTemplateSpecializationDecl>(RT->getAsCXXRecordDecl()); + + return false; + } + + return false; +} + +void DeclareImplicitDeductionGuidesFromInheritedConstructors( + Sema &SemaRef, TemplateDecl *Template, ClassTemplateDecl *Pattern, + TypeSourceInfo *BaseTSI, unsigned BaseIdx) { + auto &Context = SemaRef.Context; + DeclContext *DC = Template->getDeclContext(); + const auto *BaseTST = BaseTSI->getType()->getAs<TemplateSpecializationType>(); + if (!BaseTST) + return; + SourceLocation BaseLoc = BaseTSI->getTypeLoc().getBeginLoc(); + + TemplateDecl *BaseTD = BaseTST->getTemplateName().getAsTemplateDecl(); + + // The alias template `A` that we build out of the base type must be a + // deducible template. `A` will be of the correct form, so it is deducible iff + // BaseTD is deducible + if (!BaseTD || !IsDeducibleTemplate(BaseTD)) + return; + + // Substitute any parameters with default arguments not present in the base, + // since partial specializations cannot have default parameters + // See https://github.com/cplusplus/CWG/issues/627 + TemplateParameterList *TemplateTPL = Pattern->getTemplateParameters(); + SmallVector<unsigned int> BaseDeducedTemplateParamsList = + TemplateParamsReferencedInTemplateArgumentList( + TemplateTPL, BaseTST->template_arguments()); + llvm::SmallSet<unsigned int, 8> BaseDeducedTemplateParamsSet( + BaseDeducedTemplateParamsList.begin(), + BaseDeducedTemplateParamsList.end()); + SmallVector<NamedDecl *, 8> AliasTemplateParams; + SmallVector<TemplateArgument, 8> SubstArgs; + AliasTemplateParams.reserve(TemplateTPL->size()); + SubstArgs.reserve(TemplateTPL->size()); + LocalInstantiationScope Scope(SemaRef); + for (unsigned I = 0, N = TemplateTPL->size(); I < N; ++I) { + NamedDecl *Param = TemplateTPL->getParam(I); + if (!BaseDeducedTemplateParamsSet.contains(I)) { + if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param); + TTP && TTP->hasDefaultArgument()) { + SubstArgs.push_back(TTP->getDefaultArgument().getArgument()); + continue; + } + + if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param); + NTTP && NTTP->hasDefaultArgument()) { + SubstArgs.push_back(NTTP->getDefaultArgument().getArgument()); + continue; + } + + if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param); + TTP && TTP->hasDefaultArgument()) { + SubstArgs.push_back(TTP->getDefaultArgument().getArgument()); + continue; + } + + // We have a template parameter that is not present in the base + // and does not have a default argument. We create the deduction + // guide anyway to display a diagnostic. + } + + MultiLevelTemplateArgumentList Args; + Args.setKind(TemplateSubstitutionKind::Rewrite); + Args.addOuterTemplateArguments(SubstArgs); + Args.addOuterRetainedLevels(Template->getTemplateDepth()); + + NamedDecl *NewParam = transformTemplateParameter( + SemaRef, DC, Param, Args, AliasTemplateParams.size(), + Template->getTemplateDepth()); + if (!NewParam) + return; + + AliasTemplateParams.push_back(NewParam); + SubstArgs.push_back(Context.getInjectedTemplateArg(NewParam)); + } + + Expr *RequiresClause = nullptr; + MultiLevelTemplateArgumentList Args; + Args.setKind(TemplateSubstitutionKind::Rewrite); + Args.addOuterTemplateArguments(SubstArgs); + Args.addOuterRetainedLevels(Template->getTemplateDepth()); + if (Expr *TemplateRC = TemplateTPL->getRequiresClause()) { + ExprResult E = SemaRef.SubstExpr(TemplateRC, Args); + if (E.isInvalid()) + return; + RequiresClause = E.getAs<Expr>(); + } + auto *AliasTPL = TemplateParameterList::Create( + Context, TemplateTPL->getTemplateLoc(), TemplateTPL->getLAngleLoc(), + AliasTemplateParams, TemplateTPL->getRAngleLoc(), RequiresClause); + + // Clone AliasTPL into a new parameter list for the partial specialization, + // but with default arguments removed, using the template instantiator + // for heavy lifting. + LocalInstantiationScope CloneScope(SemaRef); + MultiLevelTemplateArgumentList CloneArgs; + CloneArgs.setKind(TemplateSubstitutionKind::Rewrite); + CloneArgs.addOuterRetainedLevels(Template->getTemplateDepth()); + TemplateDeclInstantiator CloneTDI(SemaRef, DC, CloneArgs); + TemplateParameterList *PartialSpecTPL = + CloneTDI.SubstTemplateParams(AliasTPL); + CloneScope.Exit(); + for (NamedDecl *Param : *PartialSpecTPL) { + if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { + TTP->removeDefaultArgument(); + } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + NTTP->removeDefaultArgument(); + } else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) { + TTP->removeDefaultArgument(); + } ---------------- antangelo wrote:
Fixed https://github.com/llvm/llvm-project/pull/98788 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits