Skip to content

Conversation

zyn0217
Copy link
Contributor

@zyn0217 zyn0217 commented Sep 28, 2025

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

…pe 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.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Sep 28, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 28, 2025

@llvm/pr-subscribers-clang

Author: Younan Zhang (zyn0217)

Changes

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


Full diff: https://github.com/llvm/llvm-project/pull/161035.diff

4 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1-1)
  • (modified) clang/lib/Sema/SemaInit.cpp (+2-3)
  • (modified) clang/lib/Sema/SemaTemplateDeductionGuide.cpp (+38-4)
  • (modified) clang/test/SemaCXX/cxx20-ctad-type-alias.cpp (+18)
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{}>));
+
+}

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@zyn0217 zyn0217 requested a review from mizvekov October 2, 2025 05:16
Copy link
Contributor

@mizvekov mizvekov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Thanks!

@zyn0217 zyn0217 enabled auto-merge (squash) October 3, 2025 05:57
@zyn0217 zyn0217 merged commit e0eb7c2 into llvm:main Oct 3, 2025
10 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 3, 2025

LLVM Buildbot has detected a new failure on builder bolt-aarch64-ubuntu-clang running on bolt-worker-aarch64 while building clang at step 5 "build-clang-bolt".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/128/builds/7471

Here is the relevant piece of the build log for the reference
Step 5 (build-clang-bolt) failure: build (failure)
...
36.786 [8/2/3328] Linking CXX static library lib/libclangIndex.a
36.824 [6/3/3329] Linking CXX static library lib/libclangCrossTU.a
36.846 [5/3/3330] Linking CXX static library lib/libclangExtractAPI.a
36.966 [5/2/3331] Linking CXX static library lib/libclangStaticAnalyzerCore.a
37.311 [4/2/3332] Linking CXX static library lib/libclangCodeGen.a
37.634 [4/1/3333] Linking CXX static library lib/libclangStaticAnalyzerCheckers.a
37.683 [3/1/3334] Linking CXX static library lib/libclangStaticAnalyzerFrontend.a
37.720 [2/1/3335] Linking CXX static library lib/libclangFrontendTool.a
38.545 [1/1/3336] Linking CXX executable bin/clang-22
179.125 [0/1/3337] Creating executable symlink bin/clang
FAILED: bin/clang 
/usr/bin/cmake -E cmake_symlink_executable bin/clang-22 bin/clang && cd /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/tools/clang/tools/driver && /usr/bin/cmake -E create_symlink clang-22 /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/./bin/clang++ && cd /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/tools/clang/tools/driver && /usr/bin/cmake -E create_symlink clang-22 /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/./bin/clang-cl && cd /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/tools/clang/tools/driver && /usr/bin/cmake -E create_symlink clang-22 /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/./bin/clang-cpp && cd /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/tools/clang/tools/driver && /usr/bin/python3 /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/llvm-project/clang/tools/driver/../../utils/perf-training/perf-helper.py bolt-optimize --method INSTRUMENT --input /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/bin/clang-22 --instrumented-output /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/./bin/clang-bolt.inst --fdata /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/tools/clang/tools/driver/../../utils/perf-training/prof.fdata --perf-training-binary-dir /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/tools/clang/tools/driver/../../utils/perf-training --readelf /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/bin/llvm-readobj --bolt /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/bin/llvm-bolt --lit /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/./bin/llvm-lit --merge-fdata /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/bin/merge-fdata
Running: /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/bin/llvm-bolt /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/bin/clang-22 -o /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/./bin/clang-bolt.inst -instrument --instrumentation-file-append-pid --instrumentation-file=/home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/tools/clang/tools/driver/../../utils/perf-training/prof.fdata
BOLT-INFO: shared object or position-independent executable detected
BOLT-INFO: Target architecture: aarch64
BOLT-INFO: BOLT version: <unknown>
BOLT-INFO: first alloc address is 0x0
BOLT-INFO: creating new program header table at address 0x8800000, offset 0x8800000
BOLT-INFO: enabling relocation mode
BOLT-INFO: forcing -jump-tables=move for instrumentation
BOLT-WARNING: 1 collisions detected while hashing binary objects. Use -v=1 to see the list.
BOLT-INFO: number of removed linker-inserted veneers: 0
BOLT-INFO: 0 out of 153188 functions in the binary (0.0%) have non-empty execution profile
BOLT-INSTRUMENTER: Number of indirect call site descriptors: 60359
BOLT-INSTRUMENTER: Number of indirect call target descriptors: 151023
BOLT-INSTRUMENTER: Number of function descriptors: 151010
BOLT-INSTRUMENTER: Number of branch counters: 1988637
BOLT-INSTRUMENTER: Number of ST leaf node counters: 1013142
BOLT-INSTRUMENTER: Number of direct call counters: 0
BOLT-INSTRUMENTER: Total number of counters: 3001779
BOLT-INSTRUMENTER: Total size of counters: 24014232 bytes (static alloc memory)
BOLT-INSTRUMENTER: Total size of string table emitted: 15755537 bytes in file
BOLT-INSTRUMENTER: Total size of descriptors: 221817964 bytes in file
BOLT-INSTRUMENTER: Profile will be saved to file /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/tools/clang/tools/driver/../../utils/perf-training/prof.fdata
BOLT-INFO: removed 22127 empty blocks
BOLT-INFO: merged 4 duplicate CFG edges
BOLT-INFO: Starting stub-insertion pass
BOLT-INFO: Inserted 1462 stubs in the hot area and 0 stubs in the cold area. Shared 163370 times, iterated 4 times.
BOLT-INFO: padding code to 0x12e00000 to accommodate hot text
BOLT-INFO: output linked against instrumentation runtime library, lib entry point is 0x159b88c0
BOLT-INFO: clear procedure is 0x159b7540
BOLT-INFO: patched build-id (flipped last bit)
BOLT-INFO: setting __bolt_runtime_start to 0x159b88c0
BOLT-INFO: setting __bolt_runtime_fini to 0x159b8954
BOLT-INFO: setting __hot_start to 0x8a00000
BOLT-INFO: setting __hot_end to 0x12ca5ba8
Running: /usr/bin/python3 /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/./bin/llvm-lit -v /home/buildbot/workspace/bolt-aarch64-ubuntu-clang/build/tools/clang/tools/driver/../../utils/perf-training/bolt-fdata
-- Testing: 2 tests, 2 workers --
FAIL: Clang Perf Training :: cxx/hello_world.cpp (1 of 2)

