[clang] [clang] Implement CTAD for type alias template. (PR #77890)
Haojian Wu via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 26 10:54:12 PST 2024
================
@@ -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();
+ }
----------------
hokein wrote:
Done.
https://github.com/llvm/llvm-project/pull/77890
More information about the cfe-commits
mailing list