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

>From 16c7a3c385c68174c6f718a24471c175e4257f06 Mon Sep 17 00:00:00 2001
From: Sirraide <[email protected]>
Date: Wed, 26 Nov 2025 18:03:57 +0100
Subject: [PATCH 1/2] [Clang] [C++26] Expansion Statements (Part 11)

---
 clang/docs/ReleaseNotes.rst                   |   2 +
 .../clang/Basic/DiagnosticCommonKinds.td      |   4 -
 clang/test/AST/ast-dump-expansion-stmt.cpp    |  54 +++++++++
 clang/test/AST/ast-print-expansion-stmts.cpp  | 113 ++++++++++++++++++
 clang/www/cxx_status.html                     |   8 +-
 5 files changed, 176 insertions(+), 5 deletions(-)
 create mode 100644 clang/test/AST/ast-dump-expansion-stmt.cpp
 create mode 100644 clang/test/AST/ast-print-expansion-stmts.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/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/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>

>From 77bb03e7cd1a875283292b6d11912c53ed78ef5b Mon Sep 17 00:00:00 2001
From: Sirraide <[email protected]>
Date: Fri, 10 Jul 2026 21:58:54 +0200
Subject: [PATCH 2/2] Revert "[Clang] [C++26] Expansion Statements (Part 10)"

This reverts commit 4e3cf1966eb18c3155c567dcefc5510ee1f7c378.
---
 .../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 deletions(-)
 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/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/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) {}
-}

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to