[clang] [clang] Implement P2582R1: CTAD from inherited constructors (PR #98788)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 10 16:03:47 PDT 2024
================
@@ -1216,10 +1308,225 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
->getDeductionCandidateKind() == DeductionCandidate::Aggregate)
continue;
- BuildDeductionGuideForTypeAlias(SemaRef, AliasTemplate, F, Loc);
+ BuildDeductionGuideForTypeAlias(SemaRef, AliasTemplate, F, Loc,
+ DeducingTemplate, DerivedClassMapperType);
}
}
+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();
+ if (!BaseTD)
+ return;
+
+ // Subsitute any parameters with default arguments not present in the base,
+ // since partial specializations cannot have default parameters
+ TemplateParameterList *TemplateTPL = Pattern->getTemplateParameters();
+ auto BaseDeducedTemplateParams =
+ TemplateParamsReferencedInTemplateArgumentList(
+ TemplateTPL, BaseTST->template_arguments());
+ SmallVector<NamedDecl *, 8> PartialSpecParams;
+ SmallVector<TemplateArgument, 8> SubstArgs;
+ PartialSpecParams.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 (!BaseDeducedTemplateParams.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, PartialSpecParams.size(),
+ Template->getTemplateDepth());
+ if (!NewParam)
+ return;
+
+ PartialSpecParams.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 *PartialSpecTPL = TemplateParameterList::Create(
+ Context, TemplateTPL->getTemplateLoc(), TemplateTPL->getLAngleLoc(),
+ PartialSpecParams, TemplateTPL->getRAngleLoc(), RequiresClause);
+
+ // [over.match.class.deduct]p1.10
+ // Let A be an alias template whose template parameter list is that of
+ // [Template] and whose defining-type-id is [BaseTSI] ...
+ auto *TransformedBase =
+ SemaRef.SubstType(BaseTSI, Args, BaseLoc, DeclarationName(), true);
+ auto *BaseAD = TypeAliasDecl::Create(
+ Context, DC, SourceLocation(), BaseLoc,
+ TransformedBase->getType().getBaseTypeIdentifier(), TransformedBase);
+ std::string AliasDeclName =
+ (Twine("__ctad_alias_") + BaseTD->getName() + "_to_" +
+ Template->getName() + "_" + Twine(BaseIdx))
+ .str();
+ IdentifierInfo *AliasIdentifier = &Context.Idents.get(AliasDeclName);
+ auto *BaseATD = TypeAliasTemplateDecl::Create(
+ Context, DC, BaseLoc, DeclarationName(AliasIdentifier), PartialSpecTPL,
+ BaseAD);
+ BaseAD->setDescribedAliasTemplate(BaseATD);
+ BaseAD->setImplicit();
+ BaseATD->setImplicit();
+
+ DC->addDecl(BaseATD);
+
+ // ... given a class template `template <typename> class CC;`
+ // whose primary template is not defined ...
+ auto *TParam = TemplateTypeParmDecl::Create(
+ Context, DC, SourceLocation(), SourceLocation(),
+ Template->getTemplateDepth(), 0, nullptr, false, false);
+ TParam->setImplicit();
+ auto *MapperTPL = TemplateParameterList::Create(
+ Context, SourceLocation(), SourceLocation(),
+ ArrayRef<NamedDecl *>(TParam), SourceLocation(), nullptr);
+
+ std::string MapperDeclName =
+ (Twine("__ctad_mapper_") + BaseTD->getName() + "_to_" +
+ Template->getName() + "_" + Twine(BaseIdx))
+ .str();
+ IdentifierInfo *MapperII = &Context.Idents.get(MapperDeclName);
+ CXXRecordDecl *MapperRD = CXXRecordDecl::Create(
+ Context, CXXRecordDecl::TagKind::Struct, DC, SourceLocation(),
+ SourceLocation(), nullptr, nullptr);
+ ClassTemplateDecl *MapperTD =
+ ClassTemplateDecl::Create(Context, DC, SourceLocation(),
+ DeclarationName(MapperII), MapperTPL, MapperRD);
+ MapperRD->setDescribedClassTemplate(MapperTD);
+ MapperTD->setImplicit();
+ MapperRD->setImplicit();
+
+ DC->addDecl(MapperTD);
+
+ // ... and with a single partial specialization whose template parameter list
+ // is that of A with the template argument list of A ...
+ TemplateArgument AliasTA(TransformedBase->getType());
+ ArrayRef<TemplateArgument> TAL(AliasTA);
+ auto MapperTemplateName =
+ Context.getCanonicalTemplateName(TemplateName(MapperTD));
+ QualType CanonType =
+ Context.getTemplateSpecializationType(MapperTemplateName, TAL);
+
+ auto *MapperSpecialization = ClassTemplatePartialSpecializationDecl::Create(
+ Context, ClassTemplatePartialSpecializationDecl::TagKind::Struct, DC,
+ SourceLocation(), SourceLocation(), PartialSpecTPL, MapperTD, TAL,
----------------
antangelo wrote:
Done, I am now cloning the alias TPL and stripping default arguments from it to create a new TPL for the partial specialization.
https://github.com/llvm/llvm-project/pull/98788
More information about the cfe-commits
mailing list