[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Jul 10 13:00:02 PDT 2026


https://github.com/Sirraide updated https://github.com/llvm/llvm-project/pull/169689

>From 4e3cf1966eb18c3155c567dcefc5510ee1f7c378 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH 1/2] [Clang] [C++26] Expansion Statements (Part 10)

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 +
 clang/include/clang/Basic/LangOptions.def     |  1 +
 clang/include/clang/Options/Options.td        |  4 +
 clang/lib/Driver/ToolChains/Clang.cpp         |  1 +
 clang/lib/Sema/SemaExpand.cpp                 | 18 +++++
 .../SemaCXX/cxx2c-expansion-stmts-limit.cpp   | 73 +++++++++++++++++++
 .../SemaCXX/cxx2c-fexpansion-statements.cpp   |  9 +++
 7 files changed, 110 insertions(+)
 create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
 create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bfe0fe75389fa..14e6b71a4256e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
   "assertion failed during evaluation of constant expression">;
 def err_expansion_size_expr_not_ice : Error<
   "expansion statement size is not a constant expression">;
+def err_expansion_too_big : Error<
+  "expansion statement size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+  "use -fexpansion-limit=N to adjust this limit">;
 def err_iterating_expansion_stmt_unsupported : Error<
   "iterating expansion statements are not yet supported">;
 
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index dd4c5a653d38b..7da7851085130 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -386,6 +386,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
         "maximum constexpr call depth")
 LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
         "maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 16384, Benign, "maximum template for expansions")
 LANGOPT(EnableNewConstInterp, 1, 0, Benign,
         "enable the experimental new constant interpreter")
 LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 412683fd968b0..6819a2b582b89 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2159,6 +2159,10 @@ def fconstexpr_steps_EQ : Joined<["-"], "fconstexpr-steps=">, Group<f_Group>,
   Visibility<[ClangOption, CC1Option]>,
   HelpText<"Set the maximum number of steps in constexpr function evaluation (0 = no limit)">,
   MarshallingInfoInt<LangOpts<"ConstexprStepLimit">, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group<f_Group>,
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Set the maximum number of times a single expansion statement may be expanded (0 = no limit)">,
+  MarshallingInfoInt<LangOpts<"MaxTemplateForExpansions">, "256">;
 def fexperimental_new_constant_interpreter : Flag<["-"], "fexperimental-new-constant-interpreter">, Group<f_Group>,
   HelpText<"Enable the experimental new constant interpreter">,
   Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 86b0a705c7fe9..e7b16101943ae 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6563,6 +6563,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
   Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
   Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+  Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
 
   Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
 
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 8647276149d9a..8b25adc98b659 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -52,6 +52,18 @@ struct IterableExpansionStmtData {
 };
 } // namespace
 
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+                               SourceLocation Loc) {
+  unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+  if (Max != 0 && NumInstantiations > Max) {
+    S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+    S.Diag(Loc, diag::note_use_fexpansion_limit);
+    return true;
+  }
+
+  return false;
+}
+
 // Build a 'DeclRefExpr' designating the template parameter that is used as
 // the expansion index
 static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
@@ -255,6 +267,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
   if (!Arity)
     return StmtError();
 
+  if (CheckExpansionSize(S, *Arity, ColonLoc))
+    return StmtError();
+
   QualType AutoRRef = S.Context.getAutoRRefDeductType();
   SmallVector<BindingDecl *> Bindings;
   for (unsigned I = 0; I < *Arity; ++I)
@@ -513,6 +528,9 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!NumInstantiations)
     return StmtError();
 
+  if (CheckExpansionSize(*this, *NumInstantiations, Expansion->getColonLoc()))
+    return StmtError();
+
   // Collect preamble statements.
   //
   // There are at most 3 of these: for iterating expansion statements, these
