https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/161035
>From eba5a86714873b45d0c3b8d00af57e96a705644f Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Sun, 28 Sep 2025 10:40:26 +0800 Subject: [PATCH 1/3] [Clang] Ensure initialized NTTP expressions when building CTAD for type aliases We missed calling CheckTemplateArgument when building CTAD deduction guides. That ensures some InitExprs are correctly initialized, as in the test that crashed due to incorrect NTTP initialization. We don't use CheckTemplateArguments because, in CTAD synthesis, template parameter packs don't always appear at the end of the parameter list, unlike user-written ones mandated by the standard. This makes it difficult for CheckTemplateArguments to determine how many arguments a pack should match, leading to unnecessary complexity. On the other hand, since we substitute non-deduced template parameters with deduced ones, we need to fold the packs midway through substitution, where CheckTemplateArgument is more convenient. As a drive-by this also removes some dead code in SemaInit. --- clang/docs/ReleaseNotes.rst | 2 +- clang/lib/Sema/SemaInit.cpp | 5 +-- clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 42 +++++++++++++++++-- clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 18 ++++++++ 4 files changed, 59 insertions(+), 8 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 98c889c08b329..888b202c538de 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -361,7 +361,7 @@ Bug Fixes in This Version first parameter. (#GH113323). - Fixed a crash with incompatible pointer to integer conversions in designated initializers involving string literals. (#GH154046) -- Fix crash on CTAD for alias template. (#GH131342) +- Fix crash on CTAD for alias template. (#GH131342), (#GH131408) - Clang now emits a frontend error when a function marked with the `flatten` attribute calls another function that requires target features not enabled in the caller. This prevents a fatal error in the backend. diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index c97129336736b..0d0d2c00eb5d4 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8219,8 +8219,8 @@ ExprResult InitializationSequence::Perform(Sema &S, // InitializeTemporary entity for our target type. QualType Ty = Step->Type; bool IsTemporary = !S.Context.hasSameType(Entity.getType(), Ty); - InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty); - InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity; + InitializedEntity InitEntity = + IsTemporary ? InitializedEntity::InitializeTemporary(Ty) : Entity; InitListChecker PerformInitList(S, InitEntity, InitList, Ty, /*VerifyOnly=*/false, /*TreatUnavailableAsInvalid=*/false); @@ -8242,7 +8242,6 @@ ExprResult InitializationSequence::Perform(Sema &S, InitListExpr *StructuredInitList = PerformInitList.getFullyStructuredList(); - CurInit.get(); CurInit = shouldBindAsTemporary(InitEntity) ? S.MaybeBindToTemporary(StructuredInitList) : StructuredInitList; diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 3d54d1eb4373a..451ec3754ca70 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -1171,17 +1171,38 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, Args.addOuterTemplateArguments(TransformedDeducedAliasArgs); for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) { const auto &D = DeduceResults[Index]; + auto *TP = F->getTemplateParameters()->getParam(Index); if (IsNonDeducedArgument(D)) { // 2): Non-deduced template parameters would be substituted later. continue; } TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{}); - TemplateArgumentLoc Output; - if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) { + TemplateArgumentListInfo Output; + if (!SemaRef.SubstTemplateArguments(Input, Args, Output)) { assert(TemplateArgsForBuildingFPrime[Index].isNull() && "InstantiatedArgs must be null before setting"); - TemplateArgsForBuildingFPrime[Index] = Output.getArgument(); + Sema::CheckTemplateArgumentInfo CTAI; + if (Input.getArgument().getKind() == TemplateArgument::Pack) { + for (auto TA : Output.arguments()) { + if (SemaRef.CheckTemplateArgument( + TP, TA, F, F->getLocation(), F->getLocation(), + /*ArgumentPackIndex=*/-1, CTAI, + Sema::CheckTemplateArgumentKind::CTAK_Specified)) + return nullptr; + } + TemplateArgsForBuildingFPrime[Index] = + TemplateArgument::CreatePackCopy(Context, CTAI.SugaredConverted); + } else { + assert(Output.arguments().size() == 1); + TemplateArgumentLoc Transformed = Output.arguments()[0]; + if (SemaRef.CheckTemplateArgument( + TP, Transformed, F, F->getLocation(), F->getLocation(), + /*ArgumentPackIndex=*/-1, CTAI, + Sema::CheckTemplateArgumentKind::CTAK_Specified)) + return nullptr; + TemplateArgsForBuildingFPrime[Index] = CTAI.SugaredConverted[0]; + } } } @@ -1202,8 +1223,21 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() && "The argument must be null before setting"); + TemplateArgument Transformed = Context.getInjectedTemplateArg(NewParam); + if (NewParam->isTemplateParameterPack()) + Transformed = *Transformed.pack_begin(); + TemplateArgumentLoc TALoc = SemaRef.getTrivialTemplateArgumentLoc( + Transformed, QualType(), NewParam->getBeginLoc()); + Sema::CheckTemplateArgumentInfo CTAI; + if (SemaRef.CheckTemplateArgument( + TP, TALoc, F, F->getLocation(), F->getLocation(), + /*ArgumentPackIndex=*/-1, CTAI, + Sema::CheckTemplateArgumentKind::CTAK_Specified)) + return nullptr; TemplateArgsForBuildingFPrime[FTemplateParamIdx] = - Context.getInjectedTemplateArg(NewParam); + NewParam->isTemplateParameterPack() + ? TemplateArgument::CreatePackCopy(Context, CTAI.SugaredConverted) + : CTAI.SugaredConverted[0]; } auto *TemplateArgListForBuildingFPrime = diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp index 2f1817d0ca7eb..d7ce966f46060 100644 --- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp +++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp @@ -586,3 +586,21 @@ Baz a{}; static_assert(__is_same(decltype(a), A<A<int>>)); } // namespace GH133132 + +namespace GH131408 { + +struct Node {}; + +template <class T, Node> +struct A { + A(T) {} +}; + +template <class T> +using AA = A<T, {}>; + +AA a{0}; + +static_assert(__is_same(decltype(a), A<int, Node{}>)); + +} >From 6e11a6fcdf3b8271cb549e097bb1a934b9c940e7 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 30 Sep 2025 07:53:49 +0800 Subject: [PATCH 2/3] No need to check conversions for non-deduced parameters --- clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 451ec3754ca70..39752d8fc5dd0 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -1223,21 +1223,8 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() && "The argument must be null before setting"); - TemplateArgument Transformed = Context.getInjectedTemplateArg(NewParam); - if (NewParam->isTemplateParameterPack()) - Transformed = *Transformed.pack_begin(); - TemplateArgumentLoc TALoc = SemaRef.getTrivialTemplateArgumentLoc( - Transformed, QualType(), NewParam->getBeginLoc()); - Sema::CheckTemplateArgumentInfo CTAI; - if (SemaRef.CheckTemplateArgument( - TP, TALoc, F, F->getLocation(), F->getLocation(), - /*ArgumentPackIndex=*/-1, CTAI, - Sema::CheckTemplateArgumentKind::CTAK_Specified)) - return nullptr; TemplateArgsForBuildingFPrime[FTemplateParamIdx] = - NewParam->isTemplateParameterPack() - ? TemplateArgument::CreatePackCopy(Context, CTAI.SugaredConverted) - : CTAI.SugaredConverted[0]; + Context.getInjectedTemplateArg(NewParam); } auto *TemplateArgListForBuildingFPrime = >From 349f172b009fa6166fb6c529bd778684fafe5c24 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Thu, 2 Oct 2025 13:15:53 +0800 Subject: [PATCH 3/3] Apply Matheus's feedback --- clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 39752d8fc5dd0..d1a2d531eecf3 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -1179,30 +1179,38 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{}); TemplateArgumentListInfo Output; - if (!SemaRef.SubstTemplateArguments(Input, Args, Output)) { - assert(TemplateArgsForBuildingFPrime[Index].isNull() && - "InstantiatedArgs must be null before setting"); - Sema::CheckTemplateArgumentInfo CTAI; - if (Input.getArgument().getKind() == TemplateArgument::Pack) { - for (auto TA : Output.arguments()) { - if (SemaRef.CheckTemplateArgument( - TP, TA, F, F->getLocation(), F->getLocation(), - /*ArgumentPackIndex=*/-1, CTAI, - Sema::CheckTemplateArgumentKind::CTAK_Specified)) - return nullptr; - } - TemplateArgsForBuildingFPrime[Index] = - TemplateArgument::CreatePackCopy(Context, CTAI.SugaredConverted); - } else { - assert(Output.arguments().size() == 1); - TemplateArgumentLoc Transformed = Output.arguments()[0]; + if (SemaRef.SubstTemplateArguments(Input, Args, Output)) + return nullptr; + assert(TemplateArgsForBuildingFPrime[Index].isNull() && + "InstantiatedArgs must be null before setting"); + // CheckTemplateArgument is necessary for NTTP initializations. + // FIXME: We may want to call CheckTemplateArguments instead, but we cannot + // match packs as usual, since packs can appear in the middle of the + // parameter list of a synthesized CTAD guide. See also the FIXME in + // test/SemaCXX/cxx20-ctad-type-alias.cpp:test25. + Sema::CheckTemplateArgumentInfo CTAI; + if (Input.getArgument().getKind() == TemplateArgument::Pack) { + for (auto TA : Output.arguments()) { if (SemaRef.CheckTemplateArgument( - TP, Transformed, F, F->getLocation(), F->getLocation(), + TP, TA, F, F->getLocation(), F->getLocation(), /*ArgumentPackIndex=*/-1, CTAI, Sema::CheckTemplateArgumentKind::CTAK_Specified)) return nullptr; - TemplateArgsForBuildingFPrime[Index] = CTAI.SugaredConverted[0]; } + // We will substitute the non-deduced template arguments with these + // transformed (unpacked at this point) arguments, where that substitution + // requires a pack for the corresponding parameter packs. + TemplateArgsForBuildingFPrime[Index] = + TemplateArgument::CreatePackCopy(Context, CTAI.SugaredConverted); + } else { + assert(Output.arguments().size() == 1); + TemplateArgumentLoc Transformed = Output.arguments()[0]; + if (SemaRef.CheckTemplateArgument( + TP, Transformed, F, F->getLocation(), F->getLocation(), + /*ArgumentPackIndex=*/-1, CTAI, + Sema::CheckTemplateArgumentKind::CTAK_Specified)) + return nullptr; + TemplateArgsForBuildingFPrime[Index] = CTAI.SugaredConverted[0]; } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits