[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-07 Thread via llvm-branch-commits

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

>From 06ea16d93a842681a5b879c1f454016d049876ff Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  20 ++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 171 ++
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 ++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 +++-
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h|  90 -
 .../Parser/cxx2c-expansion-statements.cpp |  80 
 clang/test/SemaTemplate/GH176155.cpp  |  20 +-
 10 files changed, 395 insertions(+), 65 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ced04356732c4..598196cd185a3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5954,6 +5954,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9ed21ab847030..10bd6bbe5476f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13310,6 +13310,9 @@ class Sema final : public SemaBase {
   /// We are performing overload resolution for a call to a function
   /// template or variable template named 'sycl_kernel_launch'.
   SYCLKernelLaunchOverloadResolution,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13505,6 +13508,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15825,6 +15834,17 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult BuildCXXExpansionSelectExpr(InitListExpr *Range, Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index e5eaab0da7adb..786aeba183ff6 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -478,6 +478,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "SYCLKernelLaunchLookup";
 case CodeSynthesisContext::SYCLKernelLaunchOverloadResolution:
   return "SYCLKernelLaunchOverloadResolution";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index a8bf3161b7eaa..f1fef24d59479 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -23,6 +23,46 @@
 
 using namespace clang;
 
+// Build a 'DeclRefExpr' designating the template parameter that is used as
+// the expansion index
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ 

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-07 Thread via llvm-branch-commits

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

>From 06ea16d93a842681a5b879c1f454016d049876ff Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  20 ++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 171 ++
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 ++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 +++-
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h|  90 -
 .../Parser/cxx2c-expansion-statements.cpp |  80 
 clang/test/SemaTemplate/GH176155.cpp  |  20 +-
 10 files changed, 395 insertions(+), 65 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ced04356732c4..598196cd185a3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5954,6 +5954,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9ed21ab847030..10bd6bbe5476f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13310,6 +13310,9 @@ class Sema final : public SemaBase {
   /// We are performing overload resolution for a call to a function
   /// template or variable template named 'sycl_kernel_launch'.
   SYCLKernelLaunchOverloadResolution,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13505,6 +13508,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15825,6 +15834,17 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult BuildCXXExpansionSelectExpr(InitListExpr *Range, Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index e5eaab0da7adb..786aeba183ff6 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -478,6 +478,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "SYCLKernelLaunchLookup";
 case CodeSynthesisContext::SYCLKernelLaunchOverloadResolution:
   return "SYCLKernelLaunchOverloadResolution";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index a8bf3161b7eaa..f1fef24d59479 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -23,6 +23,46 @@
 
 using namespace clang;
 
+// Build a 'DeclRefExpr' designating the template parameter that is used as
+// the expansion index
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ 

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread via llvm-branch-commits


@@ -10,56 +10,56 @@ struct initializer_list {
 
 void bad() {
   template for; // expected-error {{expected '(' after 'for'}}
-  template for (); // expected-error {{expected expression}} expected-error 
{{expected ';' in 'for' statement specifier}} expected-error {{expansion 
statement must be a range-based for loop}} expected-error {{TODO (expansion 
statements)}}
-  template for (;); // expected-error {{expected ';' in 'for' statement 
specifier}} expected-error {{expansion statement must be a range-based for 
loop}} expected-error {{TODO (expansion statements)}}
-  template for (;;); // expected-error {{expansion statement must be a 
range-based for loop}} expected-error {{TODO (expansion statements)}}
-  template for (int x;;); // expected-error {{expansion statement must be a 
range-based for loop}} expected-error {{TODO (expansion statements)}}
-  template for (x : {1}); // expected-error {{expansion statement requires 
type for expansion variable}} expected-error {{TODO (expansion statements)}}
-  template for (: {1}); // expected-error {{expected expression}} 
expected-error {{expected ';' in 'for' statement specifier}} expected-error 
{{expansion statement must be a range-based for loop}} expected-error {{TODO 
(expansion statements)}}
-  template for (auto y : {1})]; // expected-error {{expected expression}} 
expected-error {{TODO (expansion statements)}}
-  template for (auto y : {1}; // expected-error {{expected ')'}} expected-note 
{{to match this '('}} expected-error {{TODO (expansion statements)}}
-  template for (extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}} expected-error {{TODO (expansion 
statements)}}
-  template for (extern static auto y : {1, 2}); // expected-error {{cannot 
combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}} expected-error {{TODO 
(expansion statements)}}
-  template for (static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}} expected-error {{TODO (expansion 
statements)}}
-  template for (thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}} expected-error 
{{TODO (expansion statements)}}
-  template for (__thread auto y : {1, 2}); // expected-error {{'__thread' 
variables must have global storage}} expected-error {{TODO (expansion 
statements)}}
-  template for (static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}} expected-error {{TODO 
(expansion statements)}}
-  template for (constinit auto y : {1, 2}); // expected-error {{local variable 
cannot be declared 'constinit'}} expected-error {{TODO (expansion statements)}}
-  template for (consteval auto y : {1, 2});  // expected-error {{consteval can 
only be used in function declarations}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; extern static auto y : {1, 2}); // expected-error 
{{cannot combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}} expected-error 
{{TODO (expansion statements)}}
-  template for (int x; __thread auto y : {1, 2}); // expected-error 
{{'__thread' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; constinit auto y : {1, 2}); // expected-error {{local 
variable cannot be declared 'constinit'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; consteval auto y : {1, 2});  // expected-error 
{{consteval can only be used in function declarations}} expected-error {{TODO 
(expansion statements)}}
-  template for (auto y : {abc, -+, }); // expected-error {{use of undeclared 
identifier 'abc'}} expected-error {{expected expression}} expected-error {{TODO 
(expansion stateme

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread Corentin Jabot via llvm-branch-commits


@@ -10,56 +10,56 @@ struct initializer_list {
 
 void bad() {
   template for; // expected-error {{expected '(' after 'for'}}
-  template for (); // expected-error {{expected expression}} expected-error 
{{expected ';' in 'for' statement specifier}} expected-error {{expansion 
statement must be a range-based for loop}} expected-error {{TODO (expansion 
statements)}}
-  template for (;); // expected-error {{expected ';' in 'for' statement 
specifier}} expected-error {{expansion statement must be a range-based for 
loop}} expected-error {{TODO (expansion statements)}}
-  template for (;;); // expected-error {{expansion statement must be a 
range-based for loop}} expected-error {{TODO (expansion statements)}}
-  template for (int x;;); // expected-error {{expansion statement must be a 
range-based for loop}} expected-error {{TODO (expansion statements)}}
-  template for (x : {1}); // expected-error {{expansion statement requires 
type for expansion variable}} expected-error {{TODO (expansion statements)}}
-  template for (: {1}); // expected-error {{expected expression}} 
expected-error {{expected ';' in 'for' statement specifier}} expected-error 
{{expansion statement must be a range-based for loop}} expected-error {{TODO 
(expansion statements)}}
-  template for (auto y : {1})]; // expected-error {{expected expression}} 
expected-error {{TODO (expansion statements)}}
-  template for (auto y : {1}; // expected-error {{expected ')'}} expected-note 
{{to match this '('}} expected-error {{TODO (expansion statements)}}
-  template for (extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}} expected-error {{TODO (expansion 
statements)}}
-  template for (extern static auto y : {1, 2}); // expected-error {{cannot 
combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}} expected-error {{TODO 
(expansion statements)}}
-  template for (static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}} expected-error {{TODO (expansion 
statements)}}
-  template for (thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}} expected-error 
{{TODO (expansion statements)}}
-  template for (__thread auto y : {1, 2}); // expected-error {{'__thread' 
variables must have global storage}} expected-error {{TODO (expansion 
statements)}}
-  template for (static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}} expected-error {{TODO 
(expansion statements)}}
-  template for (constinit auto y : {1, 2}); // expected-error {{local variable 
cannot be declared 'constinit'}} expected-error {{TODO (expansion statements)}}
-  template for (consteval auto y : {1, 2});  // expected-error {{consteval can 
only be used in function declarations}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; extern static auto y : {1, 2}); // expected-error 
{{cannot combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}} expected-error 
{{TODO (expansion statements)}}
-  template for (int x; __thread auto y : {1, 2}); // expected-error 
{{'__thread' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; constinit auto y : {1, 2}); // expected-error {{local 
variable cannot be declared 'constinit'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; consteval auto y : {1, 2});  // expected-error 
{{consteval can only be used in function declarations}} expected-error {{TODO 
(expansion statements)}}
-  template for (auto y : {abc, -+, }); // expected-error {{use of undeclared 
identifier 'abc'}} expected-error {{expected expression}} expected-error {{TODO 
(expansion stateme

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread Corentin Jabot via llvm-branch-commits


@@ -23,6 +23,45 @@
 
 using namespace clang;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.

cor3ntin wrote:

I think this would be an improvement, thanks

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread via llvm-branch-commits


@@ -64,13 +103,144 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();

Sirraide wrote:

Hmm, well actually that diagnostic says ‘types may not be defined in a for 
range declaration’, and in the standard, _for-range-declaration_ is a grammar 
production that is also used for expansion statements; we can change to ‘in the 
declaration of an expansion variable’ maybe, but I’m not sure if that’s better

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread via llvm-branch-commits


@@ -23,6 +23,45 @@
 
 using namespace clang;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.

Sirraide wrote:

Hmm, I can probably change it to ‘Build a 'DeclRefExpr' designating the 
template parameter that is used as the expansion index’. I don’t think there is 
any actual terminology for this in the standard; it’s more of an implementation 
detail

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread via llvm-branch-commits


@@ -10,56 +10,56 @@ struct initializer_list {
 
 void bad() {
   template for; // expected-error {{expected '(' after 'for'}}
-  template for (); // expected-error {{expected expression}} expected-error 
{{expected ';' in 'for' statement specifier}} expected-error {{expansion 
statement must be a range-based for loop}} expected-error {{TODO (expansion 
statements)}}
-  template for (;); // expected-error {{expected ';' in 'for' statement 
specifier}} expected-error {{expansion statement must be a range-based for 
loop}} expected-error {{TODO (expansion statements)}}
-  template for (;;); // expected-error {{expansion statement must be a 
range-based for loop}} expected-error {{TODO (expansion statements)}}
-  template for (int x;;); // expected-error {{expansion statement must be a 
range-based for loop}} expected-error {{TODO (expansion statements)}}
-  template for (x : {1}); // expected-error {{expansion statement requires 
type for expansion variable}} expected-error {{TODO (expansion statements)}}
-  template for (: {1}); // expected-error {{expected expression}} 
expected-error {{expected ';' in 'for' statement specifier}} expected-error 
{{expansion statement must be a range-based for loop}} expected-error {{TODO 
(expansion statements)}}
-  template for (auto y : {1})]; // expected-error {{expected expression}} 
expected-error {{TODO (expansion statements)}}
-  template for (auto y : {1}; // expected-error {{expected ')'}} expected-note 
{{to match this '('}} expected-error {{TODO (expansion statements)}}
-  template for (extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}} expected-error {{TODO (expansion 
statements)}}
-  template for (extern static auto y : {1, 2}); // expected-error {{cannot 
combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}} expected-error {{TODO 
(expansion statements)}}
-  template for (static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}} expected-error {{TODO (expansion 
statements)}}
-  template for (thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}} expected-error 
{{TODO (expansion statements)}}
-  template for (__thread auto y : {1, 2}); // expected-error {{'__thread' 
variables must have global storage}} expected-error {{TODO (expansion 
statements)}}
-  template for (static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}} expected-error {{TODO 
(expansion statements)}}
-  template for (constinit auto y : {1, 2}); // expected-error {{local variable 
cannot be declared 'constinit'}} expected-error {{TODO (expansion statements)}}
-  template for (consteval auto y : {1, 2});  // expected-error {{consteval can 
only be used in function declarations}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; extern static auto y : {1, 2}); // expected-error 
{{cannot combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}} expected-error 
{{TODO (expansion statements)}}
-  template for (int x; __thread auto y : {1, 2}); // expected-error 
{{'__thread' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; constinit auto y : {1, 2}); // expected-error {{local 
variable cannot be declared 'constinit'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; consteval auto y : {1, 2});  // expected-error 
{{consteval can only be used in function declarations}} expected-error {{TODO 
(expansion statements)}}
-  template for (auto y : {abc, -+, }); // expected-error {{use of undeclared 
identifier 'abc'}} expected-error {{expected expression}} expected-error {{TODO 
(expansion stateme

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread via llvm-branch-commits


@@ -9372,19 +9372,101 @@ 
TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
 template 
 StmtResult TreeTransform::TransformCXXExpansionStmtPattern(
 CXXExpansionStmtPattern *S) {
-  llvm_unreachable("TOOD");
+  assert(SemaRef.CurContext->isExpansionStmt());
+
+  Decl *ESD =
+  getDerived().TransformDecl(S->getDecl()->getLocation(), S->getDecl());
+  if (!ESD || ESD->isInvalidDecl())
+return StmtError();
+  CXXExpansionStmtDecl *NewESD = cast(ESD);
+
+  // This is required because some parts of an expansion statement (e.g. the
+  // init-statement) are not in a dependent context and must thus be 
transformed
+  // in the parent context.
+  auto TransformStmtInParentContext = [&] (Stmt *SubStmt) -> StmtResult {
+Sema::ContextRAII CtxGuard(SemaRef, SemaRef.CurContext->getParent(),
+   /*NewThis=*/false);
+return getDerived().TransformStmt(SubStmt);

Sirraide wrote:

Also the new context object references `Parser::ForRangeInfo`, which is 
private, so I’d have to refactor that as well...

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread via llvm-branch-commits


@@ -9372,19 +9372,101 @@ 
TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
 template 
 StmtResult TreeTransform::TransformCXXExpansionStmtPattern(
 CXXExpansionStmtPattern *S) {
-  llvm_unreachable("TOOD");
+  assert(SemaRef.CurContext->isExpansionStmt());
+
+  Decl *ESD =
+  getDerived().TransformDecl(S->getDecl()->getLocation(), S->getDecl());
+  if (!ESD || ESD->isInvalidDecl())
+return StmtError();
+  CXXExpansionStmtDecl *NewESD = cast(ESD);
+
+  // This is required because some parts of an expansion statement (e.g. the
+  // init-statement) are not in a dependent context and must thus be 
transformed
+  // in the parent context.
+  auto TransformStmtInParentContext = [&] (Stmt *SubStmt) -> StmtResult {
+Sema::ContextRAII CtxGuard(SemaRef, SemaRef.CurContext->getParent(),
+   /*NewThis=*/false);
+return getDerived().TransformStmt(SubStmt);

Sirraide wrote:

I think I mentioned that in part 2 just now, but that context object was mainly 
just for use in `Parser::ParseForStatement()` where we have code paths that are 
shared between expansion statements and regular for loops; I could use it here 
as well, but I’d have to move it into a header somewhere that’s accessible to 
both the parser and sema at that point; I’m not sure it’s worth it but I can do 
that if you prefer

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread via llvm-branch-commits


@@ -64,13 +103,144 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.

Sirraide wrote:

The ‘shared statements’ are the statements that are ‘shared’ across all 
expansions of an expansion statement (e.g. the range variable in an iterating 
expansion statement); see the comment on I think `CXXExpansionStmtPattern` for 
more information (that or it maybe it was on `CXXExpansionStmtInstantiation`)

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread Corentin Jabot via llvm-branch-commits


@@ -10,56 +10,56 @@ struct initializer_list {
 
 void bad() {
   template for; // expected-error {{expected '(' after 'for'}}
-  template for (); // expected-error {{expected expression}} expected-error 
{{expected ';' in 'for' statement specifier}} expected-error {{expansion 
statement must be a range-based for loop}} expected-error {{TODO (expansion 
statements)}}
-  template for (;); // expected-error {{expected ';' in 'for' statement 
specifier}} expected-error {{expansion statement must be a range-based for 
loop}} expected-error {{TODO (expansion statements)}}
-  template for (;;); // expected-error {{expansion statement must be a 
range-based for loop}} expected-error {{TODO (expansion statements)}}
-  template for (int x;;); // expected-error {{expansion statement must be a 
range-based for loop}} expected-error {{TODO (expansion statements)}}
-  template for (x : {1}); // expected-error {{expansion statement requires 
type for expansion variable}} expected-error {{TODO (expansion statements)}}
-  template for (: {1}); // expected-error {{expected expression}} 
expected-error {{expected ';' in 'for' statement specifier}} expected-error 
{{expansion statement must be a range-based for loop}} expected-error {{TODO 
(expansion statements)}}
-  template for (auto y : {1})]; // expected-error {{expected expression}} 
expected-error {{TODO (expansion statements)}}
-  template for (auto y : {1}; // expected-error {{expected ')'}} expected-note 
{{to match this '('}} expected-error {{TODO (expansion statements)}}
-  template for (extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}} expected-error {{TODO (expansion 
statements)}}
-  template for (extern static auto y : {1, 2}); // expected-error {{cannot 
combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}} expected-error {{TODO 
(expansion statements)}}
-  template for (static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}} expected-error {{TODO (expansion 
statements)}}
-  template for (thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}} expected-error 
{{TODO (expansion statements)}}
-  template for (__thread auto y : {1, 2}); // expected-error {{'__thread' 
variables must have global storage}} expected-error {{TODO (expansion 
statements)}}
-  template for (static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}} expected-error {{TODO 
(expansion statements)}}
-  template for (constinit auto y : {1, 2}); // expected-error {{local variable 
cannot be declared 'constinit'}} expected-error {{TODO (expansion statements)}}
-  template for (consteval auto y : {1, 2});  // expected-error {{consteval can 
only be used in function declarations}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; extern auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'extern'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; extern static auto y : {1, 2}); // expected-error 
{{cannot combine with previous 'extern' declaration specifier}} expected-error 
{{expansion variable 'y' may not be declared 'extern'}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static auto y : {1, 2}); // expected-error {{expansion 
variable 'y' may not be declared 'static'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; thread_local auto y : {1, 2}); // expected-error 
{{'thread_local' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static thread_local auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'thread_local'}} expected-error 
{{TODO (expansion statements)}}
-  template for (int x; __thread auto y : {1, 2}); // expected-error 
{{'__thread' variables must have global storage}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; static __thread auto y : {1, 2}); // expected-error 
{{expansion variable 'y' may not be declared 'static'}} expected-error {{TODO 
(expansion statements)}}
-  template for (int x; constinit auto y : {1, 2}); // expected-error {{local 
variable cannot be declared 'constinit'}} expected-error {{TODO (expansion 
statements)}}
-  template for (int x; consteval auto y : {1, 2});  // expected-error 
{{consteval can only be used in function declarations}} expected-error {{TODO 
(expansion statements)}}
-  template for (auto y : {abc, -+, }); // expected-error {{use of undeclared 
identifier 'abc'}} expected-error {{expected expression}} expected-error {{TODO 
(expansion stateme

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread Corentin Jabot via llvm-branch-commits


@@ -64,13 +103,144 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();

cor3ntin wrote:

We probably want to customize that diagnostic

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread Corentin Jabot via llvm-branch-commits


@@ -64,13 +103,144 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.

cor3ntin wrote:

Shared?

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread Corentin Jabot via llvm-branch-commits


@@ -9372,19 +9372,101 @@ 
TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
 template 
 StmtResult TreeTransform::TransformCXXExpansionStmtPattern(
 CXXExpansionStmtPattern *S) {
-  llvm_unreachable("TOOD");
+  assert(SemaRef.CurContext->isExpansionStmt());
+
+  Decl *ESD =
+  getDerived().TransformDecl(S->getDecl()->getLocation(), S->getDecl());
+  if (!ESD || ESD->isInvalidDecl())
+return StmtError();
+  CXXExpansionStmtDecl *NewESD = cast(ESD);
+
+  // This is required because some parts of an expansion statement (e.g. the
+  // init-statement) are not in a dependent context and must thus be 
transformed
+  // in the parent context.
+  auto TransformStmtInParentContext = [&] (Stmt *SubStmt) -> StmtResult {
+Sema::ContextRAII CtxGuard(SemaRef, SemaRef.CurContext->getParent(),
+   /*NewThis=*/false);
+return getDerived().TransformStmt(SubStmt);

cor3ntin wrote:

You are not using the new context object here either?

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread Corentin Jabot via llvm-branch-commits


@@ -64,13 +103,144 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();

cor3ntin wrote:

We probably want to customize that diagnostic

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-05-04 Thread Corentin Jabot via llvm-branch-commits


@@ -23,6 +23,45 @@
 
 using namespace clang;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.

cor3ntin wrote:

Don't we have better terminology for that thing?

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-04-27 Thread Yanzuo Liu via llvm-branch-commits


@@ -7108,6 +7138,12 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation 
Loc, NamedDecl *D,
 // anonymous unions in class templates).
   }
 
+  if (CurrentInstantiationScope) {
+if (auto Found = CurrentInstantiationScope->getInstantiationOfIfExists(D))
+  if (auto *FD = dyn_cast(cast(*Found)))
+return FD;
+  }

zwuis wrote:

I applied this part locally and GH176155 is 'fixed'. But I don't know what the 
underlying problem is, nor do I know why this fixes it.

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-04-01 Thread Erich Keane via llvm-branch-commits


@@ -65,13 +104,138 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.
+  SmallVector Shared;

erichkeane wrote:

SGTM.  

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-04-01 Thread via llvm-branch-commits


@@ -65,13 +104,138 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.
+  SmallVector Shared;

Sirraide wrote:

How about this?
```c++
  // Collect shared statements.
  //
  // There are at most 3 of these: for iterating expansion statements, these
  // consist of the '__range' and '__begin' variables, and for destructuring 
  // expansion statements of the DecompositionDecl whose initializer we're
  // expanding. Finally, any expansion statement may have an init-statement
  // as well.
```

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-04-01 Thread Erich Keane via llvm-branch-commits


@@ -65,13 +104,138 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.
+  SmallVector Shared;

erichkeane wrote:

I would like the comment, we often get folks doing "cleanup all uses of 
SmallVector sizes instead of using defaults" and this sort of context gets 
missed in a massive patch.

So a comment helps.

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-04-01 Thread via llvm-branch-commits


@@ -65,13 +104,138 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.
+  SmallVector Shared;

Sirraide wrote:

I think it’s only confusing in this patch; this is what we end up with in the 
end:
```c++
  // Collect shared statements.
  SmallVector Shared;
  if (Expansion->getInit())
Shared.push_back(Expansion->getInit());

  if (Expansion->isIterating()) {
Shared.push_back(Expansion->getRangeVarStmt());
Shared.push_back(Expansion->getBeginVarStmt());
  } else if (Expansion->isDestructuring()) {
Shared.push_back(Expansion->getDecompositionDeclStmt());
MarkAnyDeclReferenced(Exp->getBeginLoc(), Expansion->getDecompositionDecl(),
  true);
  }
```
>From looking at this I think it’s clear why I picked `3` here, but I can still 
>add a comment if you’d like

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-04-01 Thread Erich Keane via llvm-branch-commits


@@ -65,13 +104,138 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.
+  SmallVector Shared;

erichkeane wrote:

Can you document that?  We typically want to keep to NOT specifying it unless 
we have a reason, so a comment to prevent folks from 'cleaning' this up would 
be valuable.

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-31 Thread via llvm-branch-commits


@@ -65,13 +104,138 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.
+  SmallVector Shared;

Sirraide wrote:

Updated this to 3, which is the maximum number of shared statements you can have

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-31 Thread via llvm-branch-commits


@@ -65,13 +104,138 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.
+  SmallVector Shared;

Sirraide wrote:

On that note the inline size of this should probably not be `1` then otherwise 
some expansion statements will always heap-allocate here... I’ll update this to 
a size that makes more sense

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-31 Thread via llvm-branch-commits

https://github.com/Sirraide edited 
https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-31 Thread via llvm-branch-commits


@@ -65,13 +104,138 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.
+  SmallVector Shared;

Sirraide wrote:

It isn’t for enumerating expansion statements, but iterating and destructuring 
expansion statements have multiple shared statements

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-31 Thread Erich Keane via llvm-branch-commits

https://github.com/erichkeane approved this pull request.

1 small question, else i think this LGTM.

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-31 Thread Erich Keane via llvm-branch-commits

https://github.com/erichkeane edited 
https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-31 Thread Erich Keane via llvm-branch-commits

https://github.com/erichkeane commented:

1 small question, else i think this LGTM.

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-31 Thread Erich Keane via llvm-branch-commits


@@ -65,13 +104,138 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinalizeExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.
+  SmallVector Shared;

erichkeane wrote:

Why is this a vector if we only ever create 1 here? 

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-24 Thread via llvm-branch-commits

Sirraide wrote:

I don’t know what, but _something_ in this patch fixes 
test/SemaTemplate/GH176155.cpp, as in it doesn’t issue any diagnostics anymore; 
GCC accepts that test w/o any diagnostics so I just updated the test.

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-24 Thread via llvm-branch-commits

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

>From be79edd149978f1b595e498b09ef0c9f79b76a8c Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  20 +++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 164 ++
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 +++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 +++-
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h|  90 +-
 .../Parser/cxx2c-expansion-statements.cpp |  80 -
 clang/test/SemaTemplate/GH176155.cpp  |  20 +--
 10 files changed, 388 insertions(+), 65 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 50fb1c607b789..0e52becd21779 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5935,6 +5935,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 190c0eed2e141..24c81ed9ea590 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13288,6 +13288,9 @@ class Sema final : public SemaBase {
   /// We are performing overload resolution for a call to a function
   /// template or variable template named 'sycl_kernel_launch'.
   SYCLKernelLaunchOverloadResolution,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13483,6 +13486,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15803,6 +15812,17 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult BuildCXXExpansionSelectExpr(InitListExpr *Range, Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index 7bcb4d7d89db1..39362242940f8 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -480,6 +480,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "SYCLKernelLaunchLookup";
 case CodeSynthesisContext::SYCLKernelLaunchOverloadResolution:
   return "SYCLKernelLaunchOverloadResolution";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 449ff88d1a3ad..106cc7b608212 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,45 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-19 Thread via llvm-branch-commits


@@ -24,6 +24,45 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *ExpansionVar,

Sirraide wrote:

Right, American spelling; I’ll update that. Also, I used PascalCase instead of 
camelCase because that’s what the rest of Sema uses

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-19 Thread via llvm-branch-commits


@@ -65,13 +104,144 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinaliseExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.
+  SmallVector Shared;
+  if (Expansion->getInit())
+Shared.push_back(Expansion->getInit());
+
+  assert(Expansion->isEnumerating() && "TODO");
+
+  // Return an empty statement if the range is empty.
+  if (*NumInstantiations == 0) {
+Expansion->getDecl()->setInstantiations(
+CXXExpansionStmtInstantiation::Create(
+Context, Expansion->getBeginLoc(), Expansion->getEndLoc(),
+/*Instantiations=*/{}, Shared, Expansion->isDestructuring()));
+return Expansion;
+  }
+
+  // Create a compound statement binding the expansion variable and body.
+  Stmt *VarAndBody[] = {Expansion->getExpansionVarStmt(), Body};
+  Stmt *CombinedBody =
+  CompoundStmt::Create(Context, VarAndBody, FPOptionsOverride(),
+   Body->getBeginLoc(), Body->getEndLoc());
+
+  // Expand the body for each instantiation.
+  SmallVector Instantiations;
+  CXXExpansionStmtDecl *ESD = Expansion->getDecl();
+  for (uint64_t I = 0; I < *NumInstantiations; ++I) {
+// Now that we're expanding this, exit the context of the expansion stmt
+// so that we no longer treat this as dependent.
+ContextRAII CtxGuard(*this, CurContext->getParent(),
+ /*NewThis=*/false);
+
+TemplateArgument Arg{Context, llvm::APSInt::get(I),
+ Context.getPointerDiffType()};
+MultiLevelTemplateArgumentList MTArgList(ESD, Arg, true);
+MTArgList.addOuterRetainedLevels(
+Expansion->getDecl()->getIndexTemplateParm()->getDepth());
+
+LocalInstantiationScope LIScope(*this, /*CombineWithOuterScope=*/true);
+NonSFINAEContext _(*this);
+InstantiatingTemplate Inst(*this, Body->getBeginLoc(), Expansion, Arg,
+   Body->getSourceRange());
+
+StmtResult Instantiation = SubstStmt(CombinedBody, MTArgList);
+if (Instantiation.isInvalid())
+  return StmtError();
+Instantiations.push_back(Instantiation.get());
+  }
+
+  auto *InstantiationsStmt = CXXExpansionStmtInstantiation::Create(
+  Context, Expansion->getBeginLoc(), Expansion->getEndLoc(), 
Instantiations,
+  Shared, Expansion->isDestructuring());
+
+  Expansion->getDecl()->setInstantiations(InstantiationsStmt);
+  return Expansion;
+}
+
+ExprResult Sema::BuildCXXExpansionSelectExpr(InitListExpr *Range, Expr *Idx) {
+  if (Idx->isValueDependent() || InitListContainsPack(Range))
+return new (Context) CXXExpansionSelectExpr(Context, Range, Idx);
+
+  // The index is a DRE to a template parameter; we should never
+  // fail to ev

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-18 Thread Timm Baeder via llvm-branch-commits


@@ -65,13 +104,144 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
 Expr *ExpansionInitializer, SourceLocation LParenLoc,
 SourceLocation ColonLoc, SourceLocation RParenLoc,
 ArrayRef LifetimeExtendTemps) {
+  if (!ExpansionInitializer || !ExpansionVarStmt)
+return StmtError();
+
+  assert(CurContext->isExpansionStmt());
+  auto *DS = cast(ExpansionVarStmt);
+  if (!DS->isSingleDecl()) {
+Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+return StmtError();
+  }
+
+  VarDecl *ExpansionVar = dyn_cast(DS->getSingleDecl());
+  if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+  ExpansionInitializer->containsErrors())
+return StmtError();
+
+  // This is an enumerating expansion statement.
+  if (auto *ILE = dyn_cast(ExpansionInitializer)) {
+assert(ILE->isSyntacticForm());
+ExprResult Initializer =
+BuildCXXExpansionSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+if (FinaliseExpansionVar(*this, ExpansionVar, Initializer))
+  return StmtError();
+
+// Note that lifetime extension only applies to destructuring expansion
+// statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+// types of expansion statements (this is CWG 3043).
+return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+   ColonLoc, RParenLoc);
+  }
+
   Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
   return StmtError();
 }
 
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+SourceLocation ColonLoc, SourceLocation RParenLoc) {
+  return CXXExpansionStmtPattern::CreateEnumerating(
+  Context, cast(ESD), Init,
+  cast(ExpansionVar), LParenLoc, ColonLoc, RParenLoc);
+}
+
 StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
   if (!Exp || !Body)
 return StmtError();
 
+  auto *Expansion = cast(Exp);
+  assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+  Expansion->setBody(Body);
+  if (HasDependentSize(Expansion))
+return Expansion;
+
+  // This can fail if this is an iterating expansion statement.
+  std::optional NumInstantiations = ComputeExpansionSize(Expansion);
+  if (!NumInstantiations)
+return StmtError();
+
+  // Collect shared statements.
+  SmallVector Shared;
+  if (Expansion->getInit())
+Shared.push_back(Expansion->getInit());
+
+  assert(Expansion->isEnumerating() && "TODO");
+
+  // Return an empty statement if the range is empty.
+  if (*NumInstantiations == 0) {
+Expansion->getDecl()->setInstantiations(
+CXXExpansionStmtInstantiation::Create(
+Context, Expansion->getBeginLoc(), Expansion->getEndLoc(),
+/*Instantiations=*/{}, Shared, Expansion->isDestructuring()));
+return Expansion;
+  }
+
+  // Create a compound statement binding the expansion variable and body.
+  Stmt *VarAndBody[] = {Expansion->getExpansionVarStmt(), Body};
+  Stmt *CombinedBody =
+  CompoundStmt::Create(Context, VarAndBody, FPOptionsOverride(),
+   Body->getBeginLoc(), Body->getEndLoc());
+
+  // Expand the body for each instantiation.
+  SmallVector Instantiations;
+  CXXExpansionStmtDecl *ESD = Expansion->getDecl();
+  for (uint64_t I = 0; I < *NumInstantiations; ++I) {
+// Now that we're expanding this, exit the context of the expansion stmt
+// so that we no longer treat this as dependent.
+ContextRAII CtxGuard(*this, CurContext->getParent(),
+ /*NewThis=*/false);
+
+TemplateArgument Arg{Context, llvm::APSInt::get(I),
+ Context.getPointerDiffType()};
+MultiLevelTemplateArgumentList MTArgList(ESD, Arg, true);
+MTArgList.addOuterRetainedLevels(
+Expansion->getDecl()->getIndexTemplateParm()->getDepth());
+
+LocalInstantiationScope LIScope(*this, /*CombineWithOuterScope=*/true);
+NonSFINAEContext _(*this);
+InstantiatingTemplate Inst(*this, Body->getBeginLoc(), Expansion, Arg,
+   Body->getSourceRange());
+
+StmtResult Instantiation = SubstStmt(CombinedBody, MTArgList);
+if (Instantiation.isInvalid())
+  return StmtError();
+Instantiations.push_back(Instantiation.get());
+  }
+
+  auto *InstantiationsStmt = CXXExpansionStmtInstantiation::Create(
+  Context, Expansion->getBeginLoc(), Expansion->getEndLoc(), 
Instantiations,
+  Shared, Expansion->isDestructuring());
+
+  Expansion->getDecl()->setInstantiations(InstantiationsStmt);
+  return Expansion;
+}
+
+ExprResult Sema::BuildCXXExpansionSelectExpr(InitListExpr *Range, Expr *Idx) {
+  if (Idx->isValueDependent() || InitListContainsPack(Range))
+return new (Context) CXXExpansionSelectExpr(Context, Range, Idx);
+
+  // The index is a DRE to a template parameter; we should never
+  // fail to ev

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-18 Thread Timm Baeder via llvm-branch-commits


@@ -24,6 +24,45 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *ExpansionVar,

tbaederr wrote:

Quickly grepping the source, it seems like this should be finali_z_e.

Functions should also start lowercase.

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-18 Thread via llvm-branch-commits

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

>From 50a2d608d69960d5289d3ba9e6df33525a078645 Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  20 ++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 173 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 ++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 +++-
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h|  83 -
 .../Parser/cxx2c-expansion-statements.cpp |  80 
 9 files changed, 383 insertions(+), 52 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 50fb1c607b789..0e52becd21779 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5935,6 +5935,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 190c0eed2e141..24c81ed9ea590 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13288,6 +13288,9 @@ class Sema final : public SemaBase {
   /// We are performing overload resolution for a call to a function
   /// template or variable template named 'sycl_kernel_launch'.
   SYCLKernelLaunchOverloadResolution,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13483,6 +13486,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15803,6 +15812,17 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult BuildCXXExpansionSelectExpr(InitListExpr *Range, Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index 7bcb4d7d89db1..39362242940f8 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -480,6 +480,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "SYCLKernelLaunchLookup";
 case CodeSynthesisContext::SYCLKernelLaunchOverloadResolution:
   return "SYCLKernelLaunchOverloadResolution";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 96c0d9be9451c..f16d44a03bfb8 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,45 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansi

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-03-18 Thread via llvm-branch-commits

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

>From 50a2d608d69960d5289d3ba9e6df33525a078645 Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  20 ++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 173 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 ++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 +++-
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h|  83 -
 .../Parser/cxx2c-expansion-statements.cpp |  80 
 9 files changed, 383 insertions(+), 52 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 50fb1c607b789..0e52becd21779 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5935,6 +5935,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 190c0eed2e141..24c81ed9ea590 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13288,6 +13288,9 @@ class Sema final : public SemaBase {
   /// We are performing overload resolution for a call to a function
   /// template or variable template named 'sycl_kernel_launch'.
   SYCLKernelLaunchOverloadResolution,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13483,6 +13486,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15803,6 +15812,17 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult BuildCXXExpansionSelectExpr(InitListExpr *Range, Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index 7bcb4d7d89db1..39362242940f8 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -480,6 +480,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "SYCLKernelLaunchLookup";
 case CodeSynthesisContext::SYCLKernelLaunchOverloadResolution:
   return "SYCLKernelLaunchOverloadResolution";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 96c0d9be9451c..f16d44a03bfb8 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,45 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansi

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2026-01-10 Thread Yanzuo Liu via llvm-branch-commits


@@ -24,6 +24,45 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *ExpansionVar,
+ ExprResult Initializer) {
+  if (Initializer.isInvalid()) {
+S.ActOnInitializerError(ExpansionVar);
+return true;
+  }
+
+  S.AddInitializerToDecl(ExpansionVar, Initializer.get(), 
/*DirectInit=*/false);
+  return ExpansionVar->isInvalidDecl();
+}
+
+static auto InitListContainsPack(const InitListExpr *ILE) {
+  return llvm::any_of(ArrayRef(ILE->getInits(), ILE->getNumInits()),

zwuis wrote:

```diff
-ArrayRef(ILE->getInits(), ILE->getNumInits())
+ILE->inits()
```

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-12-05 Thread via llvm-branch-commits

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

>From 1861f5a04b849455139583c37dce3dfa3a0f445b Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH 1/4] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  22 +++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 151 ++
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 +++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 -
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h|  83 +-
 .../Parser/cxx2c-expansion-statements.cpp |  80 +-
 9 files changed, 365 insertions(+), 50 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d97bc41302c26..fea25ef6a0734 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5842,6 +5842,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b40c96fd48851..3b14f4d605b61 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13177,6 +13177,9 @@ class Sema final : public SemaBase {
 
   /// We are performing partial ordering for template template parameters.
   PartialOrderingTTP,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13372,6 +13375,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15644,6 +15653,19 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult
+  BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
+  Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index e0c1d304e8290..75d5a76c04a32 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -476,6 +476,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "TypeAliasTemplateInstantiation";
 case CodeSynthesisContext::PartialOrderingTTP:
   return "PartialOrderingTTP";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 96c0d9be9451c..f1cd2baa9ae39 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,23 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *Expan

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-12-05 Thread via llvm-branch-commits

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

>From 1861f5a04b849455139583c37dce3dfa3a0f445b Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH 1/4] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  22 +++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 151 ++
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 +++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 -
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h|  83 +-
 .../Parser/cxx2c-expansion-statements.cpp |  80 +-
 9 files changed, 365 insertions(+), 50 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d97bc41302c26..fea25ef6a0734 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5842,6 +5842,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b40c96fd48851..3b14f4d605b61 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13177,6 +13177,9 @@ class Sema final : public SemaBase {
 
   /// We are performing partial ordering for template template parameters.
   PartialOrderingTTP,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13372,6 +13375,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15644,6 +15653,19 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult
+  BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
+  Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index e0c1d304e8290..75d5a76c04a32 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -476,6 +476,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "TypeAliasTemplateInstantiation";
 case CodeSynthesisContext::PartialOrderingTTP:
   return "PartialOrderingTTP";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 96c0d9be9451c..f1cd2baa9ae39 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,23 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *Expan

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-12-03 Thread via llvm-branch-commits

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

>From ce432df0abadee6cec9eedcfa44f8f9f70663c69 Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH 1/4] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  22 +++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 151 ++
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 +++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 -
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h|  83 +-
 .../Parser/cxx2c-expansion-statements.cpp |  80 +-
 9 files changed, 365 insertions(+), 50 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ca862316a2f27..d4783c1c9677d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5827,6 +5827,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 786e53a2e179a..4d25143cffaf4 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13176,6 +13176,9 @@ class Sema final : public SemaBase {
 
   /// We are performing partial ordering for template template parameters.
   PartialOrderingTTP,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13371,6 +13374,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15643,6 +15652,19 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult
+  BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
+  Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index e0c1d304e8290..75d5a76c04a32 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -476,6 +476,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "TypeAliasTemplateInstantiation";
 case CodeSynthesisContext::PartialOrderingTTP:
   return "PartialOrderingTTP";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 96c0d9be9451c..f1cd2baa9ae39 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,23 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *Expan

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-12-03 Thread via llvm-branch-commits

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

>From ce432df0abadee6cec9eedcfa44f8f9f70663c69 Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH 1/4] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  22 +++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 151 ++
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 +++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 -
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h|  83 +-
 .../Parser/cxx2c-expansion-statements.cpp |  80 +-
 9 files changed, 365 insertions(+), 50 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ca862316a2f27..d4783c1c9677d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5827,6 +5827,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 786e53a2e179a..4d25143cffaf4 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13176,6 +13176,9 @@ class Sema final : public SemaBase {
 
   /// We are performing partial ordering for template template parameters.
   PartialOrderingTTP,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13371,6 +13374,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15643,6 +15652,19 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult
+  BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
+  Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index e0c1d304e8290..75d5a76c04a32 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -476,6 +476,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "TypeAliasTemplateInstantiation";
 case CodeSynthesisContext::PartialOrderingTTP:
   return "PartialOrderingTTP";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 96c0d9be9451c..f1cd2baa9ae39 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,23 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *Expan

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-12-01 Thread via llvm-branch-commits

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

>From b85d1e42886db4f86efa241fdd02135ff8423682 Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  22 +++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 151 ++
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 +++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 -
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h| 110 -
 .../Parser/cxx2c-expansion-statements.cpp |  78 -
 9 files changed, 390 insertions(+), 50 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ca862316a2f27..d4783c1c9677d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5827,6 +5827,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 786e53a2e179a..4d25143cffaf4 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13176,6 +13176,9 @@ class Sema final : public SemaBase {
 
   /// We are performing partial ordering for template template parameters.
   PartialOrderingTTP,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13371,6 +13374,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15643,6 +15652,19 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult
+  BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
+  Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index e0c1d304e8290..75d5a76c04a32 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -476,6 +476,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "TypeAliasTemplateInstantiation";
 case CodeSynthesisContext::PartialOrderingTTP:
   return "PartialOrderingTTP";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index c74ed63d3295a..acb28d6bbdcfb 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,23 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *Expansi

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-12-01 Thread via llvm-branch-commits

Sirraide wrote:

> No comments here, everything looks reasonable, but I've burned out on review 
> of this, so quitting this patch set. I'll come back when we get the other 2 
> settled/ready (another time...).

Fair enough haha, and thanks for the reviews so far!

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-12-01 Thread Erich Keane via llvm-branch-commits

https://github.com/erichkeane commented:

No comments here, everything looks reasonable, but I've burned out on review of 
this, so quitting this patch set.  I'll come back when we get the other 2 
settled/ready (another time...).

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-11-28 Thread via llvm-branch-commits

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

>From c4c6899f6e48afdf85611f7a66bdf63f456f9bbb Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  22 +++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 151 ++
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 +++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 -
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h| 110 -
 .../Parser/cxx2c-expansion-statements.cpp |  78 -
 9 files changed, 390 insertions(+), 50 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ca862316a2f27..d4783c1c9677d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5827,6 +5827,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 786e53a2e179a..4d25143cffaf4 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13176,6 +13176,9 @@ class Sema final : public SemaBase {
 
   /// We are performing partial ordering for template template parameters.
   PartialOrderingTTP,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13371,6 +13374,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15643,6 +15652,19 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult
+  BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
+  Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index e0c1d304e8290..75d5a76c04a32 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -476,6 +476,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "TypeAliasTemplateInstantiation";
 case CodeSynthesisContext::PartialOrderingTTP:
   return "PartialOrderingTTP";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index c74ed63d3295a..acb28d6bbdcfb 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,23 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *Expansi

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-11-28 Thread via llvm-branch-commits

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

>From c4c6899f6e48afdf85611f7a66bdf63f456f9bbb Mon Sep 17 00:00:00 2001
From: Sirraide 
Date: Tue, 25 Nov 2025 20:47:23 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 3)

---
 .../clang/Basic/DiagnosticSemaKinds.td|   2 +
 clang/include/clang/Sema/Sema.h   |  22 +++
 clang/lib/Frontend/FrontendActions.cpp|   2 +
 clang/lib/Sema/SemaExpand.cpp | 151 ++
 clang/lib/Sema/SemaTemplateInstantiate.cpp|  29 +++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  38 -
 clang/lib/Sema/SemaTemplateVariadic.cpp   |   8 +-
 clang/lib/Sema/TreeTransform.h| 110 -
 .../Parser/cxx2c-expansion-statements.cpp |  78 -
 9 files changed, 390 insertions(+), 50 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ca862316a2f27..d4783c1c9677d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5827,6 +5827,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 786e53a2e179a..4d25143cffaf4 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13176,6 +13176,9 @@ class Sema final : public SemaBase {
 
   /// We are performing partial ordering for template template parameters.
   PartialOrderingTTP,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13371,6 +13374,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15643,6 +15652,19 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult
+  BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
+  Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index e0c1d304e8290..75d5a76c04a32 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -476,6 +476,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "TypeAliasTemplateInstantiation";
 case CodeSynthesisContext::PartialOrderingTTP:
   return "PartialOrderingTTP";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index c74ed63d3295a..acb28d6bbdcfb 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,23 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *Expansi

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-11-28 Thread via llvm-branch-commits

github-actions[bot] wrote:


# :penguin: Linux x64 Test Results

* 3053 tests passed
* 7 tests skipped

All tests passed but another part of the build **failed**. Click on a failure 
below to see the details.


tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGDecl.cpp.o

```
FAILED: tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGDecl.cpp.o
sccache /opt/llvm/bin/clang++ -DCLANG_EXPORTS -DGTEST_HAS_RTTI=0 -D_DEBUG 
-D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE 
-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS 
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/lib/CodeGen
 -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen 
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include 
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include
 -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include 
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -gmlt 
-fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror 
-Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra 
-Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers 
-pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough 
-Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor 
-Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion 
-Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported 
-fdiagnostics-color -ffunction-sections -fdata-sections -fno-common 
-Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG -std=c++17  
-fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT 
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGDecl.cpp.o -MF 
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGDecl.cpp.o.d -o 
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGDecl.cpp.o -c 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen/CGDecl.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen/CGDecl.cpp:53:11:
 error: enumeration value 'CXXExpansionStmt' not handled in switch 
[-Werror,-Wswitch]
53 |   switch (D.getKind()) {
|   ^~~
1 error generated.
```


tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGStmt.cpp.o

```
FAILED: tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGStmt.cpp.o
sccache /opt/llvm/bin/clang++ -DCLANG_EXPORTS -DGTEST_HAS_RTTI=0 -D_DEBUG 
-D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE 
-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS 
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/lib/CodeGen
 -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen 
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include 
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include
 -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include 
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -gmlt 
-fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror 
-Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra 
-Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers 
-pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough 
-Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor 
-Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion 
-Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported 
-fdiagnostics-color -ffunction-sections -fdata-sections -fno-common 
-Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG -std=c++17  
-fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT 
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGStmt.cpp.o -MF 
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGStmt.cpp.o.d -o 
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGStmt.cpp.o -c 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen/CGStmt.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen/CGStmt.cpp:100:11:
 error: 5 enumeration values not handled in switch: 
'CXXIteratingExpansionStmtPatternClass', 
'CXXEnumeratingExpansionStmtPatternClass', 
'CXXDestructuringExpansionStmtPatternClass'... [-Werror,-Wswitch]
100 |   switch (S->getStmtClass()) {
|   ^
1 error generated.
```


If these failures are unrelated to your changes (for example tests are broken 
or flaky at HEAD), please open an issue at 
https://github.com/llvm/llvm-project/issues and add the `infrastructure` label.

https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-11-28 Thread via llvm-branch-commits

https://github.com/Sirraide ready_for_review 
https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-11-28 Thread via llvm-branch-commits

llvmbot wrote:




@llvm/pr-subscribers-clang-codegen

Author: None (Sirraide)


Changes



---

Patch is 32.88 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/169682.diff


9 Files Affected:

- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2) 
- (modified) clang/include/clang/Sema/Sema.h (+22) 
- (modified) clang/lib/Frontend/FrontendActions.cpp (+2) 
- (modified) clang/lib/Sema/SemaExpand.cpp (+151) 
- (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+26-3) 
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+37-1) 
- (modified) clang/lib/Sema/SemaTemplateVariadic.cpp (+6-2) 
- (modified) clang/lib/Sema/TreeTransform.h (+105-5) 
- (modified) clang/test/Parser/cxx2c-expansion-statements.cpp (+39-39) 


``diff
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ca862316a2f27..d4783c1c9677d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5827,6 +5827,8 @@ def note_template_nsdmi_here : Note<
   "in instantiation of default member initializer %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+  "in instantiation of expansion statement requested here">;
 def note_template_exception_spec_instantiation_here : Note<
   "in instantiation of exception specification for %0 requested here">;
 def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 786e53a2e179a..4d25143cffaf4 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13176,6 +13176,9 @@ class Sema final : public SemaBase {
 
   /// We are performing partial ordering for template template parameters.
   PartialOrderingTTP,
+
+  /// We are instantiating an expansion statement.
+  ExpansionStmtInstantiation,
 } Kind;
 
 /// Whether we're substituting into constraints.
@@ -13371,6 +13374,12 @@ class Sema final : public SemaBase {
   concepts::Requirement *Req,
   SourceRange InstantiationRange = SourceRange());
 
+/// \brief Note that we are substituting the body of an expansion 
statement.
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+  CXXExpansionStmtPattern *ExpansionStmt,
+  ArrayRef TArgs,
+  SourceRange InstantiationRange);
+
 /// \brief Note that we are checking the satisfaction of the constraint
 /// expression inside of a nested requirement.
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15643,6 +15652,19 @@ class Sema final : public SemaBase {
   ArrayRef LifetimeExtendTemps);
 
   StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+  StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+  ExprResult
+  BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
+  Expr *Idx);
+
+  std::optional
+  ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
   ///@}
 };
 
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index e0c1d304e8290..75d5a76c04a32 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -476,6 +476,8 @@ class DefaultTemplateInstCallback : public 
TemplateInstantiationCallback {
   return "TypeAliasTemplateInstantiation";
 case CodeSynthesisContext::PartialOrderingTTP:
   return "PartialOrderingTTP";
+case CodeSynthesisContext::ExpansionStmtInstantiation:
+  return "ExpansionStmtInstantiation";
 }
 return "";
   }
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index c74ed63d3295a..acb28d6bbdcfb 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,23 @@
 using namespace clang;
 using namespace sema;
 
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+  return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+S.Context.getPointerDiffType(), VK_PRValue,
+ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *ExpansionVar,
+ ExprResult Initializer) {
+  if 

[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-11-28 Thread via llvm-branch-commits

https://github.com/Sirraide edited 
https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) (PR #169682)

2025-11-28 Thread via llvm-branch-commits

https://github.com/Sirraide edited 
https://github.com/llvm/llvm-project/pull/169682
___
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits