[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