diff --git a/clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp b/clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
new file mode 100644
index 0000000000000..384ca022ae5ee
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=32 -verify
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=32 -verify -fexperimental-new-constant-interpreter
+
+void g(int);
+
+#if 0 // Disabled until we support iterating expansion statements.
+template <__SIZE_TYPE__ size>
+struct String {
+  char data[size];
+
+  template <__SIZE_TYPE__ n>
+  constexpr String(const char (&str)[n]) { __builtin_memcpy(data, str, n); }
+
+  constexpr const char* begin() const { return data; }
+  constexpr const char* end() const { return data + size - 1; }
+};
+
+template <__SIZE_TYPE__ n>
+String(const char (&str)[n]) -> String<n>;
+
+template <typename T, __SIZE_TYPE__ size>
+struct Array {
+  T data[size]{};
+  constexpr const T* begin() const { return data; }
+  constexpr const T* end() const { return data + size; }
+};
+#endif // 0
+
+void expansion_size() {
+#if 0 // Disabled until we support iterating expansion statements.
+  static constexpr Array<int, 32> almost_too_big;
+  template for (auto x : almost_too_big) g(x);
+  template for (constexpr auto x : almost_too_big) g(x);
+
+  static constexpr Array<int, 33> too_big;
+  template for (auto x : too_big) g(x); // expected-error {{expansion statement size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+  template for (constexpr auto x : too_big) g(x); // expected-error {{expansion statement size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+
+  static constexpr String big{"1234567890123456789012345678901234567890234567890"};
+  template for (auto x : big) g(x); // expected-error {{expansion statement size 49 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+  template for (constexpr auto x : big) g(x); // expected-error {{expansion statement size 49 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+#endif // 0
+
+  template for (auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+    31, 32}) g(x);
+  template for (constexpr auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+    31, 32}) g(x);
+
+  template for (auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // expected-error {{expansion statement size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+    31, 32, 33}) g(x);
+  template for (constexpr auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // expected-error {{expansion statement size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+    31, 32, 33}) g(x);
+
+  int huge[1'000'000'000];
+  template for (auto x : huge) {} // expected-error {{expansion statement size 1000000000 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+}
+
+void array_too_big() {
+  int ok[32];
+  int too_big[33];
+
+  template for (auto x : ok) {}
+  template for (auto x : too_big) {} // expected-error {{expansion statement size 33 exceeds maximum configured size 32}} \
+                                        expected-note {{use -fexpansion-limit=N to adjust this limit}}
+}
diff --git a/clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp b/clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
new file mode 100644
index 0000000000000..2c80c392e400d
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=0 -verify
+// expected-no-diagnostics
+
+// Test that passing =0 disables the limit.
+
+void big() {
+  int ok[500];
+  template for (auto x : ok) {}
+}

>From 9127173e51ed2575f47703604627006f4a4960b6 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Fri, 10 Jul 2026 21:59:51 +0200
Subject: [PATCH 2/2] [Clang] [C++26] Expansion Statements (Part 11: Final
 Touches and Tests) (#169690)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This makes some very minor final changes that didn’t really fit anywhere
else, and in addition it also adds the AST dump tests because I wasn’t
quite sure where else to put them (we can’t put them with the other AST
stuff since this requires Sema).
---
 clang/docs/ReleaseNotes.rst                   |   2 +
 .../clang/Basic/DiagnosticCommonKinds.td      |   4 -
 .../clang/Basic/DiagnosticSemaKinds.td        |   4 -
 clang/include/clang/Basic/LangOptions.def     |   1 -
 clang/include/clang/Options/Options.td        |   4 -
 clang/lib/Driver/ToolChains/Clang.cpp         |   1 -
 clang/lib/Sema/SemaExpand.cpp                 |  18 ---
 clang/test/AST/ast-dump-expansion-stmt.cpp    |  54 +++++++++
 clang/test/AST/ast-print-expansion-stmts.cpp  | 113 ++++++++++++++++++
 .../SemaCXX/cxx2c-expansion-stmts-limit.cpp   |  73 -----------
 .../SemaCXX/cxx2c-fexpansion-statements.cpp   |   9 --
 clang/www/cxx_status.html                     |   8 +-
 12 files changed, 176 insertions(+), 115 deletions(-)
 create mode 100644 clang/test/AST/ast-dump-expansion-stmt.cpp
 create mode 100644 clang/test/AST/ast-print-expansion-stmts.cpp
 delete mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
 delete mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fc17eead02589..1fab855bb1fc2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -126,6 +126,8 @@ C++ Language Changes
 
 C++2c Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
+- Clang now has partial support for `P1306R5 <https://wg21.link/P1306R5>`_ Expansion Statements. Iterating expansion
+  statements currently cannot be expanded and will result in a diagnostic, but other types of expansion statements work.
 
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index f1ee130eb1f11..cb267e3ee05c1 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -22,10 +22,6 @@ def select_constexpr_spec_kind : TextSubstitution<
 def fatal_too_many_errors
   : Error<"too many errors emitted, stopping now">, DefaultFatal;
 
-// TODO: Remove this.
-def err_expansion_statements_todo : Error<
-  "TODO (expansion statements)">;
-
 def warn_stack_exhausted : Warning<
   "stack nearly exhausted; compilation time may suffer, and "
   "crashes due to stack overflow are likely">,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 14e6b71a4256e..bfe0fe75389fa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,10 +167,6 @@ def note_constexpr_assert_failed : Note<
   "assertion failed during evaluation of constant expression">;
 def err_expansion_size_expr_not_ice : Error<
   "expansion statement size is not a constant expression">;
-def err_expansion_too_big : Error<
-  "expansion statement size %0 exceeds maximum configured size %1">;
-def note_use_fexpansion_limit : Note<
-  "use -fexpansion-limit=N to adjust this limit">;
 def err_iterating_expansion_stmt_unsupported : Error<
   "iterating expansion statements are not yet supported">;
 
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 7da7851085130..dd4c5a653d38b 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -386,7 +386,6 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
         "maximum constexpr call depth")
 LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
         "maximum constexpr evaluation steps")
-LANGOPT(MaxTemplateForExpansions, 32, 16384, Benign, "maximum template for expansions")
 LANGOPT(EnableNewConstInterp, 1, 0, Benign,
         "enable the experimental new constant interpreter")
 LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 6819a2b582b89..412683fd968b0 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2159,10 +2159,6 @@ def fconstexpr_steps_EQ : Joined<["-"], "fconstexpr-steps=">, Group<f_Group>,
   Visibility<[ClangOption, CC1Option]>,
   HelpText<"Set the maximum number of steps in constexpr function evaluation (0 = no limit)">,
   MarshallingInfoInt<LangOpts<"ConstexprStepLimit">, "1048576">;
-def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group<f_Group>,
-  Visibility<[ClangOption, CC1Option]>,
-  HelpText<"Set the maximum number of times a single expansion statement may be expanded (0 = no limit)">,
-  MarshallingInfoInt<LangOpts<"MaxTemplateForExpansions">, "256">;
 def fexperimental_new_constant_interpreter : Flag<["-"], "fexperimental-new-constant-interpreter">, Group<f_Group>,
   HelpText<"Enable the experimental new constant interpreter">,
   Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index e7b16101943ae..86b0a705c7fe9 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6563,7 +6563,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
   Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
   Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
-  Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
 
   Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
 
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 8b25adc98b659..8647276149d9a 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -52,18 +52,6 @@ struct IterableExpansionStmtData {
 };
 } // namespace
 
-static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
-                               SourceLocation Loc) {
-  unsigned Max = S.LangOpts.MaxTemplateForExpansions;
-  if (Max != 0 && NumInstantiations > Max) {
-    S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
-    S.Diag(Loc, diag::note_use_fexpansion_limit);
-    return true;
-  }
-
-  return false;
-}
-
 // Build a 'DeclRefExpr' designating the template parameter that is used as
 // the expansion index
 static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
