https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/223340
>From f7ae9a62e7d82a71be4f2c1c8f153a85b0d2f2a7 Mon Sep 17 00:00:00 2001 From: Younan Zhang <[email protected]> Date: Mon, 14 Sep 2026 17:31:25 +0800 Subject: [PATCH 1/3] [Clang] Fix synthesizing of alias CTAD constraints buildAssociatedConstraints reconstructs a template parameter list relative to its primary template. However it didn't match the construction of the CTAD guide very precisely. --- clang/docs/ReleaseNotes.md | 2 ++ clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 29 ++++++++++++------- clang/test/SemaCXX/ctad.cpp | 29 +++++++++++++++++++ 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 043a0ddae2a6c..be67a1b3779d8 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -579,6 +579,8 @@ features cannot lower the translation-unit ABI level; - Fixed a crash when a using-declaration naming an unresolvable member of a dependent base was shadowed by an invalid using-declaration. (#GH209427) +- Fixed a CTAD bug when combining with concepts. (#GH124715) + - Fixed a regression where an internal-linkage function (e.g. a `static` or anonymous-namespace helper) declared in the global module fragment of the current translation unit was removed from the overload set when the calling diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 1a488ece55d25..e1000372985fc 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -998,11 +998,19 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, AliasTemplate->getInstantiatedFromMemberTemplate()) AdjustDepth = PrimaryTemplate->getTemplateDepth(); + // FIXME: We're rebuilding the synthesized template parameter list again + // Consider reuse the template parameter from its caller. + // We rebuild all template parameters with the uninstantiated depth, and // build template arguments refer to them. - SmallVector<TemplateArgument> AdjustedAliasTemplateArgs; + SmallVector<TemplateArgument> AdjustedAliasTemplateArgs( + AliasTemplate->getTemplateParameters()->size()); - for (auto *TP : *AliasTemplate->getTemplateParameters()) { + unsigned N = 0; + for (unsigned Index = 0; Index != AdjustedAliasTemplateArgs.size(); ++Index) { + if (DeduceResults[Index].isNull()) + continue; + auto *TP = AliasTemplate->getTemplateParameters()->getParam(Index); // Rebuild any internal references to earlier parameters and reindex // as we go. MultiLevelTemplateArgumentList Args; @@ -1010,21 +1018,22 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, Args.addOuterTemplateArguments(AdjustedAliasTemplateArgs); NamedDecl *NewParam = transformTemplateParameter( SemaRef, AliasTemplate->getDeclContext(), TP, Args, - /*NewIndex=*/AdjustedAliasTemplateArgs.size(), - getDepthAndIndex(TP).first + AdjustDepth); + /*NewIndex=*/N++, getDepthAndIndex(TP).first + AdjustDepth); TemplateArgument NewTemplateArgument = Context.getInjectedTemplateArg(NewParam); - AdjustedAliasTemplateArgs.push_back(NewTemplateArgument); + AdjustedAliasTemplateArgs[Index] = NewTemplateArgument; } + assert(FirstUndeducedParamIdx == N); + // Template arguments used to transform the template arguments in // DeducedResults. SmallVector<TemplateArgument> TemplateArgsForBuildingRC( F->getTemplateParameters()->size()); // Transform the transformed template args - MultiLevelTemplateArgumentList Args; - Args.setKind(TemplateSubstitutionKind::Rewrite); - Args.addOuterTemplateArguments(AdjustedAliasTemplateArgs); + MultiLevelTemplateArgumentList ArgsForDeducedParams; + ArgsForDeducedParams.setKind(TemplateSubstitutionKind::Rewrite); + ArgsForDeducedParams.addOuterTemplateArguments(AdjustedAliasTemplateArgs); for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) { const auto &D = DeduceResults[Index]; @@ -1047,7 +1056,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{}); TemplateArgumentLoc Output; - if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) { + if (!SemaRef.SubstTemplateArgument(Input, ArgsForDeducedParams, Output)) { assert(TemplateArgsForBuildingRC[Index].isNull() && "InstantiatedArgs must be null before setting"); TemplateArgsForBuildingRC[Index] = Output.getArgument(); @@ -1119,7 +1128,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, Expr *buildIsDeducibleConstraint(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate, QualType ReturnType, - SmallVector<NamedDecl *> TemplateParams) { + ArrayRef<NamedDecl *> TemplateParams) { ASTContext &Context = SemaRef.Context; // Constraint AST nodes must use uninstantiated depth. if (auto *PrimaryTemplate = diff --git a/clang/test/SemaCXX/ctad.cpp b/clang/test/SemaCXX/ctad.cpp index 2a4e1c571ac5c..6517e88a8a831 100644 --- a/clang/test/SemaCXX/ctad.cpp +++ b/clang/test/SemaCXX/ctad.cpp @@ -197,3 +197,32 @@ namespace GH131342 { template <class T> using AA = A<T, val<T>>; AA a{0}; } // namespace GH131342 + +namespace GH124715_2 { + +template <class F, class... Args> +using invoke_result_t = decltype(F()(Args()...)); + +template <class F, class... Args> +invoke_result_t<F, Args...> invoke(F f, Args... args); + +template <class F, class... Args> +concept invocable = requires(F f, Args... args) { + invoke(f, args...); +}; + +template <class Ret, class... Args> +struct A { + A(auto&&...) {} +}; + +template <class Lambda, class... Args> + requires invocable<Lambda, Args...> +A(Lambda, Args...) -> A<invoke_result_t<Lambda, Args...>, Args...>; + +template <class T, class... Ts> +using AliasName = A<T, Ts...>; + +AliasName aa([](int){}, 0); + +} >From dec9c601da34631af5d8989bcfaed628d7cd2030 Mon Sep 17 00:00:00 2001 From: Younan Zhang <[email protected]> Date: Tue, 15 Sep 2026 16:39:52 +0800 Subject: [PATCH 2/3] Remove FIXME --- clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index e1000372985fc..5f656c01083d2 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -998,9 +998,6 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, AliasTemplate->getInstantiatedFromMemberTemplate()) AdjustDepth = PrimaryTemplate->getTemplateDepth(); - // FIXME: We're rebuilding the synthesized template parameter list again - // Consider reuse the template parameter from its caller. - // We rebuild all template parameters with the uninstantiated depth, and // build template arguments refer to them. SmallVector<TemplateArgument> AdjustedAliasTemplateArgs( >From 8d6208ad2b3d9ff161161b476d8b5b8e8faf1812 Mon Sep 17 00:00:00 2001 From: Younan Zhang <[email protected]> Date: Tue, 15 Sep 2026 16:58:27 +0800 Subject: [PATCH 3/3] Really match how BuildDeductionGuideForTypeAlias works --- clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 5f656c01083d2..fa0918ae30282 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -956,6 +956,19 @@ llvm::DenseSet<const NamedDecl *> getSourceDeductionGuides(DeclarationName Name, return Result; } +bool IsNonDeducedArgument(const TemplateArgument &TA) { + // The following cases indicate the template argument is non-deducible: + // 1. The result is null. E.g. When it comes from a default template + // argument that doesn't appear in the alias declaration. + // 2. The template parameter is a pack and that cannot be deduced from + // the arguments within the alias declaration. + // Non-deducible template parameters will persist in the transformed + // deduction guide. + return TA.isNull() || + (TA.getKind() == TemplateArgument::Pack && + llvm::any_of(TA.pack_elements(), IsNonDeducedArgument)); +} + // Build the associated constraints for the alias deduction guides. // C++ [over.match.class.deduct]p3.3: // The associated constraints ([temp.constr.decl]) are the conjunction of the @@ -968,7 +981,8 @@ Expr * buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, TypeAliasTemplateDecl *AliasTemplate, ArrayRef<DeducedTemplateArgument> DeduceResults, - unsigned FirstUndeducedParamIdx, Expr *IsDeducible) { + ArrayRef<unsigned> DeducedAliasTemplateParams, + Expr *IsDeducible) { Expr *RC = F->getTemplateParameters()->getRequiresClause(); if (!RC) return IsDeducible; @@ -1004,9 +1018,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, AliasTemplate->getTemplateParameters()->size()); unsigned N = 0; - for (unsigned Index = 0; Index != AdjustedAliasTemplateArgs.size(); ++Index) { - if (DeduceResults[Index].isNull()) - continue; + for (unsigned Index : DeducedAliasTemplateParams) { auto *TP = AliasTemplate->getTemplateParameters()->getParam(Index); // Rebuild any internal references to earlier parameters and reindex // as we go. @@ -1021,7 +1033,6 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, Context.getInjectedTemplateArg(NewParam); AdjustedAliasTemplateArgs[Index] = NewTemplateArgument; } - assert(FirstUndeducedParamIdx == N); // Template arguments used to transform the template arguments in // DeducedResults. @@ -1034,17 +1045,15 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) { const auto &D = DeduceResults[Index]; - if (D.isNull()) { // non-deduced template parameters of f + if (IsNonDeducedArgument(D)) { // non-deduced template parameters of f NamedDecl *TP = F->getTemplateParameters()->getParam(Index); MultiLevelTemplateArgumentList Args; Args.setKind(TemplateSubstitutionKind::Rewrite); Args.addOuterTemplateArguments(TemplateArgsForBuildingRC); // Rebuild the template parameter with updated depth and index. - NamedDecl *NewParam = - transformTemplateParameter(SemaRef, F->getDeclContext(), TP, Args, - /*NewIndex=*/FirstUndeducedParamIdx, - getDepthAndIndex(TP).first + AdjustDepth); - FirstUndeducedParamIdx += 1; + NamedDecl *NewParam = transformTemplateParameter( + SemaRef, F->getDeclContext(), TP, Args, + /*NewIndex=*/N++, getDepthAndIndex(TP).first + AdjustDepth); assert(TemplateArgsForBuildingRC[Index].isNull()); TemplateArgsForBuildingRC[Index] = Context.getInjectedTemplateArg(NewParam); @@ -1203,19 +1212,6 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) { return {Template, AliasRhsTemplateArgs}; } -bool IsNonDeducedArgument(const TemplateArgument &TA) { - // The following cases indicate the template argument is non-deducible: - // 1. The result is null. E.g. When it comes from a default template - // argument that doesn't appear in the alias declaration. - // 2. The template parameter is a pack and that cannot be deduced from - // the arguments within the alias declaration. - // Non-deducible template parameters will persist in the transformed - // deduction guide. - return TA.isNull() || - (TA.getKind() == TemplateArgument::Pack && - llvm::any_of(TA.pack_elements(), IsNonDeducedArgument)); -} - // Build deduction guides for a type alias template from the given underlying // source deduction guide. CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias( @@ -1362,7 +1358,6 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias( Context.getInjectedTemplateArg(NewParam); TransformedDeducedAliasArgs[AliasTemplateParamIdx] = NewTemplateArgument; } - unsigned FirstUndeducedParamIdx = FPrimeTemplateParams.size(); // To form a deduction guide f' from f, we leverage clang's instantiation // mechanism, we construct a template argument list where the template @@ -1453,7 +1448,7 @@ CXXDeductionGuideDecl *BuildDeductionGuideForTypeAlias( SemaRef, AliasTemplate, FPrime->getReturnType(), FPrimeTemplateParams); Expr *RequiresClause = buildAssociatedConstraints(SemaRef, F, AliasTemplate, DeduceResults, - FirstUndeducedParamIdx, IsDeducible); + DeducedAliasTemplateParams, IsDeducible); TemplateParameterList *FPrimeTemplateParamList = nullptr; if (!FPrimeTemplateParams.empty()) @@ -1519,11 +1514,11 @@ void DeclareImplicitDeductionGuidesForTypeAlias( NewParam->setScopeInfo(0, I); FPTL.setParam(I, NewParam); } - auto *Transformed = cast<CXXDeductionGuideDecl>(buildDeductionGuide( + auto *Transformed = buildDeductionGuide( SemaRef, AliasTemplate, /*TemplateParams=*/nullptr, /*Constructor=*/nullptr, DG->getExplicitSpecifier(), FunctionType, AliasTemplate->getBeginLoc(), AliasTemplate->getLocation(), - AliasTemplate->getEndLoc(), DG->isImplicit())); + AliasTemplate->getEndLoc(), DG->isImplicit()); Transformed->setSourceDeductionGuide(DG); Transformed->setSourceDeductionGuideKind( CXXDeductionGuideDecl::SourceDeductionGuideKind::Alias); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