@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 3, 2025

LLVM Buildbot has detected a new failure on builder clang-aarch64-quick running on linaro-clang-aarch64-quick while building clang at step 5 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/65/builds/23492

Here is the relevant piece of the build log for the reference
Step 5 (ninja check 1) failure: stage 1 checked (failure)
******************** TEST 'lit :: googletest-timeout.py' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 9
not env -u FILECHECK_OPTS "/usr/bin/python3.10" /home/tcwg-buildbot/worker/clang-aarch64-quick/llvm/llvm/utils/lit/lit.py -j1 --order=lexical -v Inputs/googletest-timeout    --param gtest_filter=InfiniteLoopSubTest --timeout=1 > /home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/utils/lit/tests/Output/googletest-timeout.py.tmp.cmd.out
# executed command: not env -u FILECHECK_OPTS /usr/bin/python3.10 /home/tcwg-buildbot/worker/clang-aarch64-quick/llvm/llvm/utils/lit/lit.py -j1 --order=lexical -v Inputs/googletest-timeout --param gtest_filter=InfiniteLoopSubTest --timeout=1
# .---command stderr------------
# | lit.py: /home/tcwg-buildbot/worker/clang-aarch64-quick/llvm/llvm/utils/lit/lit/main.py:74: note: The test suite configuration requested an individual test timeout of 0 seconds but a timeout of 1 seconds was requested on the command line. Forcing timeout to be 1 seconds.
# `-----------------------------
# RUN: at line 11
FileCheck --check-prefix=CHECK-INF < /home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/utils/lit/tests/Output/googletest-timeout.py.tmp.cmd.out /home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/utils/lit/tests/googletest-timeout.py
# executed command: FileCheck --check-prefix=CHECK-INF /home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/utils/lit/tests/googletest-timeout.py
# .---command stderr------------
# | /home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/utils/lit/tests/googletest-timeout.py:34:14: error: CHECK-INF: expected string not found in input
# | # CHECK-INF: Timed Out: 1
# |              ^
# | <stdin>:13:29: note: scanning from here
# | Reached timeout of 1 seconds
# |                             ^
# | <stdin>:37:2: note: possible intended match here
# |  Timed Out: 2 (100.00%)
# |  ^
# | 
# | Input file: <stdin>
# | Check file: /home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/utils/lit/tests/googletest-timeout.py
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |             .
# |             .
# |             .
# |             8:  
# |             9:  
# |            10: -- 
# |            11: exit: -9 
# |            12: -- 
# |            13: Reached timeout of 1 seconds 
# | check:34'0                                 X error: no match found
# |            14: ******************** 
# | check:34'0     ~~~~~~~~~~~~~~~~~~~~~
# |            15: TIMEOUT: googletest-timeout :: DummySubDir/OneTest.py/1/2 (2 of 2) 
# | check:34'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |            16: ******************** TEST 'googletest-timeout :: DummySubDir/OneTest.py/1/2' FAILED ******************** 
# | check:34'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |            17: Script(shard): 
# | check:34'0     ~~~~~~~~~~~~~~~
...

MixedMatched pushed a commit to MixedMatched/llvm-project that referenced this pull request Oct 3, 2025
…pe aliases (llvm#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 llvm#131408
} else {
assert(Output.arguments().size() == 1);
TemplateArgumentLoc Transformed = Output.arguments()[0];
if (SemaRef.CheckTemplateArgument(
Copy link
Collaborator

@shafik shafik Oct 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am looking at the for loop above and it sure seems like you could also use the for loop here and just these both above the if and remove the redundant code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I filed #161948

zyn0217 added a commit that referenced this pull request Oct 4, 2025
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Oct 4, 2025
…peAlias (#161948)

This addresses the post-commit review llvm/llvm-project#161035 (comment) from Shafik
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Clang] Crash on CTAD for alias template involving aggregate initialization of NTTP

6 participants