[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 11: Final Touches and Tests) (PR #169690)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Mar 18 18:00:36 PDT 2026


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

>From 087e2e9a43e3faacd3225fc0216c19d47cc153c9 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Wed, 26 Nov 2025 18:03:57 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 11)

---
 clang/docs/ReleaseNotes.rst                   |  11 +-
 .../clang/Basic/DiagnosticCommonKinds.td      |   4 -
 clang/test/AST/ast-dump-expansion-stmt.cpp    |  49 +++++++++
 clang/test/AST/ast-print-expansion-stmts.cpp  | 104 ++++++++++++++++++
 clang/test/SemaTemplate/GH176155.cpp          |  20 +---
 clang/www/cxx_status.html                     |   2 +-
 6 files changed, 165 insertions(+), 25 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 3dabf951661e5..304eef48f4edf 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -117,6 +117,7 @@ C++ Language Changes
 
 C++2c Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
+- Implemented `P1306R5 <https://wg21.link/P1306R5>`_ Expansion Statements.
 
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
@@ -279,7 +280,7 @@ Improvements to Clang's diagnostics
   when accessing a member function on a past-the-end array element.
   (#GH179128)
 
-- Added a missing space to the FixIt for the ``implicit-int`` group of diagnostics and 
+- Added a missing space to the FixIt for the ``implicit-int`` group of diagnostics and
   made sure that only one such diagnostic and FixIt is emitted per declaration group. (#GH179354)
 
 - Fixed the Fix-It insertion point for ``expected ';' after alias declaration``
@@ -292,7 +293,7 @@ Improvements to Clang's diagnostics
 - The ``-Wloop-analysis`` warning has been extended to catch more cases of
   variable modification inside lambda expressions (#GH132038).
 
-- Clang now emits ``-Wsizeof-pointer-memaccess`` when snprintf/vsnprintf use the sizeof 
+- Clang now emits ``-Wsizeof-pointer-memaccess`` when snprintf/vsnprintf use the sizeof
   the destination buffer(dynamically allocated) in the len parameter(#GH162366)
 
 - Added ``-Wmodule-map-path-outside-directory`` (off by default) to warn on
@@ -352,7 +353,7 @@ Bug Fixes to C++ Support
 - Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741)
 - Fixed a crash when instantiating an invalid out-of-line static data member definition in a local class. (#GH176152)
 - Fixed a crash when pack expansions are used as arguments for non-pack parameters of built-in templates. (#GH180307)
-- Fixed a bug where captured variables in non-mutable lambdas were incorrectly treated as mutable 
+- Fixed a bug where captured variables in non-mutable lambdas were incorrectly treated as mutable
   when used inside decltype in the return type. (#GH180460)
 - Fixed a crash when evaluating uninitialized GCC vector/ext_vector_type vectors in ``constexpr``. (#GH180044)
 - Fixed a crash when `explicit(bool)` is used with an incomplete enumeration. (#GH183887)
@@ -360,8 +361,8 @@ Bug Fixes to C++ Support
 - Fixed a crash when an immediate-invoked ``consteval`` lambda is used as an invalid initializer. (#GH185270)
 - Fixed an assertion failure when using a global destructor with a target with a non-default program address space. (#GH186484)
 
-- Inherited constructors in ``dllexport`` classes are now exported for ABI-compatible cases, matching 
-  MSVC behavior. Constructors with variadic arguments or callee-cleanup parameters are not yet supported 
+- Inherited constructors in ``dllexport`` classes are now exported for ABI-compatible cases, matching
+  MSVC behavior. Constructors with variadic arguments or callee-cleanup parameters are not yet supported
   and produce a warning. (#GH162640)
 
 - Fix initialization of GRO when GRO-return type mismatches, as part of CWG2563. (#GH98744)
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..eb9acd5e0b652
--- /dev/null
+++ b/clang/test/AST/ast-dump-expansion-stmt.cpp
@@ -0,0 +1,49 @@
+// 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//"
+
+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; }
+};
+
+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);
+  }
+
+  // CHECK:      CXXExpansionStmtDecl
+  // CHECK-NEXT:   CXXExpansionStmtPattern {{.*}} iterating
+  // CHECK:        CXXExpansionStmtInstantiation
+  static constexpr Array<int, 3> a;
+  template for (auto x : a) {
+    foo(x);
+  }
+
+  // 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..014da274af093
--- /dev/null
+++ b/clang/test/AST/ast-print-expansion-stmts.cpp
@@ -0,0 +1,104 @@
+// 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
+
+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; }
+};
+
+// 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);
+  }
+
+  // Iterating expansion statement.
+  //
+  // CHECK:      static constexpr Array<int, 3> a;
+  // CHECK-NEXT: template for (auto x : (a)) {
+  // CHECK-NEXT:   foo(x);
+  // CHECK-NEXT: }
+  static constexpr Array<int, 3> a;
+  template for (auto x : a) {
+    foo(x);
+  }
+
+  // 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);
+  }
+
+  // Iterating expansion statement.
+  //
+  // CHECK:      static constexpr Array<int, 3> a;
+  // CHECK-NEXT: template for (int x : (a)) {
+  // CHECK-NEXT:   foo(x);
+  // CHECK-NEXT: }
+  static constexpr Array<int, 3> a;
+  template for (int x : a) {
+    foo(x);
+  }
+
+  // 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/SemaTemplate/GH176155.cpp b/clang/test/SemaTemplate/GH176155.cpp
index 12a9de2ae2d46..ce2ca2d488a03 100644
--- a/clang/test/SemaTemplate/GH176155.cpp
+++ b/clang/test/SemaTemplate/GH176155.cpp
@@ -1,26 +1,16 @@
 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+// expected-no-diagnostics
 
 template <int> struct bad {
   template <class T, auto =
-                         [] { // #lambda
-                           // expected-note@#lambda {{while substituting into a lambda expression here}}
-                           // expected-note@#lambda 2{{capture 'i' by value}}
-                           // expected-note@#lambda 2{{capture 'i' by reference}}
-                           // expected-note@#lambda 2{{default capture by value}}
-                           // expected-note@#lambda 2{{default capture by reference}}
-                           for (int i = 0; i < 100; ++i) { // #i
-                             // expected-error at -1 {{variable 'i' cannot be implicitly captured in a lambda with no capture-default specified}}
-                             // expected-note@#i {{'i' declared here}}
-                             // expected-note@#lambda {{lambda expression begins here}}
-                             // expected-error at -4 {{variable 'i' cannot be implicitly captured in a lambda with no capture-default specified}}
-                             // expected-note@#i {{'i' declared here}}
-                             // expected-note@#lambda {{lambda expression begins here}}
+                         [] {
+                           for (int i = 0; i < 100; ++i) {
                              struct LoopHelper {
                                static constexpr void process() {}
                              };
                            }
                          }>
-  static void f(T) {} // expected-note {{in instantiation of default argument for 'f<int>' required here}}
+  static void f(T) {}
 };
 
-int main() { bad<0>::f(0); } // expected-note {{while substituting deduced template arguments into function template 'f'}}
+int main() { bad<0>::f(0); }
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 00ca18bc87635..c89e926b93239 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -317,7 +317,7 @@ <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="unreleased" align="center">Clang 22</td>
   </tr>
   <tr>
    <td>constexpr virtual inheritance</td>



More information about the llvm-branch-commits mailing list