Author: Haojian Wu Date: 2024-07-10T08:55:37+02:00 New Revision: 1205371a6e4b4f03aa5fee5124efd4234e279ca4
URL: https://github.com/llvm/llvm-project/commit/1205371a6e4b4f03aa5fee5124efd4234e279ca4 DIFF: https://github.com/llvm/llvm-project/commit/1205371a6e4b4f03aa5fee5124efd4234e279ca4.diff LOG: [clang] CTAD: Generate deduction guides for alias templates from non-template explicit deduction guides (#96686) This patch addresses an issue where non-template explicit deduction guides were not considered when synthesized the deduction guides for alias templates. Fixes #94927. Added: Modified: clang/lib/Sema/SemaTemplate.cpp clang/test/SemaCXX/cxx20-ctad-type-alias.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 726de9172e1cf..3d8cf750c12c1 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2307,8 +2307,12 @@ class ExtractTypeForDeductionGuide } }; -// Build a deduction guide with the specified parameter types. -FunctionTemplateDecl *buildDeductionGuide( +// Build a deduction guide using the provided information. +// +// A deduction guide can be either a template or a non-template function +// declaration. If \p TemplateParams is null, a non-template function +// declaration will be created. +NamedDecl *buildDeductionGuide( Sema &SemaRef, TemplateDecl *OriginalTemplate, TemplateParameterList *TemplateParams, CXXConstructorDecl *Ctor, ExplicitSpecifier ES, TypeSourceInfo *TInfo, SourceLocation LocStart, @@ -2334,16 +2338,21 @@ FunctionTemplateDecl *buildDeductionGuide( Param->setDeclContext(Guide); for (auto *TD : MaterializedTypedefs) TD->setDeclContext(Guide); + if (isa<CXXRecordDecl>(DC)) + Guide->setAccess(AS_public); + + if (!TemplateParams) { + DC->addDecl(Guide); + return Guide; + } auto *GuideTemplate = FunctionTemplateDecl::Create( SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide); GuideTemplate->setImplicit(IsImplicit); Guide->setDescribedFunctionTemplate(GuideTemplate); - if (isa<CXXRecordDecl>(DC)) { - Guide->setAccess(AS_public); + if (isa<CXXRecordDecl>(DC)) GuideTemplate->setAccess(AS_public); - } DC->addDecl(GuideTemplate); return GuideTemplate; @@ -2990,7 +2999,8 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef, ASTContext &Context = SemaRef.Context; // Constraint AST nodes must use uninstantiated depth. if (auto *PrimaryTemplate = - AliasTemplate->getInstantiatedFromMemberTemplate()) { + AliasTemplate->getInstantiatedFromMemberTemplate(); + PrimaryTemplate && TemplateParams.size() > 0) { LocalInstantiationScope Scope(SemaRef); // Adjust the depth for TemplateParams. @@ -3254,12 +3264,12 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, FPrimeTemplateParams, AliasTemplate->getTemplateParameters()->getRAngleLoc(), /*RequiresClause=*/RequiresClause); - FunctionTemplateDecl *Result = buildDeductionGuide( + auto *Result = cast<FunctionTemplateDecl>(buildDeductionGuide( SemaRef, AliasTemplate, FPrimeTemplateParamList, GG->getCorrespondingConstructor(), GG->getExplicitSpecifier(), GG->getTypeSourceInfo(), AliasTemplate->getBeginLoc(), AliasTemplate->getLocation(), AliasTemplate->getEndLoc(), - F->isImplicit()); + F->isImplicit())); cast<CXXDeductionGuideDecl>(Result->getTemplatedDecl()) ->setDeductionCandidateKind(GG->getDeductionCandidateKind()); return Result; @@ -3290,6 +3300,44 @@ void DeclareImplicitDeductionGuidesForTypeAlias( Guides.suppressDiagnostics(); for (auto *G : Guides) { + if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(G)) { + // The deduction guide is a non-template function decl, we just clone it. + auto *FunctionType = + SemaRef.Context.getTrivialTypeSourceInfo(DG->getType()); + FunctionProtoTypeLoc FPTL = + FunctionType->getTypeLoc().castAs<FunctionProtoTypeLoc>(); + + // Clone the parameters. + for (unsigned I = 0, N = DG->getNumParams(); I != N; ++I) { + const auto *P = DG->getParamDecl(I); + auto *TSI = SemaRef.Context.getTrivialTypeSourceInfo(P->getType()); + ParmVarDecl *NewParam = ParmVarDecl::Create( + SemaRef.Context, G->getDeclContext(), + DG->getParamDecl(I)->getBeginLoc(), P->getLocation(), nullptr, + TSI->getType(), TSI, SC_None, nullptr); + NewParam->setScopeInfo(0, I); + FPTL.setParam(I, NewParam); + } + auto *Transformed = cast<FunctionDecl>(buildDeductionGuide( + SemaRef, AliasTemplate, /*TemplateParams=*/nullptr, + /*Constructor=*/nullptr, DG->getExplicitSpecifier(), FunctionType, + AliasTemplate->getBeginLoc(), AliasTemplate->getLocation(), + AliasTemplate->getEndLoc(), DG->isImplicit())); + + // FIXME: Here the synthesized deduction guide is not a templated + // function. Per [dcl.decl]p4, the requires-clause shall be present only + // if the declarator declares a templated function, a bug in standard? + auto *Constraint = buildIsDeducibleConstraint( + SemaRef, AliasTemplate, Transformed->getReturnType(), {}); + if (auto *RC = DG->getTrailingRequiresClause()) { + auto Conjunction = + SemaRef.BuildBinOp(SemaRef.getCurScope(), SourceLocation{}, + BinaryOperatorKind::BO_LAnd, RC, Constraint); + if (!Conjunction.isInvalid()) + Constraint = Conjunction.getAs<Expr>(); + } + Transformed->setTrailingRequiresClause(Constraint); + } FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(G); if (!F) continue; diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp index a369ce687a728..2193be03ad9a3 100644 --- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp +++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp @@ -440,3 +440,44 @@ template<typename...TS> using AA = A<int, TS...>; AA a{0}; } + +namespace GH94927 { +template <typename T> +struct A { + A(T); +}; +A(int) -> A<char>; + +template <typename U> +using B1 = A<U>; +B1 b1(100); // deduce to A<char>; +static_assert(__is_same(decltype(b1), A<char>)); + +template <typename U> +requires (!__is_same(U, char)) // filter out the explicit deduction guide. +using B2 = A<U>; +template <typename V> +using B3 = B2<V>; + +B2 b2(100); // deduced to A<int>; +static_assert(__is_same(decltype(b2), A<int>)); +B3 b3(100); // decuded to A<int>; +static_assert(__is_same(decltype(b3), A<int>)); + + +// the nested case +template <typename T1> +struct Out { + template <typename T2> + struct A { + A(T2); + }; + A(int) -> A<T1>; + + template <typename T3> + using B = A<T3>; +}; + +Out<float>::B out(100); // deduced to Out<float>::A<float>; +static_assert(__is_same(decltype(out), Out<float>::A<float>)); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits