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

Reply via email to