@@ -267,9 +255,6 @@ static StmtResult BuildDestructuringDecompositionDecl(
   if (!Arity)
     return StmtError();
 
-  if (CheckExpansionSize(S, *Arity, ColonLoc))
-    return StmtError();
-
   QualType AutoRRef = S.Context.getAutoRRefDeductType();
   SmallVector<BindingDecl *> Bindings;
   for (unsigned I = 0; I < *Arity; ++I)
@@ -528,9 +513,6 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!NumInstantiations)
     return StmtError();
 
-  if (CheckExpansionSize(*this, *NumInstantiations, Expansion->getColonLoc()))
-    return StmtError();
-
   // Collect preamble statements.
   //
   // There are at most 3 of these: for iterating expansion statements, these
diff --git a/clang/test/AST/ast-dump-expansion-stmt.cpp b/clang/test/AST/ast-dump-expansion-stmt.cpp
new file mode 100644
index 0000000000000..94f0ee1449f17
--- /dev/null
+++ b/clang/test/AST/ast-dump-expansion-stmt.cpp
@@ -0,0 +1,54 @@
+// Test without serialization:
+// RUN: %clang_cc1 -std=c++26 -triple x86_64-unknown-unknown -ast-dump %s
+//
+// Test with serialization:
+// RUN: %clang_cc1 -std=c++26 -triple x86_64-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++26 -triple x86_64-unknown-unknown -include-pch %t -ast-dump-all /dev/null \
+// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//"
+
+#if 0 // Disabled until we support iterating expansion statements.
+template <typename T, __SIZE_TYPE__ size>
+struct Array {
+  T data[size]{};
+  constexpr const T* begin() const { return data; }
+  constexpr const T* end() const { return data + size; }
+};
+#endif // 0
+
+void foo(int);
+
+template <typename T>
+void test(T t) {
+  // CHECK:      CXXExpansionStmtDecl
+  // CHECK-NEXT:   CXXExpansionStmtPattern {{.*}} enumerating
+  // CHECK:        CXXExpansionStmtInstantiation
+  template for (auto x : {1, 2, 3}) {
+    foo(x);
+  }
+
+#if 0 // Disabled until we support iterating expansion statements.
+  // NOTE: Remove 'DISABLED-' when the '#if 0' is removed.
+  // DISABLED-CHECK:      CXXExpansionStmtDecl
+  // DISABLED-CHECK-NEXT:   CXXExpansionStmtPattern {{.*}} iterating
+  // DISABLED-CHECK:        CXXExpansionStmtInstantiation
+  static constexpr Array<int, 3> a;
+  template for (auto x : a) {
+    foo(x);
+  }
+#endif
+
+  // CHECK:      CXXExpansionStmtDecl
+  // CHECK-NEXT:   CXXExpansionStmtPattern {{.*}} destructuring
+  // CHECK:        CXXExpansionStmtInstantiation
+  int arr[3]{1, 2, 3};
+  template for (auto x : arr) {
+    foo(x);
+  }
+
+  // CHECK:      CXXExpansionStmtDecl
+  // CHECK-NEXT:   CXXExpansionStmtPattern {{.*}} dependent
+  // CHECK-NOT:    CXXExpansionStmtInstantiation
+  template for (auto x : t) {
+    foo(x);
+  }
+}
diff --git a/clang/test/AST/ast-print-expansion-stmts.cpp b/clang/test/AST/ast-print-expansion-stmts.cpp
new file mode 100644
index 0000000000000..880e17a9d3e2f
--- /dev/null
+++ b/clang/test/AST/ast-print-expansion-stmts.cpp
@@ -0,0 +1,113 @@
+// Without serialization:
+// RUN: %clang_cc1 -std=c++26 -ast-print %s | FileCheck %s
+//
+// With serialization:
+// RUN: %clang_cc1 -std=c++26 -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++26 -include-pch %t -ast-print  /dev/null | FileCheck %s
+
+#if 0 // Disabled until we support iterating expansion statements.
+template <typename T, __SIZE_TYPE__ size>
+struct Array {
+  T data[size]{};
+  constexpr const T* begin() const { return data; }
+  constexpr const T* end() const { return data + size; }
+};
+#endif // 0
+
+// CHECK: void foo(int);
+void foo(int);
+
+// CHECK: template <typename T> void test(T t) {
+template <typename T>
+void test(T t) {
+  // Enumerating expansion statement.
+  //
+  // CHECK:      template for (auto x : {1, 2, 3}) {
+  // CHECK-NEXT:     foo(x);
+  // CHECK-NEXT: }
+  template for (auto x : {1, 2, 3}) {
+    foo(x);
+  }
+
+#if 0 // Disabled until we support iterating expansion statements.
+  // Iterating expansion statement.
+  //
+  // NOTE: Remove 'DISABLED-' when the '#if 0' is removed.
+  // DISABLED-CHECK:      static constexpr Array<int, 3> a;
+  // DISABLED-CHECK-NEXT: template for (auto x : (a)) {
+  // DISABLED-CHECK-NEXT:   foo(x);
+  // DISABLED-CHECK-NEXT: }
+  static constexpr Array<int, 3> a;
+  template for (auto x : a) {
+    foo(x);
+  }
+#endif // 0
+
+  // Destructuring expansion statement.
+  //
+  // CHECK:      int arr[3]{1, 2, 3};
+  // CHECK-NEXT: template for (auto x : arr) {
+  // CHECK-NEXT:   foo(x);
+  // CHECK-NEXT: }
+  int arr[3]{1, 2, 3};
+  template for (auto x : arr) {
+    foo(x);
+  }
+
+  // Dependent expansion statement.
+  //
+  // CHECK:      template for (auto x : t) {
+  // CHECK-NEXT:   foo(x);
+  // CHECK-NEXT: }
+  template for (auto x : t) {
+    foo(x);
+  }
+}
+
+// CHECK: template <typename T> void test2(T t) {
+template <typename T>
+void test2(T t) {
+  // Enumerating expansion statement.
+  //
+  // CHECK:      template for (int x : {1, 2, 3}) {
+  // CHECK-NEXT:     foo(x);
+  // CHECK-NEXT: }
+  template for (int x : {1, 2, 3}) {
+    foo(x);
+  }
+
+#if 0 // Disabled until we support iterating expansion statements.
+  // Iterating expansion statement.
+  //
+  // NOTE: Remove 'DISABLED-' when the '#if 0' is removed.
+  // DISABLED-CHECK:      static constexpr Array<int, 3> a;
+  // DISABLED-CHECK-NEXT: template for (int x : (a)) {
+  // DISABLED-CHECK-NEXT:   foo(x);
+  // DISABLED-CHECK-NEXT: }
+
+  static constexpr Array<int, 3> a;
+  template for (int x : a) {
+    foo(x);
+  }
+#endif // 0
+
+  // Destructuring expansion statement.
+  //
+  // CHECK:      int arr[3]{1, 2, 3};
+  // CHECK-NEXT: template for (int x : arr) {
+  // CHECK-NEXT:   foo(x);
+  // CHECK-NEXT: }
+  int arr[3]{1, 2, 3};
+  template for (int x : arr) {
+    foo(x);
+  }
+
+  // Dependent expansion statement.
+  //
+  // CHECK:      template for (int x : t) {
+  // CHECK-NEXT:   foo(x);
+  // CHECK-NEXT: }
+  template for (int x : t) {
+    foo(x);
+  }
+}
diff --git a/clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp b/clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
deleted file mode 100644
index 384ca022ae5ee..0000000000000
--- a/clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=32 -verify
-// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=32 -verify -fexperimental-new-constant-interpreter
-
-void g(int);
-
-#if 0 // Disabled until we support iterating expansion statements.
-template <__SIZE_TYPE__ size>
-struct String {
-  char data[size];
-
-  template <__SIZE_TYPE__ n>
-  constexpr String(const char (&str)[n]) { __builtin_memcpy(data, str, n); }
-
-  constexpr const char* begin() const { return data; }
-  constexpr const char* end() const { return data + size - 1; }
-};
-
-template <__SIZE_TYPE__ n>
-String(const char (&str)[n]) -> String<n>;
-
-template <typename T, __SIZE_TYPE__ size>
-struct Array {
-  T data[size]{};
-  constexpr const T* begin() const { return data; }
-  constexpr const T* end() const { return data + size; }
-};
-#endif // 0
-
-void expansion_size() {
-#if 0 // Disabled until we support iterating expansion statements.
-  static constexpr Array<int, 32> almost_too_big;
-  template for (auto x : almost_too_big) g(x);
-  template for (constexpr auto x : almost_too_big) g(x);
-
-  static constexpr Array<int, 33> too_big;
-  template for (auto x : too_big) g(x); // expected-error {{expansion statement size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
-  template for (constexpr auto x : too_big) g(x); // expected-error {{expansion statement size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
-
-  static constexpr String big{"1234567890123456789012345678901234567890234567890"};
-  template for (auto x : big) g(x); // expected-error {{expansion statement size 49 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
-  template for (constexpr auto x : big) g(x); // expected-error {{expansion statement size 49 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
-#endif // 0
-
-  template for (auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
-    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
-    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
-    31, 32}) g(x);
-  template for (constexpr auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
-    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
-    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
-    31, 32}) g(x);
-
-  template for (auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // expected-error {{expansion statement size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
-    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
-    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
-    31, 32, 33}) g(x);
-  template for (constexpr auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // expected-error {{expansion statement size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
-    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
-    21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
-    31, 32, 33}) g(x);
-
-  int huge[1'000'000'000];
-  template for (auto x : huge) {} // expected-error {{expansion statement size 1000000000 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
-}
-
-void array_too_big() {
-  int ok[32];
-  int too_big[33];
-
-  template for (auto x : ok) {}
-  template for (auto x : too_big) {} // expected-error {{expansion statement size 33 exceeds maximum configured size 32}} \
-                                        expected-note {{use -fexpansion-limit=N to adjust this limit}}
-}
diff --git a/clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp b/clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
deleted file mode 100644
index 2c80c392e400d..0000000000000
--- a/clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=0 -verify
-// expected-no-diagnostics
-
-// Test that passing =0 disables the limit.
-
-void big() {
-  int ok[500];
-  template for (auto x : ok) {}
-}
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 2c834b07f9a8f..9ff43c713d5b3 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -320,7 +320,13 @@ <h2 id="cxx26">C++2c implementation status</h2>
  <tr>
   <td>Expansion Statements</td>
   <td><a href="https://wg21.link/P1306">P1306R5</a></td>
-  <td class="none" align="center">No</td>
+  <td class="partial" align="center">
+    <details>
+      <summary>Clang 23 (Partial)</summary>
+      Iterating expansion statements currently cannot be expanded and will
+      result in a diagnostic, but other types of expansion statements work.
+    </details>
+  </td>
  </tr>
  <tr>
    <td>constexpr virtual inheritance</td>



More information about the llvm-branch-commits mailing list