https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/161035
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. I 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 in middle 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. Fixes #131408 >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] [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{}>)); + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits