[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 7: Constexpr support and tests) (PR #169686)

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


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

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

---
 clang/lib/AST/ByteCode/Compiler.cpp           |   42 +
 clang/lib/AST/ByteCode/Compiler.h             |    3 +-
 clang/lib/AST/ExprConstant.cpp                |   40 +
 clang/lib/Sema/SemaDeclCXX.cpp                |    3 +
 .../cxx2c-expansion-statements-shadow.cpp     |   11 +
 clang/test/SemaCXX/cxx2c-expansion-stmts.cpp  | 1590 +++++++++++++++++
 6 files changed, 1688 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/SemaCXX/cxx2c-expansion-statements-shadow.cpp
 create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts.cpp

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index c7f074c9efc6a..0215db156e516 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5920,6 +5920,9 @@ template <class Emitter> bool Compiler<Emitter>::visitStmt(const Stmt *S) {
     return this->emitInvalid(S);
   case Stmt::LabelStmtClass:
     return this->visitStmt(cast<LabelStmt>(S)->getSubStmt());
+  case Stmt::CXXExpansionStmtInstantiationClass:
+    return this->visitCXXExpansionStmtInstantiation(
+        cast<CXXExpansionStmtInstantiation>(S));
   default: {
     if (const auto *E = dyn_cast<Expr>(S))
       return this->discard(E);
@@ -6004,6 +6007,13 @@ bool Compiler<Emitter>::visitDeclStmt(const DeclStmt *DS,
             FunctionDecl, NamespaceAliasDecl, UsingDirectiveDecl>(D))
       continue;
 
+    if (const auto *ESD = dyn_cast<CXXExpansionStmtDecl>(D)) {
+      assert(ESD->getInstantiations() && "not expanded?");
+      if (!this->visitStmt(ESD->getInstantiations()))
+        return false;
+      continue;
+    }
+
     const auto *VD = dyn_cast<VarDecl>(D);
     if (!VD)
       return false;
@@ -6590,6 +6600,38 @@ bool Compiler<Emitter>::visitCXXTryStmt(const CXXTryStmt *S) {
   return this->visitStmt(S->getTryBlock());
 }
 
+/// template for (auto x : {1, 2}) {}
+///
+/// This is not a loop from an AST perspective at all since it has already
+/// been instantiated to a list of compound statements.
+///
+/// Since we can have control flow in those compound statements, we need to
+/// handle it mostly like a loop though.
+template <class Emitter>
+bool Compiler<Emitter>::visitCXXExpansionStmtInstantiation(
+    const CXXExpansionStmtInstantiation *S) {
+  LocalScope<Emitter> WholeLoopScope(this, ScopeKind::Block);
+
+  for (const Stmt *PreambleStmt : S->getPreambleStmts()) {
+    if (!this->visitDeclStmt(cast<DeclStmt>(PreambleStmt), true))
+      return false;
+  }
+
+  LabelTy EndLabel = this->getLabel();
+  for (const Stmt *Instantiation : S->getInstantiations()) {
+    LabelTy ContinueLabel = this->getLabel();
+    LoopScope<Emitter> LS(this, S, EndLabel, ContinueLabel);
+
+    if (!this->visitStmt(Instantiation))
+      return false;
+    this->emitLabel(ContinueLabel);
+  }
+
+  this->emitLabel(EndLabel);
+
+  return WholeLoopScope.destroyLocals();
+}
+
 template <class Emitter>
 bool Compiler<Emitter>::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) {
   assert(MD->isLambdaStaticInvoker());
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index cd14f72b87f9f..551b07f9d8db0 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -249,7 +249,8 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
   bool visitDefaultStmt(const DefaultStmt *S);
   bool visitAttributedStmt(const AttributedStmt *S);
   bool visitCXXTryStmt(const CXXTryStmt *S);
-
+  bool
+  visitCXXExpansionStmtInstantiation(const CXXExpansionStmtInstantiation *S);
 protected:
   bool visitStmt(const Stmt *S);
   bool visitExpr(const Expr *E, bool DestroyToplevelScope) override;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index a464ed90f70b8..f9030cbd77515 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5968,6 +5968,12 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
       const VarDecl *VD = dyn_cast_or_null<VarDecl>(D);
       if (VD && !CheckLocalVariableDeclaration(Info, VD))
         return ESR_Failed;
+
+      if (const auto *ESD = dyn_cast<CXXExpansionStmtDecl>(D)) {
+        assert(ESD->getInstantiations() && "not expanded?");
+        return EvaluateStmt(Result, Info, ESD->getInstantiations(), Case);
+      }
+
       // Each declaration initialization is its own full-expression.
       FullExpressionRAII Scope(Info);
       if (!EvaluateDecl(Info, D, /*EvaluateConditionDecl=*/true) &&
@@ -6240,6 +6246,40 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
     return Scope.destroy() ? ESR_Succeeded : ESR_Failed;
   }
 
+  case Stmt::CXXExpansionStmtInstantiationClass: {
+    BlockScopeRAII Scope(Info);
+    const auto *Expansion = cast<CXXExpansionStmtInstantiation>(S);
+    for (const Stmt *PreambleStmt : Expansion->getPreambleStmts()) {
+      EvalStmtResult ESR = EvaluateStmt(Result, Info, PreambleStmt);
+      if (ESR != ESR_Succeeded) {
+        if (ESR != ESR_Failed && !Scope.destroy())
+          return ESR_Failed;
+        return ESR;
+      }
+    }
+
+    // No need to push an extra scope for these since they're already
+    // CompoundStmts.
+    EvalStmtResult ESR = ESR_Succeeded;
+    for (const Stmt *Instantiation : Expansion->getInstantiations()) {
+      ESR = EvaluateStmt(Result, Info, Instantiation);
+      if (ESR == ESR_Failed ||
+          ShouldPropagateBreakContinue(Info, Expansion, &Scope, ESR))
+        return ESR;
+      if (ESR != ESR_Continue) {
+        // Succeeded here actually means we encountered a 'break'.
+        assert(ESR == ESR_Succeeded || ESR == ESR_Returned);
+        break;
+      }
+    }
+
+    // Map Continue back to Succeeded if we fell off the end of the loop.
+    if (ESR == ESR_Continue)
+      ESR = ESR_Succeeded;
+
+    return Scope.destroy() ? ESR : ESR_Failed;
+  }
+
   case Stmt::SwitchStmtClass:
     return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S));
 
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index b3a02a3fd5d02..deb6342e94ef4 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -2027,6 +2027,9 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
       //   - using-enum-declaration
       continue;
 
+    case Decl::CXXExpansionStmt:
+      continue;
+
     case Decl::Typedef:
     case Decl::TypeAlias: {
       //   - typedef declarations and alias-declarations that do not define
diff --git a/clang/test/SemaCXX/cxx2c-expansion-statements-shadow.cpp b/clang/test/SemaCXX/cxx2c-expansion-statements-shadow.cpp
new file mode 100644
index 0000000000000..c82fd0b5e39be
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-expansion-statements-shadow.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -Wshadow -verify
+// expected-no-diagnostics
+
+// Test that -Wshadow doesn't fire on implicit variable declarations
+// introduced in the expansion of an expansion statement.
+
+void f() {
+  int a[4];
+  template for (int __u0; auto x : a) {}
+  template for (auto x : a) { int __u0; }
+}
diff --git a/clang/test/SemaCXX/cxx2c-expansion-stmts.cpp b/clang/test/SemaCXX/cxx2c-expansion-stmts.cpp
new file mode 100644
index 0000000000000..f98ddd0fa949d
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-expansion-stmts.cpp
@@ -0,0 +1,1590 @@
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fdeclspec -fblocks -Wno-vla-cxx-extension -fconstexpr-steps=10000 -verify=expected,old-interp
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fdeclspec -fblocks -Wno-vla-cxx-extension -fconstexpr-steps=10000 -verify=expected,new-interp -fexperimental-new-constant-interpreter
+namespace std {
+template <typename T>
+struct initializer_list {
+  const T* a;
+  const T* b;
+  initializer_list(T* a, T* b): a{a}, b{b} {}
+};
+}
+
+struct S {
+  int x;
+  constexpr S(int x) : x{x} {}
+};
+
+void g(int); // #g
+template <int n> constexpr int tg() { return n; }
+
+void f1() {
+  template for (auto x : {}) static_assert(false, "discarded");
+  template for (constexpr auto x : {}) static_assert(false, "discarded");
+  template for (auto x : {1}) g(x);
+  template for (auto x : {1, 2, 3}) g(x);
+  template for (constexpr auto x : {1}) g(x);
+  template for (constexpr auto x : {1, 2, 3}) g(x);
+  template for (constexpr auto x : {1}) tg<x>();
+  template for (constexpr auto x : {1, 2, 3})
+    static_assert(tg<x>());
+
+  template for (int x : {1, 2, 3}) g(x);
+  template for (S x : {1, 2, 3}) g(x.x);
+  template for (constexpr S x : {1, 2, 3}) tg<x.x>();
+
+  template for (int x : {"1", S(1), {1, 2}}) { // expected-error {{cannot initialize a variable of type 'int' with an lvalue of type 'const char[2]'}} \
+                                                  expected-error {{no viable conversion from 'S' to 'int'}} \
+                                                  expected-error {{excess elements in scalar initializer}} \
+                                                  expected-note 3 {{in instantiation of expansion statement requested here}}
+    g(x);
+  }
+
+  template for (constexpr auto x : {1, 2, 3, 4}) { // expected-note 3 {{in instantiation of expansion statement requested here}}
+    static_assert(tg<x>() == 4); // expected-error 3 {{static assertion failed due to requirement 'tg<x>() == 4'}} \
+                                    expected-note {{expression evaluates to '1 == 4'}} \
+                                    expected-note {{expression evaluates to '2 == 4'}} \
+                                    expected-note {{expression evaluates to '3 == 4'}}
+  }
+
+
+  template for (constexpr auto x : {1, 2}) { // expected-note 2 {{in instantiation of expansion statement requested here}}
+    static_assert(false, "not discarded"); // expected-error 2 {{static assertion failed: not discarded}}
+  }
+}
+
+template <typename T>
+void t1() {
+  template for (T x : {}) g(x);
+  template for (constexpr T x : {}) g(x);
+  template for (auto x : {}) g(x);
+  template for (constexpr auto x : {}) g(x);
+  template for (T x : {1, 2}) g(x);
+  template for (T x : {T(1), T(2)}) g(x);
+  template for (auto x : {T(1), T(2)}) g(x);
+  template for (constexpr T x : {T(1), T(2)}) static_assert(tg<x>());
+  template for (constexpr auto x : {T(1), T(2)}) static_assert(tg<x>());
+}
+
+template <typename U>
+struct s1 {
+  template <typename T>
+  void tf() {
+      template for (T x : {}) g(x);
+      template for (constexpr T x : {}) g(x);
+      template for (U x : {}) g(x);
+      template for (constexpr U x : {}) g(x);
+      template for (auto x : {}) g(x);
+      template for (constexpr auto x : {}) g(x);
+      template for (T x : {1, 2}) g(x);
+      template for (U x : {1, 2}) g(x);
+      template for (U x : {T(1), T(2)}) g(x);
+      template for (T x : {U(1), U(2)}) g(x);
+      template for (auto x : {T(1), T(2)}) g(x);
+      template for (auto x : {U(1), T(2)}) g(x);
+      template for (constexpr U x : {T(1), T(2)}) static_assert(tg<x>());
+      template for (constexpr T x : {U(1), U(2)}) static_assert(tg<x>());
+      template for (constexpr auto x : {T(1), U(2)}) static_assert(tg<x>());
+    }
+};
+
+template <typename T>
+void t2() {
+  template for (T x : {}) g(x);
+}
+
+void f2() {
+  t1<int>();
+  t1<long>();
+  s1<long>().tf<long>();
+  s1<int>().tf<int>();
+  s1<int>().tf<long>();
+  s1<long>().tf<int>();
+  t2<S>();
+  t2<S[1231]>();
+  t2<S***>();
+}
+
+template <__SIZE_TYPE__ size>
+struct String {
+  char data[size];
+
+  template <__SIZE_TYPE__ n>
+  constexpr String(const char (&str)[n]) { __builtin_memcpy(data, str, n); }
+
+  constexpr const char* begin() const { return data; }
+  constexpr const char* end() const { return data + size - 1; }
+};
+
+template <__SIZE_TYPE__ n>
+String(const char (&str)[n]) -> String<n>;
+
+// Note: Remove this test once we do support them.
+int iterating_expansion_stmts_unsupported() {
+  static constexpr String s{"abcd"};
+  int count = 0;
+  template for (constexpr auto x : s) count++; // expected-error {{iterating expansion statements are not yet supported}}
+  return count;
+}
+
+template <typename T>
+int iterating_expansion_stmts_unsupported_dependent() {
+  static constexpr String s{"abcd"};
+  int count = 0;
+  template for (auto x : T(s)) count++; // expected-error {{iterating expansion statements are not yet supported}}
+  return count;
+}
+
+void iterating_expansion_stmts_unsupported_dependent_instantiate() {
+  iterating_expansion_stmts_unsupported_dependent<String<5>>(); // expected-note {{in instantiation of}}
+}
+
+#if 0 // Disabled until we support iterating expansion statements.
+constexpr int f3() {
+  static constexpr String s{"abcd"};
+  int count = 0;
+  template for (constexpr auto x : s) count++;
+  return count;
+}
+
+template <String s>
+constexpr int tf3() {
+  int count = 0;
+  template for (constexpr auto x : s) count++;
+  return count;
+}
+
+static_assert(f3() == 4);
+static_assert(tf3<"1">() == 1);
+static_assert(tf3<"12">() == 2);
+static_assert(tf3<"123">() == 3);
+static_assert(tf3<"1234">() == 4);
+
+void f4() {
+  static constexpr String empty{""};
+  static constexpr String s{"abcd"};
+  template for (auto x : empty) static_assert(false, "not expanded");
+  template for (constexpr auto x : s) g(x);
+  template for (auto x : s) g(x);
+}
+
+struct NegativeSize {
+  static constexpr const char* str = "123";
+  constexpr const char* begin() const { return str + 3; }
+  constexpr const char* end() const { return str; }
+};
+
+void negative_size() {
+  static constexpr NegativeSize n;
+  template for (auto x : n) g(x); // expected-error {{expansion statement size is not a constant expression}} \
+                                     old-interp-note {{constexpr evaluation hit maximum step limit}} \
+                                     new-interp-note {{cannot refer to element 5 of array of 4 elements in a constant expression}} \
+                                     expected-note {{in call to}}
+  template for (constexpr auto x : n) g(x); // expected-error {{expansion statement size is not a constant expression}} \
+                                               old-interp-note {{constexpr evaluation hit maximum step limit}} \
+                                               new-interp-note {{cannot refer to element 5 of array of 4 elements in a constant expression}} \
+                                               expected-note {{in call to}}
+}
+
+template <typename T, __SIZE_TYPE__ size>
+struct Array {
+  T data[size]{};
+  constexpr const T* begin() const { return data; }
+  constexpr const T* end() const { return data + size; }
+};
+
+struct NotInt {
+  struct iterator {};
+  constexpr iterator begin() const { return {}; }
+  constexpr iterator end() const { return {}; }
+};
+
+void not_int() {
+  static constexpr NotInt ni;
+  template for (auto x : ni) g(x); // expected-error {{invalid operands to binary expression}} \
+                                      expected-note {{while attempting to construct 'begin - begin' with iterator type 'iterator'}}
+}
+
+static constexpr Array<int, 3> integers{1, 2, 3};
+
+constexpr int friend_func();
+
+struct Private {
+  friend constexpr int friend_func();
+
+private:
+  constexpr const int* begin() const { return integers.begin(); } // expected-note 3 {{declared private here}}
+  constexpr const int* end() const { return integers.end(); } // expected-note 3 {{declared private here}}
+
+public:
+  static constexpr int member_func() {
+    int sum = 0;
+    static constexpr Private p1;
+    template for (auto x : p1) sum += x;
+    return sum;
+  }
+};
+
+struct Protected {
+  friend constexpr int friend_func();
+
+protected:
+  constexpr const int* begin() const { return integers.begin(); } // expected-note 3 {{declared protected here}}
+  constexpr const int* end() const { return integers.end(); } // expected-note 3 {{declared protected here}}
+
+public:
+  static constexpr int member_func() {
+    int sum = 0;
+    static constexpr Protected p1;
+    template for (auto x : p1) sum += x;
+    return sum;
+  }
+};
+
+void access_control() {
+  static constexpr Private p1;
+  template for (auto x : p1) g(x); // expected-error 3 {{'begin' is a private member of 'Private'}} expected-error 3 {{'end' is a private member of 'Private'}}
+
+  static constexpr Protected p2;
+  template for (auto x : p2) g(x); // expected-error 3 {{'begin' is a protected member of 'Protected'}} expected-error 3 {{'end' is a protected member of 'Protected'}}
+}
+
+constexpr int friend_func() {
+  int sum = 0;
+  static constexpr Private p1;
+  template for (auto x : p1) sum += x;
+
+  static constexpr Protected p2;
+  template for (auto x : p2) sum += x;
+  return sum;
+}
+
+static_assert(friend_func() == 12);
+static_assert(Private::member_func() == 6);
+static_assert(Protected::member_func() == 6);
+
+struct SizeNotICE {
+  struct iterator {
+    friend constexpr iterator operator+(iterator a, __PTRDIFF_TYPE__) { return a; }
+    friend constexpr __PTRDIFF_TYPE__ operator-(iterator, iterator) { return 7; }
+    constexpr iterator operator++() { return *this; }
+    int constexpr operator*() const { return 7; }
+
+    // NOT constexpr!
+    friend int operator!=(iterator, iterator) { return 7; } // expected-note {{declared here}}
+  };
+  constexpr iterator begin() const { return {}; }
+  constexpr iterator end() const { return {}; }
+};
+
+struct PlusMissing {
+  struct iterator {
+    friend constexpr __PTRDIFF_TYPE__ operator-(iterator, iterator) { return 7; }
+    constexpr iterator operator++() { return *this; }
+    int constexpr operator*() const { return 7; }
+  };
+  constexpr iterator begin() const { return {}; }
+  constexpr iterator end() const { return {}; }
+};
+
+struct DerefMissing {
+  struct iterator {
+    friend constexpr __PTRDIFF_TYPE__ operator-(iterator, iterator) { return 7; }
+    friend constexpr iterator operator+(iterator a, __PTRDIFF_TYPE__) { return a; }
+  };
+  constexpr iterator begin() const { return {}; }
+  constexpr iterator end() const { return {}; }
+};
+
+struct MinusMissing {
+  struct iterator {};
+  constexpr iterator begin() const { return {}; }
+  constexpr iterator end() const { return {}; }
+};
+
+void missing_funcs() {
+  static constexpr SizeNotICE s1;
+  static constexpr PlusMissing s2;
+  static constexpr DerefMissing s3;
+  static constexpr MinusMissing s4;
+
+  template for (auto x : s1) g(x); // expected-error {{expansion statement size is not a constant expression}} \
+                                      expected-note {{non-constexpr function 'operator!=' cannot be used in a constant expression}} \
+                                      expected-note {{in call to}}
+
+  template for (auto x : s2) g(x); // expected-error {{invalid operands to binary expression}}
+  template for (auto x : s3) g(x); // expected-error {{indirection requires pointer operand ('iterator' invalid)}}
+  template for (auto x : s4) g(x); // expected-error {{invalid operands to binary expression ('iterator' and 'iterator')}} \
+                                      expected-note {{while attempting to construct 'begin - begin' with iterator type 'iterator'}}
+}
+
+namespace adl {
+struct ADL {
+
+};
+
+constexpr const int* begin(const ADL&) { return integers.begin(); }
+constexpr const int* end(const ADL&) { return integers.end(); }
+}
+
+namespace adl_error {
+struct ADLError1 {
+  constexpr const int* begin() const { return integers.begin(); }
+};
+
+struct ADLError2 {
+  constexpr const int* end() const { return integers.end(); }
+};
+
+constexpr const int* begin(const ADLError2&) { return integers.begin(); }
+constexpr const int* end(const ADLError1&) { return integers.end(); }
+}
+
+namespace adl_both {
+static constexpr Array<int, 5> integers2{1, 2, 3, 4, 5};
+struct ADLBoth {
+  // Test that member begin/end are preferred over ADl begin/end. These return
+  // pointers to a different array.
+  constexpr const int* begin() const { return integers2.begin(); }
+  constexpr const int* end() const { return integers2.end(); }
+};
+
+constexpr const int* begin(const ADLBoth&) { return integers.begin(); }
+constexpr const int* end(const ADLBoth&) { return integers.end(); }
+}
+
+constexpr int adl_begin_end() {
+  static constexpr adl::ADL a;
+  int sum = 0;
+  template for (auto x : a) sum += x;
+  template for (constexpr auto x : a) sum += x;
+  return sum;
+}
+
+static_assert(adl_begin_end() == 12);
+
+void adl_mixed() {
+  static constexpr adl_error::ADLError1 a1;
+  static constexpr adl_error::ADLError2 a2;
+
+  // These are actually destructuring because there is no
+  // valid begin/end pair.
+  template for (auto x : a1) g(x);
+  template for (auto x : a2) g(x);
+}
+
+constexpr int adl_both_test() {
+  static constexpr adl_both::ADLBoth a;
+  int sum = 0;
+  template for (auto x : a) sum += x;
+  return sum;
+}
+
+static_assert(adl_both_test() == 15);
+#endif // 0
+
+struct A {};
+struct B { int x = 1; };
+struct C { int a = 1, b = 2, c = 3; };
+struct D {
+  int a = 1;
+  int* b = nullptr;
+  const char* c = "3";
+};
+
+struct Nested {
+  A a;
+  B b;
+  C c;
+};
+
+struct PrivateDestructurable {
+  friend void destructurable_friend();
+private:
+  int a, b; // expected-note 4 {{declared private here}}
+};
+
+struct ProtectedDestructurable {
+  friend void destructurable_friend();
+protected:
+  int a, b; // expected-note 4 {{declared protected here}}
+};
+
+void destructuring() {
+  static constexpr A a;
+  static constexpr B b;
+  static constexpr C c;
+  static constexpr D d;
+
+  template for (auto x : a) static_assert(false, "not expanded");
+  template for (constexpr auto x : a) static_assert(false, "not expanded");
+
+  template for (auto x : b) g(x);
+  template for (constexpr auto x : b) g(x);
+
+  template for (auto x : c) g(x);
+  template for (constexpr auto x : c) g(x);
+
+  template for (auto x : d) { // expected-note 2 {{in instantiation of expansion statement requested here}}
+    // expected-note@#g {{candidate function not viable: no known conversion from 'int *' to 'int' for 1st argument}}
+    // expected-note@#g {{candidate function not viable: no known conversion from 'const char *' to 'int' for 1st argument}}
+    g(x); // expected-error 2 {{no matching function for call to 'g'}}
+
+  }
+
+  template for (constexpr auto x : d) { // expected-note 2 {{in instantiation of expansion statement requested here}}
+    // expected-note@#g {{candidate function not viable: no known conversion from 'int *const' to 'int' for 1st argument}}
+    // expected-note@#g {{candidate function not viable: no known conversion from 'const char *const' to 'int' for 1st argument}}
+    g(x); // expected-error 2 {{no matching function for call to 'g'}}
+  }
+}
+
+constexpr int array() {
+  static constexpr int x[4]{1, 2, 3, 4};
+  int sum = 0;
+  template for (auto y : x) sum += y;
+  template for (constexpr auto y : x) sum += y;
+  return sum;
+}
+
+static_assert(array() == 20);
+
+template <auto v>
+constexpr int destructure() {
+  int sum = 0;
+  template for (auto x : v) sum += x;
+  template for (constexpr auto x : v) sum += x;
+  return sum;
+}
+
+static_assert(destructure<B{10}>() == 20);
+static_assert(destructure<C{}>() == 12);
+static_assert(destructure<C{3, 4, 5}>() == 24);
+
+constexpr int nested() {
+  static constexpr Nested n;
+  int sum = 0;
+  template for (constexpr auto x : n) {
+    static constexpr auto val = x;
+    template for (auto y : val) {
+      sum += y;
+    }
+  }
+  template for (constexpr auto x : n) {
+    static constexpr auto val = x;
+    template for (constexpr auto y : val) {
+      sum += y;
+    }
+  }
+  return sum;
+}
+
+static_assert(nested() == 14);
+
+void access_control_destructurable() {
+  template for (auto x : PrivateDestructurable()) {} // expected-error 2 {{cannot bind private member 'a' of 'PrivateDestructurable'}} \
+                                                        expected-error 2 {{cannot bind private member 'b' of 'PrivateDestructurable'}}
+
+  template for (auto x : ProtectedDestructurable()) {} // expected-error 2 {{cannot bind protected member 'a' of 'ProtectedDestructurable'}} \
+                                                          expected-error 2 {{cannot bind protected member 'b' of 'ProtectedDestructurable'}}
+
+  struct Derived : ProtectedDestructurable {
+    void f() {
+      template for (auto x : *this) {}
+    }
+  };
+}
+
+void destructurable_friend() {
+  template for (auto x : PrivateDestructurable()) {}
+  template for (auto x : ProtectedDestructurable()) {}
+}
+
+struct Placeholder {
+  A get_value() const { return {}; }
+  __declspec(property(get = get_value)) A a;
+};
+
+void placeholder() {
+  template for (auto x: Placeholder().a) {}
+}
+
+union Union { int a; long b;};
+
+struct MemberPtr {
+  void f() {}
+};
+
+void overload_set(int); // expected-note 2 {{possible target for call}}
+void overload_set(long); // expected-note 2 {{possible target for call}}
+
+void invalid_types() {
+  template for (auto x : void()) {} // expected-error {{cannot expand expression of incomplete type 'void'}}
+  template for (auto x : 1) {} // expected-error {{cannot expand expression of type 'int'}}
+  template for (auto x : 1.f) {} // expected-error {{cannot expand expression of type 'float'}}
+  template for (auto x : 'c') {} // expected-error {{cannot expand expression of type 'char'}}
+  template for (auto x : invalid_types) {} // expected-error {{cannot expand expression of type 'void ()'}}
+  template for (auto x : &invalid_types) {} // expected-error {{cannot expand expression of type 'void (*)()'}}
+  template for (auto x : &MemberPtr::f) {} // expected-error {{cannot expand expression of type 'void (MemberPtr::*)()'}}
+  template for (auto x : overload_set) {} // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
+  template for (auto x : &overload_set) {} // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
+  template for (auto x : nullptr) {} // expected-error {{cannot expand expression of type 'std::nullptr_t'}}
+  template for (auto x : __builtin_strlen) {} // expected-error {{builtin functions must be directly called}}
+  template for (auto x : Union()) {} // expected-error {{cannot expand expression of type 'Union'}}
+  template for (auto x : (char*)nullptr) {} // expected-error {{cannot expand expression of type 'char *'}}
+  template for (auto x : []{}) {} // expected-error {{cannot expand lambda closure type}}
+  template for (auto x : [x=3]{}) {} // expected-error {{cannot expand lambda closure type}}
+  template for (auto x : [](auto){}) {} // expected-error {{cannot expand lambda closure type}}
+  template for (auto x : []<typename>(){}) {} // expected-error {{cannot expand lambda closure type}}
+}
+
+constexpr int string_literals() {
+  int i = 0;
+  template for (auto x : "1234") i += int(x);
+  template for (auto x : L"1234") i += int(x);
+  template for (auto x : u"1234") i += int(x);
+  template for (auto x : U"1234") i += int(x);
+  template for (auto x : R"(1234)") i += int(x);
+  return i;
+}
+
+static_assert(string_literals() == 5 * (int('1') + int('2') + int('3') + int('4')));
+
+struct Bitfields {
+  int x : 5 = 1;
+  int y : 5 = 2;
+  int _ : 5 = 3;
+};
+
+constexpr int bitfields() {
+  int i = 0;
+  template for (auto x : Bitfields()) i += x;
+  return i;
+}
+
+static_assert(bitfields() == 6);
+
+struct EnumMember {
+  enum {
+    x, y, z
+  };
+
+  enum class Foo {
+    a, b, c
+  };
+
+  using enum Foo;
+};
+
+constexpr int enum_member() {
+  int i = 0;
+  template for (auto x : EnumMember()) i += x;
+  return i;
+}
+
+static_assert(enum_member() == 0);
+
+struct Mutable {
+  mutable int x{};
+};
+
+constexpr int mutable_member() {
+  const Mutable m;
+  template for (auto& i : m) i = 42;
+  return m.x;
+}
+
+static_assert(mutable_member() == 42);
+
+constexpr int vector_type() {
+  __attribute__((vector_size(sizeof(int) * 4))) int vec{1, 2, 3, 4};
+  int i = 0;
+  template for (auto x : vec) i += x;
+  return i;
+}
+
+static_assert(vector_type() == 10);
+
+constexpr int complex() {
+  _Complex int c{1, 2};
+  int i = 0;
+  template for (auto x : c) i += x;
+  return i;
+}
+
+static_assert(complex() == 3);
+
+#if 0 // Disabled until we support iterating expansion statements.
+struct BeginOnly {
+  int x{1};
+  constexpr const int* begin() const { return nullptr; }
+};
+
+struct EndOnly {
+  int x{2};
+  constexpr const int* end() const { return nullptr; }
+};
+
+namespace adl1 {
+struct BeginOnly {
+  int x{3};
+};
+constexpr const int* begin(const BeginOnly&) { return nullptr; }
+}
+
+namespace adl2 {
+struct EndOnly {
+  int x{4};
+};
+constexpr const int* end(const EndOnly&) { return nullptr; }
+}
+
+namespace adl3 {
+struct BeginOnlyDeleted {
+  int x{4};
+};
+constexpr const int* begin(const BeginOnlyDeleted&) = delete;
+}
+
+namespace adl4 {
+struct EndOnlyDeleted {
+  int x{4};
+};
+constexpr const int* end(const EndOnlyDeleted&) = delete;
+}
+
+namespace adl5 {
+struct BothDeleted {
+  int x{4};
+};
+constexpr const int* begin(const BothDeleted&) = delete; // expected-note {{candidate function has been explicitly deleted}}
+constexpr const int* end(const BothDeleted&) = delete;
+}
+
+namespace adl6 {
+struct BeginNotViable {
+  int x{4};
+};
+constexpr const int* begin(int) { return nullptr; }
+}
+
+namespace adl7 {
+struct EndNotViable {
+  int x{4};
+};
+constexpr const int* end(int) { return nullptr; }
+}
+
+namespace adl8 {
+struct BothNotViable {
+  int x{4};
+};
+constexpr const int* begin(int) { return nullptr; }
+constexpr const int* end(int) { return nullptr; }
+}
+
+namespace adl9 {
+struct BeginDeleted {
+  int x{4};
+};
+constexpr const int* begin(const BeginDeleted&) = delete; // expected-note {{candidate function has been explicitly deleted}}
+constexpr const int* end(const BeginDeleted&) { return nullptr; }
+}
+
+namespace adl10 {
+struct EndDeleted {
+  int x{4};
+};
+constexpr const int* begin(const EndDeleted&) { return nullptr; }
+constexpr const int* end(const EndDeleted&) = delete; // expected-note {{candidate function has been explicitly deleted}}
+}
+
+void unpaired_begin_end() {
+  static constexpr adl1::BeginOnly begin_only;
+  static constexpr adl2::EndOnly end_only;
+  static constexpr adl3::BeginOnlyDeleted begin_only_deleted;
+  static constexpr adl4::EndOnlyDeleted end_only_deleted;
+  static constexpr adl5::BothDeleted both_deleted;
+  static constexpr adl6::BeginNotViable begin_not_viable;
+  static constexpr adl7::EndNotViable end_not_viable;
+  static constexpr adl8::BothNotViable both_not_viable;
+  static constexpr adl9::BeginDeleted begin_deleted;
+  static constexpr adl10::EndDeleted end_deleted;
+
+  // Ok, these are destructuring because there is no valid pair.
+  template for (auto x : begin_only) {}
+  template for (auto x : begin_only_deleted) {}
+  template for (auto x : begin_not_viable) {}
+  template for (auto x : end_only) {}
+  template for (auto x : end_only_deleted) {}
+  template for (auto x : end_not_viable) {}
+
+  // This is also ok because overload resolution fails.
+  template for (auto x : both_not_viable) {}
+
+  // These are invalid because overload resolution succeeds (even though
+  // there is no usable begin() and/or end()).
+  template for (auto x : both_deleted) {} // expected-error {{call to deleted function 'begin'}} \
+                                             expected-note {{when looking up 'begin' function for range expression of type 'const adl5::BothDeleted'}}~
+
+  template for (auto x : begin_deleted) {} // expected-error {{call to deleted function 'begin'}} \
+                                              expected-note {{when looking up 'begin' function for range expression of type 'const adl9::BeginDeleted'}}
+
+  template for (auto x : end_deleted) {} // expected-error {{call to deleted function 'end'}} \
+                                            expected-note {{when looking up 'end' function for range expression of type 'const adl10::EndDeleted'}}
+}
+#endif // 0
+
+// Examples taken from [stmt.expand].
+namespace stmt_expand_examples {
+consteval int f(auto const&... Containers) {
+  int result = 0;
+  template for (auto const& c : {Containers...}) {      // OK, enumerating expansion statement
+    result += c[0];
+  }
+  return result;
+}
+constexpr int c1[] = {1, 2, 3};
+constexpr int c2[] = {4, 3, 2, 1};
+static_assert(f(c1, c2) == 5);
+
+#if 0 // Disabled until we support iterating expansion statements.
+// TODO: This entire example should work without issuing any diagnostics once
+// we have full support for references to constexpr variables (P2686).
+consteval int f() {
+  constexpr Array<int, 3> arr {1, 2, 3}; // expected-note{{add 'static' to give it a constant address}} \
+                                            new-interp-note 5 {{add 'static' to give it a constant address}}
+
+  int result = 0;
+
+  // expected-error@#invalid-ref {{constexpr variable '__range1' must be initialized by a constant expression}}
+  // expected-error@#invalid-ref {{constexpr variable '__begin1' must be initialized by a constant expression}}
+  // expected-error@#invalid-ref {{constexpr variable '__end1' must be initialized by a constant expression}}
+  // expected-note@#invalid-ref {{reference to 'arr' is not a constant expression}}
+  // old-interp-error@#invalid-ref {{expansion statement size is not a constant expression}}
+  // old-interp-note@#invalid-ref {{in call to}}
+  // old-interp-note@#invalid-ref 3 {{member call on variable '__range1' whose value is not known}}
+  // old-interp-note@#invalid-ref 3 {{declared here}}
+  // new-interp-error@#invalid-ref 3 {{constexpr variable '__iter1' must be initialized by a constant expression}}
+  // new-interp-note@#invalid-ref 5 {{pointer to subobject of 'arr' is not a constant expression}}
+  // new-interp-note@#invalid-ref 3 {{in instantiation of expansion statement}}
+  template for (constexpr int s : arr) { // #invalid-ref                // OK, iterating expansion statement
+    result += sizeof(char[s]);
+  }
+  return result;
+}
+static_assert(f() == 6); // old-interp-error {{static assertion failed due to requirement 'f() == 6'}} old-interp-note {{expression evaluates to '0 == 6'}}
+#endif // 0
+
+struct S {
+  int i;
+  short s;
+};
+
+consteval long f(S s) {
+  long result = 0;
+  template for (auto x : s) {                           // OK, destructuring expansion statement
+    result += sizeof(x);
+  }
+  return result;
+}
+static_assert(f(S{}) == sizeof(int) + sizeof(short));
+}
+
+void not_constant_expression() {
+  template for (constexpr auto x : B()) { // expected-error {{constexpr variable '[__u0]' must be initialized by a constant expression}} \
+                                             expected-note {{reference to temporary is not a constant expression}} \
+                                             expected-note {{temporary created here}} \
+                                             expected-error {{constexpr variable 'x' must be initialized by a constant expression}} \
+                                             expected-note {{in instantiation of expansion statement requested here}} \
+                                             old-interp-note {{read of variable '[__u0]' whose value is not known}} \
+                                             old-interp-note {{declared here}} \
+                                             new-interp-note {{cannot access field of null pointer}}
+    g(x);
+  }
+}
+
+constexpr int references_enumerating() {
+  int x = 1, y = 2, z = 3;
+  template for (auto& x : {x, y, z}) { ++x; }
+  template for (auto&& x : {x, y, z}) { ++x; }
+  return x + y + z;
+}
+
+static_assert(references_enumerating() == 12);
+
+constexpr int references_destructuring() {
+  C c;
+  template for (auto& x : c) { ++x; }
+  template for (auto&& x : c) { ++x; }
+  return c.a + c.b + c.c;
+}
+
+static_assert(references_destructuring() == 12);
+
+constexpr int break_continue() {
+  int sum = 0;
+  template for (auto x : {1, 2}) {
+    break;
+    sum += x;
+  }
+
+  template for (auto x : {3, 4}) {
+    continue;
+    sum += x;
+  }
+
+  template for (auto x : {5, 6}) {
+    if (x == 6) break;
+    sum += x;
+  }
+
+  template for (auto x : {7, 8, 9}) {
+    if (x == 8) continue;
+    sum += x;
+  }
+
+  return sum;
+}
+
+static_assert(break_continue() == 21);
+
+constexpr int break_continue_nested() {
+  int sum = 0;
+
+  template for (auto x : {1, 2}) {
+    template for (auto y : {3, 4}) {
+      if (x == 2) break;
+      sum += y;
+    }
+    sum += x;
+  }
+
+  template for (auto x : {5, 6}) {
+    template for (auto y : {7, 8}) {
+      if (x == 6) continue;
+      sum += y;
+    }
+    sum += x;
+  }
+
+  return sum;
+}
+
+static_assert(break_continue_nested() == 36);
+
+template <typename ...Ts>
+void unexpanded_pack_bad(Ts ...ts) {
+  template for (auto x : ts) {} // expected-error {{expression contains unexpanded parameter pack 'ts'}}
+  template for (Ts x : {1, 2}) {} // expected-error {{declaration type contains unexpanded parameter pack 'Ts'}}
+  template for (auto x : {ts}) {} // expected-error {{initializer contains unexpanded parameter pack}} \
+  // expected-note {{in instantiation of expansion statement requested here}}
+}
+
+struct E { int x, y; constexpr E(int x, int y) : x{x}, y{y} {}};
+
+template <typename ...Es>
+constexpr int unexpanded_pack_good(Es ...es) {
+  int sum = 0;
+  ([&] {
+    template for (auto x : es) sum += x;
+    template for (Es e : {{5, 6}, {7, 8}}) sum += e.x + e.y;
+  }(), ...);
+  return sum;
+}
+
+static_assert(unexpanded_pack_good(E{1, 2}, E{3, 4}) == 62);
+
+// Ensure that the expansion-initializer is evaluated even if it expands
+// to nothing.
+//
+// This is related to CWG 3048. Note that we currently still model this as
+// a DecompositionDecl w/ zero bindings.
+constexpr bool empty_side_effect() {
+  struct A {
+    constexpr A(bool& b) {
+      b = true;
+    }
+  };
+
+  bool constructed = false;
+  template for (auto x : A(constructed)) static_assert(false);
+  return constructed;
+}
+
+static_assert(empty_side_effect());
+
+namespace apply_lifetime_extension {
+struct T {
+  int& x;
+  constexpr T(int& x) noexcept : x(x) {}
+  constexpr ~T() noexcept { x = 42; }
+};
+
+constexpr const T& f(const T& t) noexcept { return t; }
+constexpr T g(int& x) noexcept { return T(x); }
+
+// CWG 3043:
+//
+// Lifetime extension only applies to destructuring expansion statements
+// (enumerating statements don't have a range variable, and the range variable
+// of iterating statements is constexpr).
+constexpr int lifetime_extension() {
+  int x = 5;
+  int sum  = 0;
+  template for (auto e : f(g(x))) {
+    sum += x;
+  }
+  return sum + x;
+}
+
+template <typename T>
+constexpr int lifetime_extension_instantiate_expansions() {
+  int x = 5;
+  int sum  = 0;
+  template for (T e : f(g(x))) {
+    sum += x;
+  }
+  return sum + x;
+}
+
+template <typename T>
+constexpr int lifetime_extension_dependent_expansion_stmt() {
+  int x = 5;
+  int sum  = 0;
+  template for (int e : f(g((T&)x))) {
+    sum += x;
+  }
+  return sum + x;
+}
+
+template <typename U>
+struct foo {
+  template <typename T>
+  constexpr int lifetime_extension_multiple_instantiations() {
+      int x = 5;
+      int sum  = 0;
+      template for (T e : f(g((U&)x))) {
+        sum += x;
+      }
+      return sum + x;
+  }
+};
+
+static_assert(lifetime_extension() == 47);
+static_assert(lifetime_extension_instantiate_expansions<int>() == 47);
+static_assert(lifetime_extension_dependent_expansion_stmt<int>() == 47);
+static_assert(foo<int>().lifetime_extension_multiple_instantiations<int>() == 47);
+}
+
+template <typename... Ts>
+constexpr int return_from_expansion(Ts... ts) {
+  template for (int i : {1, 2, 3}) {
+    return (ts + ...);
+  }
+  __builtin_unreachable();
+}
+
+static_assert(return_from_expansion(4, 5, 6) == 15);
+
+void not_constexpr();
+
+constexpr int empty_expansion_consteval() {
+  template for (auto _ : {}) {
+    not_constexpr();
+  }
+  return 3;
+}
+
+static_assert(empty_expansion_consteval() == 3);
+
+void nested_empty_expansion() {
+  template for (auto x1 : {})
+    template for (auto x2 : {1})
+      static_assert(false);
+
+  template for (auto x1 : {1})
+    template for (auto x2 : {})
+      template for (auto x3 : {1})
+        static_assert(false);
+
+  template for (auto x1 : {})
+    template for (auto x2 : {})
+      template for (auto x3 : {})
+        template for (auto x4 : {1})
+          static_assert(false);
+
+  template for (auto x1 : {})
+    template for (auto x2 : {1})
+      template for (auto x3 : {})
+        template for (auto x4 : {1})
+          static_assert(false);
+
+  template for (auto x1 : {})
+    template for (auto x2 : {1})
+      template for (auto x4 : {1})
+        static_assert(false);
+}
+
+struct Empty {};
+
+template <typename T>
+void nested_empty_expansion_dependent() {
+  template for (auto x1 : T())
+    template for (auto x2 : {1})
+      static_assert(false);
+
+  template for (auto x1 : {1})
+    template for (auto x2 : T())
+      template for (auto x3 : {1})
+        static_assert(false);
+
+  template for (auto x1 : T())
+    template for (auto x2 : T())
+      template for (auto x3 : T())
+        template for (auto x4 : {1})
+          static_assert(false);
+
+  template for (auto x1 : T())
+    template for (auto x2 : {1})
+      template for (auto x3 : T())
+        template for (auto x4 : {1})
+          static_assert(false);
+
+  template for (auto x1 : T())
+    template for (auto x2 : {1})
+      template for (auto x4 : {1})
+        static_assert(false);
+}
+
+void nested_empty_expansion_dependent_instantiate() {
+  nested_empty_expansion_dependent<Empty>();
+}
+
+// Destructuring expansion statements using tuple_size/tuple_element/get.
+namespace std {
+template <typename>
+struct tuple_size;
+
+template <__SIZE_TYPE__, typename>
+struct tuple_element; // expected-note {{template is declared here}}
+
+namespace get_decomposition {
+struct MemberGet {
+  int x[6]{};
+
+  template <__SIZE_TYPE__ I>
+  constexpr int& get() { return x[I * 2]; }
+};
+
+struct ADLGet {
+  long x[8]{};
+};
+
+template <__SIZE_TYPE__ I>
+constexpr long& get(ADLGet& a) { return a.x[I * 2]; }
+} // namespace get_decomposition
+
+template <>
+struct tuple_size<get_decomposition::MemberGet> {
+  static constexpr __SIZE_TYPE__ value = 3;
+};
+
+template <__SIZE_TYPE__ I>
+struct tuple_element<I, get_decomposition::MemberGet> {
+  using type = int;
+};
+
+template <>
+struct tuple_size<get_decomposition::ADLGet> {
+  static constexpr __SIZE_TYPE__ value = 4;
+};
+
+template <__SIZE_TYPE__ I>
+struct tuple_element<I, get_decomposition::ADLGet> {
+  using type = long;
+};
+
+constexpr int member() {
+  get_decomposition::MemberGet m;
+  int v = 1;
+  template for (int& i : m) {
+    i = v;
+    v++;
+  }
+  return m.x[0] + m.x[2] + m.x[4];
+}
+
+constexpr long adl() {
+  get_decomposition::ADLGet m;
+  long v = 1;
+  template for (long& i : m) {
+    i = v;
+    v++;
+  }
+  return m.x[0] + m.x[2] + m.x[4] + m.x[6];
+}
+
+static_assert(member() == 6);
+static_assert(adl() == 10);
+
+struct TupleSizeOnly {};
+
+template <>
+struct tuple_size<TupleSizeOnly> {
+  static constexpr __SIZE_TYPE__ value = 3;
+};
+
+struct TupleSizeAndGet {
+  template <__SIZE_TYPE__>
+  constexpr int get() { return 1; }
+};
+
+template <>
+struct tuple_size<TupleSizeAndGet> {
+  static constexpr __SIZE_TYPE__ value = 3;
+};
+
+void invalid() {
+  template for (auto x : TupleSizeOnly()) {} // expected-error {{use of undeclared identifier 'get'}} \
+                                                expected-note {{in implicit initialization of binding declaration}}
+
+  template for (auto x : TupleSizeAndGet()) {} // expected-error {{implicit instantiation of undefined template 'std::tuple_element<0, std::TupleSizeAndGet>'}} \
+                                                  expected-note {{in implicit initialization of binding declaration}}
+}
+} // namespace std
+
+constexpr int generic_lambda() {
+  static constexpr int arr[]{1, 2, 3};
+  int sum = 0;
+  [n = 5, &sum]<class = void>() {
+    template for (constexpr auto x : arr) {
+      sum += n + x;
+    }
+  }();
+  return sum;
+}
+
+static_assert(generic_lambda() == 21);
+
+void for_range_decl_must_be_var() {
+  template for (void q() : "error") // expected-error {{expansion statement declaration must declare a variable}}
+    ;
+}
+
+void init_list_bad() {
+  template for (auto y : {{1}, {2}, {3, {4}}, {{{5}}}}); // expected-error {{cannot deduce actual type for variable 'y' with type 'auto' from initializer list}} \
+                                                            expected-note {{in instantiation of expansion statement requested here}}
+}
+
+// Test that the init statement is evaluated even if the expansion statement
+// expands to nothing.
+constexpr int init_stmt_empty_expansion() {
+#if 0 // Disabled until we support iterating expansion statements.
+  static constexpr String empty{""};
+#endif // 0
+  int x = 0;
+  template for (int _ = x += 1; auto i : {}) {}
+#if 0 // Disabled until we support iterating expansion statements.
+  template for (int _ = x += 2; auto i : empty) {}
+#endif // 0
+  template for (int _ = x += 3; auto i : Empty()) {}
+  return x;
+}
+
+static_assert(init_stmt_empty_expansion() == 4);
+
+void vla(int n) {
+  int a[n];
+  template for (int x : a) {} // expected-error {{cannot expand variable length array type 'int[n]'}}
+}
+
+template <typename T>
+void template_vla(T& a) { // expected-note {{variably modified type 'int[n]' cannot be used as a template argument}}
+  template for (int x : a) {}
+}
+
+void instantiate_template_vla(int n) {
+  int a[n];
+  template_vla(a); // expected-error {{no matching function for call to 'template_vla'}}
+}
+
+struct Incomplete; // expected-note 2 {{forward declaration of 'Incomplete'}}
+void incomplete_type(Incomplete& s) {
+  template for (int x : s) {} // expected-error {{cannot expand expression of incomplete type 'Incomplete'}}
+}
+
+template <typename T>
+void dependent_incomplete_type(T& s) {
+  template for (int x : s) {} // expected-error {{cannot expand expression of incomplete type 'Incomplete'}}
+}
+
+template void dependent_incomplete_type<Incomplete>(Incomplete&); // expected-note {{in instantiation of function template specialization 'dependent_incomplete_type<Incomplete>' requested here}}
+
+template <typename T>
+void lambda_template(T a) {
+  template for (auto x : a) {} // expected-error {{cannot expand lambda closure type}}
+}
+
+void lambda_template_call() {
+  lambda_template([]{}); // expected-note {{in instantiation of function template specialization}}
+}
+
+#if 0 // Disabled until we support iterating expansion statements.
+// CWG 3131 makes it possible to expand over non-constexpr ranges.
+namespace cwg3131 {
+constexpr int f1() {
+  int j = 0;
+  template for (auto i : Array<int, 3>{1, 2, 3}) j +=i;
+  return j;
+}
+
+constexpr int f2() {
+  Array<int, 3> a{1, 2, 3};
+  int j = 0;
+  template for (auto i : a) j +=i; // new-interp-error {{expansion statement size is not a constant expression}} \
+                                      new-interp-note {{initializer of '__range1' is not a constant expression}} \
+                                      new-interp-note {{declared here}}
+  return j;
+}
+
+static_assert(f1() == 6);
+static_assert(f2() == 6); // new-interp-error {{static assertion failed due to requirement 'f2() == 6'}} \
+                             new-interp-note {{expression evaluates to '0 == 6'}}
+
+template <typename T>
+struct Span {
+  T* data;
+  __SIZE_TYPE__ size;
+
+  template <__SIZE_TYPE__ N>
+  constexpr Span(T(&a)[N]) : data{a}, size{N} {}
+
+  constexpr auto begin() const -> T* { return data; }
+  constexpr auto end() const -> T* { return data + size; }
+};
+
+constexpr int arr[3] = { 1, 2, 3 };
+consteval Span<const int> foo() {
+  return Span<const int>(arr);
+}
+
+constexpr int f3() {
+  int r = 0;
+  template for (constexpr auto m : foo())
+    r += m;
+  return r;
+}
+
+static_assert(f3() == 6);
+}
+
+// Test that we actually do 'begin + decltype(begin - begin){i}'.
+namespace cwg3044 {
+struct DifferenceType {
+  int v;
+  explicit constexpr DifferenceType(__PTRDIFF_TYPE__ v) : v(int(v)) {}
+};
+
+struct Range {
+  struct iterator {
+    DifferenceType v;
+
+    constexpr iterator& operator++() {
+      v.v++;
+      return *this;
+    }
+
+    constexpr int operator*() const { return int(v.v); }
+    friend constexpr bool operator!=(iterator a, iterator b) { return a.v.v != b.v.v; }
+    friend constexpr iterator operator+(iterator a, DifferenceType b) {
+      return iterator{DifferenceType{int(a.v.v) + int(b.v)}};
+    }
+    friend constexpr DifferenceType operator-(iterator a, iterator b) {
+      return DifferenceType{int(a.v.v) - int(b.v.v)};
+    }
+  };
+
+  constexpr auto begin() const { return iterator{DifferenceType{1}}; }
+  constexpr auto end() const { return iterator{DifferenceType{5}}; }
+};
+
+constexpr int f() {
+  int val = 0;
+  template for (auto v : Range()) val += v;
+  template for (constexpr auto v : Range()) val += v;
+  return val;
+}
+
+static_assert(f() == 20);
+}
+
+// Test that 'iter' is an lvalue, because we used to not actually create a
+// variable for it.
+namespace cwg3140 {
+struct IterLValue {
+  struct iterator {
+    int v;
+
+    constexpr iterator& operator++() {
+      v++;
+      return *this;
+    }
+
+    constexpr int operator*() const & { return int(v); }
+    constexpr int operator*() const && = delete("'iter' must be an lvalue");
+    friend constexpr bool operator!=(iterator a, iterator b) { return a.v != b.v; }
+    friend constexpr iterator operator+(iterator a, int b) { return iterator{a.v + b}; }
+    friend constexpr int operator-(iterator a, iterator b) { return a.v - b.v; }
+  };
+
+  constexpr auto begin() const { return iterator{1}; }
+  constexpr auto end() const { return iterator{5}; }
+};
+
+constexpr int f() {
+  int val = 0;
+  template for (auto v : IterLValue()) val += v;
+  template for (constexpr auto v : IterLValue()) val += v;
+  return val;
+}
+
+static_assert(f() == 20);
+}
+#endif // 0
+
+namespace cwg3149 {
+struct NotCopyable {
+  int x;
+  constexpr NotCopyable(int x) : x{x} {}
+  constexpr NotCopyable(NotCopyable&& o) : x{o.x} {}
+  NotCopyable(const NotCopyable&) = delete; // expected-note 2 {{explicitly marked deleted here}}
+};
+
+struct NotMovable {
+  int x;
+  constexpr NotMovable(int x) : x{x} {}
+  constexpr NotMovable(const NotMovable& o) : x{o.x} {}
+  NotMovable(NotMovable&&) = delete; // expected-note 2 {{explicitly marked deleted here}}
+};
+
+template <typename T>
+struct Wrapper {
+  T a;
+  T b;
+};
+
+constexpr int f() {
+  Wrapper<NotMovable> nm{{3},{4}};
+  Wrapper<NotCopyable> nc{{5}, {6}};
+  int sum = 0;
+  template for (auto x : Wrapper<NotCopyable>{{1}, {2}}) sum += x.x;
+  template for (auto& x : nc) sum += x.x;
+  template for (auto x : static_cast<Wrapper<NotCopyable>&&>(nc)) sum += x.x;
+  template for (auto&& x : static_cast<Wrapper<NotMovable>&&>(nm)) sum += x.x;
+  return sum;
+}
+
+static_assert(f() == 32);
+
+int err() {
+  Wrapper<NotCopyable> nc{{3},{4}};
+  int sum = 0;
+
+  // expected-error at +2 2 {{call to deleted constructor of 'cwg3149::NotMovable'}}
+  // expected-note at +1 2 {{in instantiation of expansion statement requested here}}
+  template for (auto x : Wrapper<NotMovable>{{1}, {2}}) sum += x.x;
+
+  // expected-error at +2 2 {{call to deleted constructor of 'cwg3149::NotCopyable'}}
+  // expected-note at +1 2 {{in instantiation of expansion statement requested here}}
+  template for (auto x : nc) sum += x.x;
+  return sum;
+}
+}
+
+namespace cwg3045 {
+void f1() {
+  int x;
+  int y;
+
+  template for (auto x : {1}) { // expected-note {{previous definition is here}}
+    int x{}; // expected-error {{redefinition of 'x'}}
+  }
+
+  { int x; }
+
+  template for (auto x : {1}) {
+    { int x{}; }
+    {
+      int x{};
+      { int x{}; }
+    }
+  }
+
+  template for (auto x : {1}) {
+    template for (auto y : {1}) { // expected-note {{previous definition is here}}
+      int x{};
+      int y{}; // expected-error {{redefinition of 'y'}}
+    }
+  }
+}
+
+void f2(int q) {
+  switch (q) {
+    case 1: template for (auto x : {1}) [[fallthrough]]; // expected-error {{fallthrough annotation does not directly precede switch label}}
+  }
+  switch (q) {
+    case 1: template for (auto x : {1}) [[fallthrough]]; // expected-error {{fallthrough annotation does not directly precede switch label}}
+    case 2:;
+  }
+
+  switch (q) {
+    case 1: template for (auto x : {1}) { [[fallthrough]]; } // expected-error {{fallthrough annotation does not directly precede switch label}}
+  }
+
+  switch (q) {
+    case 1: template for (auto x : {1}) {
+      switch (q) {
+        case 1: [[fallthrough]];
+        case 2:;
+      }
+    }
+  }
+}
+}
+
+#if 0 // Disabled until we support iterating expansion statements.
+// Check that we apply lifetime extension to iterating expansions statements.
+//
+// The new constant interpreter erroring on this is likely https://github.com/llvm/llvm-project/issues/187775.
+namespace cwg3140 {
+constexpr const char* arr = "1";
+struct T {
+  int& x;
+  constexpr T(int& x) noexcept : x(x) {}
+  constexpr ~T() noexcept { x = 42; }
+  constexpr const char* begin() const { return arr; }
+  constexpr const char* end() const { return arr + 1; }
+};
+
+constexpr const T& f(const T& t) noexcept { return t; }
+constexpr T g(int& x) noexcept { return T(x); }
+
+constexpr int lifetime_extension_iterating() {
+  int x = 5;
+  int sum  = 0;
+  // new-interp-error at +3 {{expansion statement size is not a constant expression}}
+  // new-interp-note at +2 {{initializer of '__range1' is not a constant expression}}
+  // new-interp-note at +1 {{declared here}}
+  template for (auto e : f(g(x))) {
+    sum += x;
+  }
+  return sum + x;
+}
+
+template <typename T>
+constexpr int lifetime_extension_iterating_dependent() {
+  int x = 5;
+  int sum  = 0;
+  // new-interp-error at +3 {{expansion statement size is not a constant expression}}
+  // new-interp-note at +2 {{initializer of '__range0' is not a constant expression}}
+  // new-interp-note at +1 {{declared here}}
+  template for (auto e : T(f(g(x)))) {
+    sum += x;
+  }
+  return sum + x;
+}
+
+template <typename T>
+constexpr int lifetime_extension_iterating_instantiation() {
+  int x = 5;
+  int sum  = 0;
+  // new-interp-error at +3 {{expansion statement size is not a constant expression}}
+  // new-interp-note at +2 {{initializer of '__range2' is not a constant expression}}
+  // new-interp-note at +1 {{declared here}}
+  template for (auto e : f(g(x))) {
+    sum += x;
+  }
+  return sum + x;
+}
+
+static_assert(lifetime_extension_iterating() == 47); // new-interp-error {{static assertion failed}} new-interp-note {{expression evaluates to}}
+static_assert(lifetime_extension_iterating_dependent<const T&>() == 47); // new-interp-error {{static assertion expression is not an integral constant expression}} new-interp-note {{in instantiation of}}
+static_assert(lifetime_extension_iterating_instantiation<void>() == 47); // new-interp-error {{static assertion expression is not an integral constant expression}} new-interp-note {{in instantiation of}}
+}
+#endif // 0
+
+// Tests that make sure that certain parts of an expansion statement end up in
+// the right DeclContext.
+namespace decl_context {
+struct S { int x{}, y{}; };
+
+void dependent_context() {
+  // The init-statement should never be in a dependent context.
+  template for (int _ = ({ static_assert(false); 4; }); auto x : {}) {} // expected-error {{static assertion failed}}
+  template for (({ static_assert(false); }); auto x : {}) {} // expected-error {{static assertion failed}}
+
+  // Likewise, the expansion-initializer is not dependent.
+  template for (auto x : { ({ static_assert(false); 4; }) }) {} // expected-error {{static assertion failed}}
+  template for (auto x : ({ static_assert(false); S(); })) {} // expected-error {{static assertion failed}}
+
+  // The for-range-declaration *is* dependent because it only appears within the
+  // expansion(s), which means that it is discarded entirely if the expansion
+  // size is 0.
+  template for (decltype(({ static_assert(false); 42; })) _ : {}) {}
+  template for (decltype(({ static_assert(false); 42; })) _ : {1}) {} // expected-error {{static assertion failed}} expected-note {{in instantiation of expansion statement}}
+}
+
+template <typename>
+void not_instantiated() {
+  template for (int _ = ({ static_assert(false); 4; }); auto x : {}) {}
+  template for (({ static_assert(false); }); auto x : {}) {}
+  template for (auto x : { ({ static_assert(false); 4; }) }) {}
+  template for (auto x : ({ static_assert(false); S(); })) {}
+  template for (decltype(({ static_assert(false); 42; })) _ : {}) {}
+  template for (decltype(({ static_assert(false); 42; })) _ : {1}) {}
+}
+
+template <typename>
+void instantiated() {
+  template for (int _ = ({ static_assert(false); 4; }); auto x : {}) {} // expected-error {{static assertion failed}}
+  template for (({ static_assert(false); }); auto x : {}) {} // expected-error {{static assertion failed}}
+  template for (auto x : { ({ static_assert(false); 4; }) }) {} // expected-error {{static assertion failed}}
+  template for (auto x : ({ static_assert(false); S(); })) {} // expected-error {{static assertion failed}}
+  template for (decltype(({ static_assert(false); 42; })) _ : {}) {}
+  template for (decltype(({ static_assert(false); 42; })) _ : {1}) {} // expected-error {{static assertion failed}}
+}
+
+template <typename>
+struct Template {
+  template <typename>
+  void not_fully_instantiated() {
+    template for (int _ = ({ static_assert(false); 4; }); auto x : {}) {}
+    template for (({ static_assert(false); }); auto x : {}) {}
+    template for (auto x : { ({ static_assert(false); 4; }) }) {}
+    template for (auto x : ({ static_assert(false); S(); })) {}
+    template for (decltype(({ static_assert(false); 42; })) _ : {}) {}
+    template for (decltype(({ static_assert(false); 42; })) _ : {1}) {}
+  }
+
+  template <typename>
+  void instantiated() {
+    template for (int _ = ({ static_assert(false); 4; }); auto x : {}) {} // expected-error {{static assertion failed}}
+    template for (({ static_assert(false); }); auto x : {}) {} // expected-error {{static assertion failed}}
+    template for (auto x : { ({ static_assert(false); 4; }) }) {} // expected-error {{static assertion failed}}
+    template for (auto x : ({ static_assert(false); S(); })) {} // expected-error {{static assertion failed}}
+    template for (decltype(({ static_assert(false); 42; })) _ : {}) {}
+    template for (decltype(({ static_assert(false); 42; })) _ : {1}) {} // expected-error {{static assertion failed}}
+  }
+};
+
+void f() {
+  instantiated<void>(); // expected-note {{in instantiation of function template specialization 'decl_context::instantiated<void>'}}
+
+  // This should *not* produce any diagnostics.
+  Template<int>();
+
+  // Rather, the diagnostics are only emitted if we actually fully instantiate
+  // the function template.
+  Template<void>().instantiated<void>(); // expected-note {{in instantiation of function template specialization 'decl_context::Template<void>::instantiated<void>'}}
+}
+}

>From d0f8ae2153d81be0e0f220c005e4e85974547bd5 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Fri, 10 Jul 2026 22:01:30 +0200
Subject: [PATCH 2/2] [Clang] [C++26] Expansion Statements (Part 8: Codegen)
 (#169687)

This implements codegen for expansion statements and adds some codegen
tests.
---
 clang/docs/ReleaseNotes.rst                   |    2 +
 .../clang/Basic/DiagnosticCommonKinds.td      |    4 -
 .../clang/Basic/DiagnosticSemaKinds.td        |    6 +
 clang/include/clang/Sema/ScopeInfo.h          |    9 +-
 clang/include/clang/Sema/Sema.h               |    6 +-
 clang/lib/CodeGen/CGDecl.cpp                  |    8 +-
 clang/lib/CodeGen/CGStmt.cpp                  |   29 +-
 clang/lib/CodeGen/CodeGenFunction.h           |    3 +
 clang/lib/Parse/ParseStmt.cpp                 |   12 +-
 clang/lib/Sema/SemaLookup.cpp                 |   47 +-
 clang/lib/Sema/SemaStmt.cpp                   |   30 +-
 clang/test/AST/ast-dump-expansion-stmt.cpp    |   54 +
 clang/test/AST/ast-print-expansion-stmts.cpp  |  113 ++
 .../cxx2c-destructuring-expansion-stmt.cpp    |  532 ++++++
 ...cxx2c-enumerating-expansion-statements.cpp | 1518 +++++++++++++++++
 .../cxx2c-expansion-stmts-control-flow.cpp    |  430 +++++
 .../cxx2c-expansion-stmts-mangling.cpp        |  134 ++
 .../cxx2c-expansion-stmts-templates.cpp       |  208 +++
 .../cxx2c-iterating-expansion-stmt.cpp        |  551 ++++++
 .../cxx2c-expansion-stmts-control-flow.cpp    |  135 ++
 clang/www/cxx_status.html                     |    8 +-
 21 files changed, 3814 insertions(+), 25 deletions(-)
 create mode 100644 clang/test/AST/ast-dump-expansion-stmt.cpp
 create mode 100644 clang/test/AST/ast-print-expansion-stmts.cpp
 create mode 100644 clang/test/CodeGenCXX/cxx2c-destructuring-expansion-stmt.cpp
 create mode 100644 clang/test/CodeGenCXX/cxx2c-enumerating-expansion-statements.cpp
 create mode 100644 clang/test/CodeGenCXX/cxx2c-expansion-stmts-control-flow.cpp
 create mode 100644 clang/test/CodeGenCXX/cxx2c-expansion-stmts-mangling.cpp
 create mode 100644 clang/test/CodeGenCXX/cxx2c-expansion-stmts-templates.cpp
 create mode 100644 clang/test/CodeGenCXX/cxx2c-iterating-expansion-stmt.cpp
 create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-control-flow.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fc17eead02589..1fab855bb1fc2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -126,6 +126,8 @@ C++ Language Changes
 
 C++2c Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
+- Clang now has partial support for `P1306R5 <https://wg21.link/P1306R5>`_ Expansion Statements. Iterating expansion
+  statements currently cannot be expanded and will result in a diagnostic, but other types of expansion statements work.
 
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index f1ee130eb1f11..cb267e3ee05c1 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -22,10 +22,6 @@ def select_constexpr_spec_kind : TextSubstitution<
 def fatal_too_many_errors
   : Error<"too many errors emitted, stopping now">, DefaultFatal;
 
-// TODO: Remove this.
-def err_expansion_statements_todo : Error<
-  "TODO (expansion statements)">;
-
 def warn_stack_exhausted : Warning<
   "stack nearly exhausted; compilation time may suffer, and "
   "crashes due to stack overflow are likely">,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5a553f92fb0e8..bfe0fe75389fa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3746,6 +3746,12 @@ def err_expansion_stmt_incomplete : Error<
   "cannot expand expression of incomplete type %0">;
 def err_expansion_stmt_lambda : Error<
   "cannot expand lambda closure type">;
+def err_expansion_stmt_case : Error<
+  "%select{'case'|'default'}0 belongs to 'switch' outside enclosing expansion statement">;
+def note_enclosing_switch_statement_here : Note<
+  "switch statement is here">;
+def err_expansion_stmt_label : Error<
+  "labels are not allowed in expansion statements">;
 
 def err_attribute_patchable_function_entry_invalid_section
     : Error<"section argument to 'patchable_function_entry' attribute is not "
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index f334f58ebd0a7..a0753fa333770 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -201,8 +201,13 @@ class FunctionScopeInfo {
 
 public:
   /// A SwitchStmt, along with a flag indicating if its list of case statements
-  /// is incomplete (because we dropped an invalid one while parsing).
-  using SwitchInfo = llvm::PointerIntPair<SwitchStmt*, 1, bool>;
+  /// is incomplete (because we dropped an invalid one while parsing), as well
+  /// as the DeclContext containing the statement.
+  struct SwitchInfo : llvm::PointerIntPair<SwitchStmt *, 1, bool> {
+    DeclContext *EnclosingDC;
+    SwitchInfo(SwitchStmt *Switch, DeclContext *DC)
+        : PointerIntPair(Switch, false), EnclosingDC(DC) {}
+  };
 
   /// SwitchStack - This is the current set of active switch statements in the
   /// block.
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 050da05a2e82b..d41cf7cdbcc00 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9610,9 +9610,11 @@ class Sema final : public SemaBase {
   /// LookupOrCreateLabel - Do a name lookup of a label with the specified name.
   /// If GnuLabelLoc is a valid source location, then this is a definition
   /// of an __label__ label name, otherwise it is a normal label definition
-  /// or use.
+  /// or use. If IsLabelStmt is true, then this is the label of a
+  /// labeled-statement.
   LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc,
-                                 SourceLocation GnuLabelLoc = SourceLocation());
+                                 SourceLocation GnuLabelLoc = SourceLocation(),
+                                 bool IsLabelStmt = false);
 
   /// Perform a name lookup for a label with the specified name; this does not
   /// create a new label if the lookup fails.
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 047aa55dc4b4a..de6b751c155ff 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -143,8 +143,12 @@ void CodeGenFunction::EmitDecl(const Decl &D, bool EvaluateConditionDecl) {
     // None of these decls require codegen support.
     return;
 
-  case Decl::CXXExpansionStmt:
-    llvm_unreachable("TODO");
+  case Decl::CXXExpansionStmt: {
+    const auto *ESD = cast<CXXExpansionStmtDecl>(&D);
+    assert(ESD->getInstantiations() && "expansion statement not expanded?");
+    EmitStmt(ESD->getInstantiations());
+    return;
+  }
 
   case Decl::NamespaceAlias:
     if (CGDebugInfo *DI = getDebugInfo())
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 8d9eb67cc2cef..9e0ea7d5eb880 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -206,7 +206,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
   case Stmt::CXXExpansionStmtPatternClass:
     llvm_unreachable("unexpanded expansion statements should not be emitted");
   case Stmt::CXXExpansionStmtInstantiationClass:
-    llvm_unreachable("Todo");
+    EmitCXXExpansionStmtInstantiation(cast<CXXExpansionStmtInstantiation>(*S));
+    break;
   case Stmt::SEHTryStmtClass:
     EmitSEHTryStmt(cast<SEHTryStmt>(*S));
     break;
@@ -1511,6 +1512,32 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
   }
 }
 
+void CodeGenFunction::EmitCXXExpansionStmtInstantiation(
+    const CXXExpansionStmtInstantiation &S) {
+  LexicalScope Scope(*this, S.getSourceRange());
+
+  for (const Stmt *DS : S.getPreambleStmts())
+    EmitStmt(DS);
+
+  if (S.getInstantiations().empty())
+    return;
+
+  JumpDest ExpandExit = getJumpDestInCurrentScope("expand.end");
+  JumpDest ContinueDest;
+  for (auto [N, Inst] : enumerate(S.getInstantiations())) {
+    if (N == S.getInstantiations().size() - 1)
+      ContinueDest = ExpandExit;
+    else
+      ContinueDest = getJumpDestInCurrentScope("expand.next");
+
+    LexicalScope ExpansionScope(*this, Inst->getSourceRange());
+    BreakContinueStack.push_back(BreakContinue(S, ExpandExit, ContinueDest));
+    EmitStmt(Inst);
+    BreakContinueStack.pop_back();
+    EmitBlock(ContinueDest.getBlock(), true);
+  }
+}
+
 void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
   if (RV.isScalar()) {
     Builder.CreateStore(RV.getScalarVal(), ReturnValue);
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 0ff93d2ce7363..b045edb83b568 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3734,6 +3734,9 @@ class CodeGenFunction : public CodeGenTypeCache {
   void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
                            ArrayRef<const Attr *> Attrs = {});
 
+  void
+  EmitCXXExpansionStmtInstantiation(const CXXExpansionStmtInstantiation &S);
+
   /// Controls insertion of cancellation exit blocks in worksharing constructs.
   class OMPCancelStackRAII {
     CodeGenFunction &CGF;
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 756d194a767cf..32cab6782f9e5 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -738,8 +738,9 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
   // identifier ':' statement
   SourceLocation ColonLoc = ConsumeToken();
 
-  LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(),
-                                              IdentTok.getLocation());
+  LabelDecl *LD = Actions.LookupOrCreateLabel(
+      IdentTok.getIdentifierInfo(), IdentTok.getLocation(), /*GnuLabelLoc=*/{},
+      /*IsLabelStmt=*/true);
 
   // Read label attributes, if present.
   StmtResult SubStmt;
@@ -783,6 +784,13 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
 
   DiagnoseLabelFollowedByDecl(*this, SubStmt.get());
 
+  // If a label cannot appear here, just return the underlying statement. We
+  // already diagnosed this as invalid in LookupOrCreateLabel() above.
+  if (!LD) {
+    Attrs.clear();
+    return SubStmt.get();
+  }
+
   Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs);
   Attrs.clear();
 
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 9502b440dbe97..ed07395c00e72 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -4468,7 +4468,8 @@ LabelDecl *Sema::LookupExistingLabel(IdentifierInfo *II, SourceLocation Loc) {
 }
 
 LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
-                                     SourceLocation GnuLabelLoc) {
+                                     SourceLocation GnuLabelLoc,
+                                     bool IsLabelStmt) {
   if (GnuLabelLoc.isValid()) {
     // Local label definitions always shadow existing labels.
     auto *Res = LabelDecl::Create(Context, CurContext, Loc, II, GnuLabelLoc);
@@ -4477,15 +4478,43 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
     return cast<LabelDecl>(Res);
   }
 
-  // Not a GNU local label.
-  LabelDecl *Res = LookupExistingLabel(II, Loc);
-  if (!Res) {
-    // If not forward referenced or defined already, create the backing decl.
-    Res = LabelDecl::Create(Context, CurContext, Loc, II);
-    Scope *S = CurScope->getFnParent();
-    assert(S && "Not in a function?");
-    PushOnScopeChains(Res, S, true);
+  LabelDecl *Existing = LookupExistingLabel(II, Loc);
+
+  // C++26 [stmt.label]p4 An identifier label shall not be enclosed by an
+  // expansion-statement.
+  //
+  // As an extension, we allow GNU local labels since they are logically
+  // scoped to the containing block, which prevents us from ending up with
+  // multiple copies of the same label in a function after instantiation.
+  //
+  // While allowing this is slightly more complicated, it also has the nice
+  // side-effect of avoiding otherwise rather horrible diagnostics you'd get
+  // when trying to use '__label__' if we didn't support this.
+  if (IsLabelStmt && CurContext->isExpansionStmt()) {
+    if (Existing && Existing->isGnuLocal())
+      return Existing;
+
+    // Drop the label from the AST as creating it anyway would cause us to
+    // either issue various unhelpful diagnostics (if we were to declare
+    // it in the function decl context) or shadow a valid label with the
+    // same name outside the expansion statement.
+    Diag(Loc, diag::err_expansion_stmt_label);
+    return nullptr;
   }
+
+  if (Existing)
+    return Existing;
+
+  // Declare non-local labels outside any expansion statements; this is required
+  // to support jumping out of an expansion statement.
+  ContextRAII Ctx{*this, CurContext->getEnclosingNonExpansionStatementContext(),
+                  /*NewThisContext=*/false};
+
+  // Not a GNU local label. Create the backing decl.
+  auto *Res = LabelDecl::Create(Context, CurContext, Loc, II);
+  Scope *S = CurScope->getFnParent();
+  assert(S && "Not in a function?");
+  PushOnScopeChains(Res, S, true);
   return Res;
 }
 
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index d53e355fbec70..406a6da0903fb 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -528,6 +528,25 @@ Sema::ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val) {
   return CheckAndFinish(Val.get());
 }
 
+static bool DiagnoseSwitchCaseInExpansionStmt(Sema &S, SourceLocation KwLoc,
+                                              bool IsDefault) {
+  // C++26 [stmt.expand] The compound-statement of an expansion-statement is a
+  // control-flow-limited statement.
+  //
+  // We diagnose this here rather than in JumpDiagnostics because those run
+  // after the expansion statement is instantiated, at which point we will have
+  // have already complained about duplicate case labels, which is not exactly
+  // great QOI.
+  if (S.CurContext->isExpansionStmt() &&
+      S.getCurFunction()->SwitchStack.back().EnclosingDC != S.CurContext) {
+    S.Diag(KwLoc, diag::err_expansion_stmt_case) << IsDefault;
+    S.Diag(S.getCurFunction()->SwitchStack.back().getPointer()->getSwitchLoc(),
+           diag::note_enclosing_switch_statement_here);
+    return true;
+  }
+  return false;
+}
+
 StmtResult
 Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprResult LHSVal,
                     SourceLocation DotDotDotLoc, ExprResult RHSVal,
@@ -547,6 +566,9 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprResult LHSVal,
     return StmtError();
   }
 
+  if (DiagnoseSwitchCaseInExpansionStmt(*this, CaseLoc, false))
+    return StmtError();
+
   if (LangOpts.OpenACC &&
       getCurScope()->isInOpenACCComputeConstructScope(Scope::SwitchScope)) {
     Diag(CaseLoc, diag::err_acc_branch_in_out_compute_construct)
@@ -572,6 +594,9 @@ Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
     return SubStmt;
   }
 
+  if (DiagnoseSwitchCaseInExpansionStmt(*this, DefaultLoc, true))
+    return StmtError();
+
   if (LangOpts.OpenACC &&
       getCurScope()->isInOpenACCComputeConstructScope(Scope::SwitchScope)) {
     Diag(DefaultLoc, diag::err_acc_branch_in_out_compute_construct)
@@ -1196,8 +1221,9 @@ StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
 
   auto *SS = SwitchStmt::Create(Context, InitStmt, Cond.get().first, CondExpr,
                                 LParenLoc, RParenLoc);
+  SS->setSwitchLoc(SwitchLoc);
   getCurFunction()->SwitchStack.push_back(
-      FunctionScopeInfo::SwitchInfo(SS, false));
+      FunctionScopeInfo::SwitchInfo(SS, CurContext));
   return SS;
 }
 
@@ -1313,7 +1339,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
     BodyStmt = new (Context) NullStmt(BodyStmt->getBeginLoc());
   }
 
-  SS->setBody(BodyStmt, SwitchLoc);
+  SS->setBody(BodyStmt);
 
   Expr *CondExpr = SS->getCond();
   if (!CondExpr) return StmtError();
diff --git a/clang/test/AST/ast-dump-expansion-stmt.cpp b/clang/test/AST/ast-dump-expansion-stmt.cpp
new file mode 100644
index 0000000000000..94f0ee1449f17
--- /dev/null
+++ b/clang/test/AST/ast-dump-expansion-stmt.cpp
@@ -0,0 +1,54 @@
+// Test without serialization:
+// RUN: %clang_cc1 -std=c++26 -triple x86_64-unknown-unknown -ast-dump %s
+//
+// Test with serialization:
+// RUN: %clang_cc1 -std=c++26 -triple x86_64-unknown-unknown -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++26 -triple x86_64-unknown-unknown -include-pch %t -ast-dump-all /dev/null \
+// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//"
+
+#if 0 // Disabled until we support iterating expansion statements.
+template <typename T, __SIZE_TYPE__ size>
+struct Array {
+  T data[size]{};
+  constexpr const T* begin() const { return data; }
+  constexpr const T* end() const { return data + size; }
+};
+#endif // 0
+
+void foo(int);
+
+template <typename T>
+void test(T t) {
+  // CHECK:      CXXExpansionStmtDecl
+  // CHECK-NEXT:   CXXExpansionStmtPattern {{.*}} enumerating
+  // CHECK:        CXXExpansionStmtInstantiation
+  template for (auto x : {1, 2, 3}) {
+    foo(x);
+  }
+
+#if 0 // Disabled until we support iterating expansion statements.
+  // NOTE: Remove 'DISABLED-' when the '#if 0' is removed.
+  // DISABLED-CHECK:      CXXExpansionStmtDecl
+  // DISABLED-CHECK-NEXT:   CXXExpansionStmtPattern {{.*}} iterating
+  // DISABLED-CHECK:        CXXExpansionStmtInstantiation
+  static constexpr Array<int, 3> a;
+  template for (auto x : a) {
+    foo(x);
+  }
+#endif
+
+  // CHECK:      CXXExpansionStmtDecl
+  // CHECK-NEXT:   CXXExpansionStmtPattern {{.*}} destructuring
+  // CHECK:        CXXExpansionStmtInstantiation
+  int arr[3]{1, 2, 3};
+  template for (auto x : arr) {
+    foo(x);
+  }
+
+  // CHECK:      CXXExpansionStmtDecl
+  // CHECK-NEXT:   CXXExpansionStmtPattern {{.*}} dependent
+  // CHECK-NOT:    CXXExpansionStmtInstantiation
+  template for (auto x : t) {
+    foo(x);
+  }
+}
diff --git a/clang/test/AST/ast-print-expansion-stmts.cpp b/clang/test/AST/ast-print-expansion-stmts.cpp
new file mode 100644
index 0000000000000..880e17a9d3e2f
--- /dev/null
+++ b/clang/test/AST/ast-print-expansion-stmts.cpp
@@ -0,0 +1,113 @@
+// Without serialization:
+// RUN: %clang_cc1 -std=c++26 -ast-print %s | FileCheck %s
+//
+// With serialization:
+// RUN: %clang_cc1 -std=c++26 -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++26 -include-pch %t -ast-print  /dev/null | FileCheck %s
+
+#if 0 // Disabled until we support iterating expansion statements.
+template <typename T, __SIZE_TYPE__ size>
+struct Array {
+  T data[size]{};
+  constexpr const T* begin() const { return data; }
+  constexpr const T* end() const { return data + size; }
+};
+#endif // 0
+
+// CHECK: void foo(int);
+void foo(int);
+
+// CHECK: template <typename T> void test(T t) {
+template <typename T>
+void test(T t) {
+  // Enumerating expansion statement.
+  //
+  // CHECK:      template for (auto x : {1, 2, 3}) {
+  // CHECK-NEXT:     foo(x);
+  // CHECK-NEXT: }
+  template for (auto x : {1, 2, 3}) {
+    foo(x);
+  }
+
+#if 0 // Disabled until we support iterating expansion statements.
+  // Iterating expansion statement.
+  //
+  // NOTE: Remove 'DISABLED-' when the '#if 0' is removed.
+  // DISABLED-CHECK:      static constexpr Array<int, 3> a;
+  // DISABLED-CHECK-NEXT: template for (auto x : (a)) {
+  // DISABLED-CHECK-NEXT:   foo(x);
+  // DISABLED-CHECK-NEXT: }
+  static constexpr Array<int, 3> a;
+  template for (auto x : a) {
+    foo(x);
+  }
+#endif // 0
+
+  // Destructuring expansion statement.
+  //
+  // CHECK:      int arr[3]{1, 2, 3};
+  // CHECK-NEXT: template for (auto x : arr) {
+  // CHECK-NEXT:   foo(x);
+  // CHECK-NEXT: }
+  int arr[3]{1, 2, 3};
+  template for (auto x : arr) {
+    foo(x);
+  }
+
+  // Dependent expansion statement.
+  //
+  // CHECK:      template for (auto x : t) {
+  // CHECK-NEXT:   foo(x);
+  // CHECK-NEXT: }
+  template for (auto x : t) {
+    foo(x);
+  }
+}
+
+// CHECK: template <typename T> void test2(T t) {
+template <typename T>
+void test2(T t) {
+  // Enumerating expansion statement.
+  //
+  // CHECK:      template for (int x : {1, 2, 3}) {
+  // CHECK-NEXT:     foo(x);
+  // CHECK-NEXT: }
+  template for (int x : {1, 2, 3}) {
+    foo(x);
+  }
+
+#if 0 // Disabled until we support iterating expansion statements.
+  // Iterating expansion statement.
+  //
+  // NOTE: Remove 'DISABLED-' when the '#if 0' is removed.
+  // DISABLED-CHECK:      static constexpr Array<int, 3> a;
+  // DISABLED-CHECK-NEXT: template for (int x : (a)) {
+  // DISABLED-CHECK-NEXT:   foo(x);
+  // DISABLED-CHECK-NEXT: }
+
+  static constexpr Array<int, 3> a;
+  template for (int x : a) {
+    foo(x);
+  }
+#endif // 0
+
+  // Destructuring expansion statement.
+  //
+  // CHECK:      int arr[3]{1, 2, 3};
+  // CHECK-NEXT: template for (int x : arr) {
+  // CHECK-NEXT:   foo(x);
+  // CHECK-NEXT: }
+  int arr[3]{1, 2, 3};
+  template for (int x : arr) {
+    foo(x);
+  }
+
+  // Dependent expansion statement.
+  //
+  // CHECK:      template for (int x : t) {
+  // CHECK-NEXT:   foo(x);
+  // CHECK-NEXT: }
+  template for (int x : t) {
+    foo(x);
+  }
+}
diff --git a/clang/test/CodeGenCXX/cxx2c-destructuring-expansion-stmt.cpp b/clang/test/CodeGenCXX/cxx2c-destructuring-expansion-stmt.cpp
new file mode 100644
index 0000000000000..64a3b20f81c6a
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx2c-destructuring-expansion-stmt.cpp
@@ -0,0 +1,532 @@
+// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+struct A {};
+struct B { int x = 1; };
+struct C { int a = 1, b = 2, c = 3; };
+
+void g(int);
+
+int references_destructuring() {
+  C c;
+  template for (auto& x : c) { ++x; }
+  template for (auto&& x : c) { ++x; }
+  return c.a + c.b + c.c;
+}
+
+template <auto v>
+int destructure() {
+  int sum = 0;
+  template for (auto x : v) sum += x;
+  template for (constexpr auto x : v) sum += x;
+  return sum;
+}
+
+void f() {
+  destructure<B{10}>();
+  destructure<C{}>();
+  destructure<C{3, 4, 5}>();
+}
+
+void empty() {
+  static constexpr A a;
+  template for (auto x : A()) g(x);
+  template for (auto& x : a) g(x);
+  template for (auto&& x : A()) g(x);
+  template for (constexpr auto x : a) g(x);
+}
+
+namespace apply_lifetime_extension {
+struct T {
+  int& x;
+  T(int& x) noexcept : x(x) {}
+  ~T() noexcept { x = 42; }
+};
+
+const T& f(const T& t) noexcept { return t; }
+T g(int& x) noexcept { return T(x); }
+
+// CWG 3043:
+//
+// Lifetime extension only applies to destructuring expansion statements
+// (enumerating statements don't have a range variable, and the range variable
+// of iterating statements is constexpr).
+int lifetime_extension() {
+  int x = 5;
+  int sum  = 0;
+  template for (auto e : f(g(x))) {
+    sum += x;
+  }
+  return sum + x;
+}
+
+template <typename T>
+int lifetime_extension_instantiate_expansions() {
+  int x = 5;
+  int sum  = 0;
+  template for (T e : f(g(x))) {
+    sum += x;
+  }
+  return sum + x;
+}
+
+template <typename T>
+int lifetime_extension_dependent_expansion_stmt() {
+  int x = 5;
+  int sum  = 0;
+  template for (int e : f(g((T&)x))) {
+    sum += x;
+  }
+  return sum + x;
+}
+
+template <typename U>
+struct foo {
+  template <typename T>
+  int lifetime_extension_multiple_instantiations() {
+    int x = 5;
+    int sum  = 0;
+    template for (T e : f(g((U&)x))) {
+      sum += x;
+    }
+    return sum + x;
+  }
+};
+
+void instantiate() {
+  lifetime_extension_instantiate_expansions<int>();
+  lifetime_extension_dependent_expansion_stmt<int>();
+  foo<int>().lifetime_extension_multiple_instantiations<int>();
+}
+}
+
+struct Volatile {
+  volatile int x;
+};
+
+int volatile_member(Volatile* v) {
+  int sum = 0;
+  template for (auto& x : *v) {
+    sum += x;
+    x = 4;
+  }
+  return sum;
+}
+
+// CHECK: $_ZN1CC1Ev = comdat any
+// CHECK: $_Z11destructureITnDaXtl1BLi10EEEEiv = comdat any
+// CHECK: $_Z11destructureITnDaXtl1CLi1ELi2ELi3EEEEiv = comdat any
+// CHECK: $_Z11destructureITnDaXtl1CLi3ELi4ELi5EEEEiv = comdat any
+// CHECK: $_ZN24apply_lifetime_extension1TC1ERi = comdat any
+// CHECK: $_ZN24apply_lifetime_extension1TD1Ev = comdat any
+// CHECK: $_ZN24apply_lifetime_extension41lifetime_extension_instantiate_expansionsIiEEiv = comdat any
+// CHECK: $_ZN24apply_lifetime_extension43lifetime_extension_dependent_expansion_stmtIiEEiv = comdat any
+// CHECK: $_ZN24apply_lifetime_extension3fooIiE42lifetime_extension_multiple_instantiationsIiEEiv = comdat any
+// CHECK: $_ZN1CC2Ev = comdat any
+// CHECK: $_ZN24apply_lifetime_extension1TC2ERi = comdat any
+// CHECK: $_ZN24apply_lifetime_extension1TD2Ev = comdat any
+// CHECK: $_ZTAXtl1BLi10EEE = comdat any
+// CHECK: $_ZTAXtl1CLi1ELi2ELi3EEE = comdat any
+// CHECK: $_ZTAXtl1CLi3ELi4ELi5EEE = comdat any
+// CHECK: @_ZZ5emptyvE1a = internal constant %struct.A zeroinitializer, align 1
+// CHECK: @_ZTAXtl1BLi10EEE = {{.*}} constant %struct.B { i32 10 }, comdat
+// CHECK: @_ZTAXtl1CLi1ELi2ELi3EEE = {{.*}} constant %struct.C { i32 1, i32 2, i32 3 }, comdat
+// CHECK: @_ZTAXtl1CLi3ELi4ELi5EEE = {{.*}} constant %struct.C { i32 3, i32 4, i32 5 }, comdat
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z24references_destructuringv()
+// CHECK: entry:
+// CHECK-NEXT:   %c = alloca %struct.C, align 4
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca ptr, align 8
+// CHECK-NEXT:   %x1 = alloca ptr, align 8
+// CHECK-NEXT:   %x4 = alloca ptr, align 8
+// CHECK-NEXT:   %1 = alloca ptr, align 8
+// CHECK-NEXT:   %x7 = alloca ptr, align 8
+// CHECK-NEXT:   %x11 = alloca ptr, align 8
+// CHECK-NEXT:   %x15 = alloca ptr, align 8
+// CHECK-NEXT:   call void @_ZN1CC1Ev(ptr {{.*}} %c)
+// CHECK-NEXT:   store ptr %c, ptr %0, align 8
+// CHECK-NEXT:   %2 = load ptr, ptr %0, align 8
+// CHECK-NEXT:   %a = getelementptr inbounds nuw %struct.C, ptr %2, i32 0, i32 0
+// CHECK-NEXT:   store ptr %a, ptr %x, align 8
+// CHECK-NEXT:   %3 = load ptr, ptr %x, align 8
+// CHECK-NEXT:   %4 = load i32, ptr %3, align 4
+// CHECK-NEXT:   %inc = add nsw i32 %4, 1
+// CHECK-NEXT:   store i32 %inc, ptr %3, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   %5 = load ptr, ptr %0, align 8
+// CHECK-NEXT:   %b = getelementptr inbounds nuw %struct.C, ptr %5, i32 0, i32 1
+// CHECK-NEXT:   store ptr %b, ptr %x1, align 8
+// CHECK-NEXT:   %6 = load ptr, ptr %x1, align 8
+// CHECK-NEXT:   %7 = load i32, ptr %6, align 4
+// CHECK-NEXT:   %inc2 = add nsw i32 %7, 1
+// CHECK-NEXT:   store i32 %inc2, ptr %6, align 4
+// CHECK-NEXT:   br label %expand.next3
+// CHECK: expand.next3:
+// CHECK-NEXT:   %8 = load ptr, ptr %0, align 8
+// CHECK-NEXT:   %c5 = getelementptr inbounds nuw %struct.C, ptr %8, i32 0, i32 2
+// CHECK-NEXT:   store ptr %c5, ptr %x4, align 8
+// CHECK-NEXT:   %9 = load ptr, ptr %x4, align 8
+// CHECK-NEXT:   %10 = load i32, ptr %9, align 4
+// CHECK-NEXT:   %inc6 = add nsw i32 %10, 1
+// CHECK-NEXT:   store i32 %inc6, ptr %9, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store ptr %c, ptr %1, align 8
+// CHECK-NEXT:   %11 = load ptr, ptr %1, align 8
+// CHECK-NEXT:   %a8 = getelementptr inbounds nuw %struct.C, ptr %11, i32 0, i32 0
+// CHECK-NEXT:   store ptr %a8, ptr %x7, align 8
+// CHECK-NEXT:   %12 = load ptr, ptr %x7, align 8
+// CHECK-NEXT:   %13 = load i32, ptr %12, align 4
+// CHECK-NEXT:   %inc9 = add nsw i32 %13, 1
+// CHECK-NEXT:   store i32 %inc9, ptr %12, align 4
+// CHECK-NEXT:   br label %expand.next10
+// CHECK: expand.next10:
+// CHECK-NEXT:   %14 = load ptr, ptr %1, align 8
+// CHECK-NEXT:   %b12 = getelementptr inbounds nuw %struct.C, ptr %14, i32 0, i32 1
+// CHECK-NEXT:   store ptr %b12, ptr %x11, align 8
+// CHECK-NEXT:   %15 = load ptr, ptr %x11, align 8
+// CHECK-NEXT:   %16 = load i32, ptr %15, align 4
+// CHECK-NEXT:   %inc13 = add nsw i32 %16, 1
+// CHECK-NEXT:   store i32 %inc13, ptr %15, align 4
+// CHECK-NEXT:   br label %expand.next14
+// CHECK: expand.next14:
+// CHECK-NEXT:   %17 = load ptr, ptr %1, align 8
+// CHECK-NEXT:   %c16 = getelementptr inbounds nuw %struct.C, ptr %17, i32 0, i32 2
+// CHECK-NEXT:   store ptr %c16, ptr %x15, align 8
+// CHECK-NEXT:   %18 = load ptr, ptr %x15, align 8
+// CHECK-NEXT:   %19 = load i32, ptr %18, align 4
+// CHECK-NEXT:   %inc17 = add nsw i32 %19, 1
+// CHECK-NEXT:   store i32 %inc17, ptr %18, align 4
+// CHECK-NEXT:   br label %expand.end18
+// CHECK: expand.end18:
+// CHECK-NEXT:   %a19 = getelementptr inbounds nuw %struct.C, ptr %c, i32 0, i32 0
+// CHECK-NEXT:   %20 = load i32, ptr %a19, align 4
+// CHECK-NEXT:   %b20 = getelementptr inbounds nuw %struct.C, ptr %c, i32 0, i32 1
+// CHECK-NEXT:   %21 = load i32, ptr %b20, align 4
+// CHECK-NEXT:   %add = add nsw i32 %20, %21
+// CHECK-NEXT:   %c21 = getelementptr inbounds nuw %struct.C, ptr %c, i32 0, i32 2
+// CHECK-NEXT:   %22 = load i32, ptr %c21, align 4
+// CHECK-NEXT:   %add22 = add nsw i32 %add, %22
+// CHECK-NEXT:   ret i32 %add22
+
+
+// CHECK-LABEL: define {{.*}} void @_Z1fv()
+// CHECK: entry:
+// CHECK-NEXT:   %call = call {{.*}} i32 @_Z11destructureITnDaXtl1BLi10EEEEiv()
+// CHECK-NEXT:   %call1 = call {{.*}} i32 @_Z11destructureITnDaXtl1CLi1ELi2ELi3EEEEiv()
+// CHECK-NEXT:   %call2 = call {{.*}} i32 @_Z11destructureITnDaXtl1CLi3ELi4ELi5EEEEiv()
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z11destructureITnDaXtl1BLi10EEEEiv()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %1 = alloca ptr, align 8
+// CHECK-NEXT:   %x1 = alloca i32, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store ptr @_ZTAXtl1BLi10EEE, ptr %0, align 8
+// CHECK-NEXT:   %2 = load i32, ptr @_ZTAXtl1BLi10EEE, align 4
+// CHECK-NEXT:   store i32 %2, ptr %x, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %4, %3
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store ptr @_ZTAXtl1BLi10EEE, ptr %1, align 8
+// CHECK-NEXT:   store i32 10, ptr %x1, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add2 = add nsw i32 %5, 10
+// CHECK-NEXT:   store i32 %add2, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end3
+// CHECK: expand.end3:
+// CHECK-NEXT:   %6 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %6
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z11destructureITnDaXtl1CLi1ELi2ELi3EEEEiv()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x1 = alloca i32, align 4
+// CHECK-NEXT:   %x4 = alloca i32, align 4
+// CHECK-NEXT:   %1 = alloca ptr, align 8
+// CHECK-NEXT:   %x6 = alloca i32, align 4
+// CHECK-NEXT:   %x9 = alloca i32, align 4
+// CHECK-NEXT:   %x12 = alloca i32, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store ptr @_ZTAXtl1CLi1ELi2ELi3EEE, ptr %0, align 8
+// CHECK-NEXT:   %2 = load i32, ptr @_ZTAXtl1CLi1ELi2ELi3EEE, align 4
+// CHECK-NEXT:   store i32 %2, ptr %x, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %4, %3
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   %5 = load i32, ptr getelementptr inbounds nuw (i8, ptr @_ZTAXtl1CLi1ELi2ELi3EEE, i64 4), align 4
+// CHECK-NEXT:   store i32 %5, ptr %x1, align 4
+// CHECK-NEXT:   %6 = load i32, ptr %x1, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add2 = add nsw i32 %7, %6
+// CHECK-NEXT:   store i32 %add2, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next3
+// CHECK: expand.next3:
+// CHECK-NEXT:   %8 = load i32, ptr getelementptr inbounds nuw (i8, ptr @_ZTAXtl1CLi1ELi2ELi3EEE, i64 8), align 4
+// CHECK-NEXT:   store i32 %8, ptr %x4, align 4
+// CHECK-NEXT:   %9 = load i32, ptr %x4, align 4
+// CHECK-NEXT:   %10 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add5 = add nsw i32 %10, %9
+// CHECK-NEXT:   store i32 %add5, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store ptr @_ZTAXtl1CLi1ELi2ELi3EEE, ptr %1, align 8
+// CHECK-NEXT:   store i32 1, ptr %x6, align 4
+// CHECK-NEXT:   %11 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add7 = add nsw i32 %11, 1
+// CHECK-NEXT:   store i32 %add7, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next8
+// CHECK: expand.next8:
+// CHECK-NEXT:   store i32 2, ptr %x9, align 4
+// CHECK-NEXT:   %12 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add10 = add nsw i32 %12, 2
+// CHECK-NEXT:   store i32 %add10, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next11
+// CHECK: expand.next11:
+// CHECK-NEXT:   store i32 3, ptr %x12, align 4
+// CHECK-NEXT:   %13 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add13 = add nsw i32 %13, 3
+// CHECK-NEXT:   store i32 %add13, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end14
+// CHECK: expand.end14:
+// CHECK-NEXT:   %14 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %14
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z11destructureITnDaXtl1CLi3ELi4ELi5EEEEiv()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x1 = alloca i32, align 4
+// CHECK-NEXT:   %x4 = alloca i32, align 4
+// CHECK-NEXT:   %1 = alloca ptr, align 8
+// CHECK-NEXT:   %x6 = alloca i32, align 4
+// CHECK-NEXT:   %x9 = alloca i32, align 4
+// CHECK-NEXT:   %x12 = alloca i32, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store ptr @_ZTAXtl1CLi3ELi4ELi5EEE, ptr %0, align 8
+// CHECK-NEXT:   %2 = load i32, ptr @_ZTAXtl1CLi3ELi4ELi5EEE, align 4
+// CHECK-NEXT:   store i32 %2, ptr %x, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %4, %3
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   %5 = load i32, ptr getelementptr inbounds nuw (i8, ptr @_ZTAXtl1CLi3ELi4ELi5EEE, i64 4), align 4
+// CHECK-NEXT:   store i32 %5, ptr %x1, align 4
+// CHECK-NEXT:   %6 = load i32, ptr %x1, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add2 = add nsw i32 %7, %6
+// CHECK-NEXT:   store i32 %add2, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next3
+// CHECK: expand.next3:
+// CHECK-NEXT:   %8 = load i32, ptr getelementptr inbounds nuw (i8, ptr @_ZTAXtl1CLi3ELi4ELi5EEE, i64 8), align 4
+// CHECK-NEXT:   store i32 %8, ptr %x4, align 4
+// CHECK-NEXT:   %9 = load i32, ptr %x4, align 4
+// CHECK-NEXT:   %10 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add5 = add nsw i32 %10, %9
+// CHECK-NEXT:   store i32 %add5, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store ptr @_ZTAXtl1CLi3ELi4ELi5EEE, ptr %1, align 8
+// CHECK-NEXT:   store i32 3, ptr %x6, align 4
+// CHECK-NEXT:   %11 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add7 = add nsw i32 %11, 3
+// CHECK-NEXT:   store i32 %add7, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next8
+// CHECK: expand.next8:
+// CHECK-NEXT:   store i32 4, ptr %x9, align 4
+// CHECK-NEXT:   %12 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add10 = add nsw i32 %12, 4
+// CHECK-NEXT:   store i32 %add10, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next11
+// CHECK: expand.next11:
+// CHECK-NEXT:   store i32 5, ptr %x12, align 4
+// CHECK-NEXT:   %13 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add13 = add nsw i32 %13, 5
+// CHECK-NEXT:   store i32 %add13, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end14
+// CHECK: expand.end14:
+// CHECK-NEXT:   %14 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %14
+
+
+// CHECK-LABEL: define {{.*}} void @_Z5emptyv()
+// CHECK: entry:
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK-NEXT:   %ref.tmp = alloca %struct.A, align 1
+// CHECK-NEXT:   %1 = alloca ptr, align 8
+// CHECK-NEXT:   %2 = alloca ptr, align 8
+// CHECK-NEXT:   %ref.tmp1 = alloca %struct.A, align 1
+// CHECK-NEXT:   %3 = alloca ptr, align 8
+// CHECK-NEXT:   store ptr %ref.tmp, ptr %0, align 8
+// CHECK-NEXT:   store ptr @_ZZ5emptyvE1a, ptr %1, align 8
+// CHECK-NEXT:   store ptr %ref.tmp1, ptr %2, align 8
+// CHECK-NEXT:   store ptr @_ZZ5emptyvE1a, ptr %3, align 8
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} i32 @_ZN24apply_lifetime_extension18lifetime_extensionEv()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK: %ref.tmp = alloca %"struct.apply_lifetime_extension::T", align 8
+// CHECK-NEXT:   %e = alloca i32, align 4
+// CHECK-NEXT:   store i32 5, ptr %x, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK: call void @_ZN24apply_lifetime_extension1gERi(ptr dead_on_unwind writable sret(%"struct.apply_lifetime_extension::T") align 8 %ref.tmp, ptr {{.*}} %x)
+// CHECK-NEXT:   %call = call {{.*}} ptr @_ZN24apply_lifetime_extension1fERKNS_1TE(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   store ptr %call, ptr %0, align 8
+// CHECK-NEXT:   %1 = load ptr, ptr %0, align 8
+// CHECK: %x1 = getelementptr inbounds nuw %"struct.apply_lifetime_extension::T", ptr %1, i32 0, i32 0
+// CHECK-NEXT:   %2 = load ptr, ptr %x1, align 8
+// CHECK-NEXT:   %3 = load i32, ptr %2, align 4
+// CHECK-NEXT:   store i32 %3, ptr %e, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %5, %4
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   call void @_ZN24apply_lifetime_extension1TD1Ev(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   %6 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %add2 = add nsw i32 %6, %7
+// CHECK-NEXT:   ret i32 %add2
+
+
+// CHECK-LABEL: define {{.*}} i32 @_ZN24apply_lifetime_extension41lifetime_extension_instantiate_expansionsIiEEiv()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK: %ref.tmp = alloca %"struct.apply_lifetime_extension::T", align 8
+// CHECK-NEXT:   %e = alloca i32, align 4
+// CHECK-NEXT:   store i32 5, ptr %x, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK: call void @_ZN24apply_lifetime_extension1gERi(ptr dead_on_unwind writable sret(%"struct.apply_lifetime_extension::T") align 8 %ref.tmp, ptr {{.*}} %x)
+// CHECK-NEXT:   %call = call {{.*}} ptr @_ZN24apply_lifetime_extension1fERKNS_1TE(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   store ptr %call, ptr %0, align 8
+// CHECK-NEXT:   %1 = load ptr, ptr %0, align 8
+// CHECK: %x1 = getelementptr inbounds nuw %"struct.apply_lifetime_extension::T", ptr %1, i32 0, i32 0
+// CHECK-NEXT:   %2 = load ptr, ptr %x1, align 8
+// CHECK-NEXT:   %3 = load i32, ptr %2, align 4
+// CHECK-NEXT:   store i32 %3, ptr %e, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %5, %4
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   call void @_ZN24apply_lifetime_extension1TD1Ev(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   %6 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %add2 = add nsw i32 %6, %7
+// CHECK-NEXT:   ret i32 %add2
+
+
+// CHECK-LABEL: define {{.*}} i32 @_ZN24apply_lifetime_extension43lifetime_extension_dependent_expansion_stmtIiEEiv()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK: %ref.tmp = alloca %"struct.apply_lifetime_extension::T", align 8
+// CHECK-NEXT:   %e = alloca i32, align 4
+// CHECK-NEXT:   store i32 5, ptr %x, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK: call void @_ZN24apply_lifetime_extension1gERi(ptr dead_on_unwind writable sret(%"struct.apply_lifetime_extension::T") align 8 %ref.tmp, ptr {{.*}} %x)
+// CHECK-NEXT:   %call = call {{.*}} ptr @_ZN24apply_lifetime_extension1fERKNS_1TE(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   store ptr %call, ptr %0, align 8
+// CHECK-NEXT:   %1 = load ptr, ptr %0, align 8
+// CHECK: %x1 = getelementptr inbounds nuw %"struct.apply_lifetime_extension::T", ptr %1, i32 0, i32 0
+// CHECK-NEXT:   %2 = load ptr, ptr %x1, align 8
+// CHECK-NEXT:   %3 = load i32, ptr %2, align 4
+// CHECK-NEXT:   store i32 %3, ptr %e, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %5, %4
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   call void @_ZN24apply_lifetime_extension1TD1Ev(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   %6 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %add2 = add nsw i32 %6, %7
+// CHECK-NEXT:   ret i32 %add2
+
+
+// CHECK-LABEL: define {{.*}} i32 @_ZN24apply_lifetime_extension3fooIiE42lifetime_extension_multiple_instantiationsIiEEiv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK: %ref.tmp = alloca %"struct.apply_lifetime_extension::T", align 8
+// CHECK-NEXT:   %e = alloca i32, align 4
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   store i32 5, ptr %x, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK: call void @_ZN24apply_lifetime_extension1gERi(ptr {{.*}} %ref.tmp, ptr {{.*}} %x)
+// CHECK-NEXT:   %call = call {{.*}} ptr @_ZN24apply_lifetime_extension1fERKNS_1TE(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   store ptr %call, ptr %0, align 8
+// CHECK-NEXT:   %1 = load ptr, ptr %0, align 8
+// CHECK: %x2 = getelementptr inbounds nuw %"struct.apply_lifetime_extension::T", ptr %1, i32 0, i32 0
+// CHECK-NEXT:   %2 = load ptr, ptr %x2, align 8
+// CHECK-NEXT:   %3 = load i32, ptr %2, align 4
+// CHECK-NEXT:   store i32 %3, ptr %e, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %5, %4
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   call void @_ZN24apply_lifetime_extension1TD1Ev(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   %6 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %add3 = add nsw i32 %6, %7
+// CHECK-NEXT:   ret i32 %add3
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z15volatile_memberP8Volatile(ptr {{.*}} %v)
+// CHECK: entry:
+// CHECK-NEXT:   %v.addr = alloca ptr, align 8
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca ptr, align 8
+// CHECK-NEXT:   store ptr %v, ptr %v.addr, align 8
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   %1 = load ptr, ptr %v.addr, align 8
+// CHECK-NEXT:   store ptr %1, ptr %0, align 8
+// CHECK-NEXT:   %2 = load ptr, ptr %0, align 8
+// CHECK-NEXT:   %x1 = getelementptr inbounds nuw %struct.Volatile, ptr %2, i32 0, i32 0
+// CHECK-NEXT:   store ptr %x1, ptr %x, align 8
+// CHECK-NEXT:   %3 = load ptr, ptr %x, align 8
+// CHECK-NEXT:   %4 = load volatile i32, ptr %3, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %5, %4
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   %6 = load ptr, ptr %x, align 8
+// CHECK-NEXT:   store volatile i32 4, ptr %6, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   %7 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %7
diff --git a/clang/test/CodeGenCXX/cxx2c-enumerating-expansion-statements.cpp b/clang/test/CodeGenCXX/cxx2c-enumerating-expansion-statements.cpp
new file mode 100644
index 0000000000000..c82b345de206b
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx2c-enumerating-expansion-statements.cpp
@@ -0,0 +1,1518 @@
+// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+struct S {
+  int x;
+  constexpr S(int x) : x{x} {}
+};
+
+void g(int);
+void g(long);
+void g(const char*);
+void g(S);
+
+template <int n> constexpr int tg() { return n; }
+
+void h(int, int);
+
+void f1() {
+  template for (auto x : {1, 2, 3}) g(x);
+}
+
+void f2() {
+  template for (auto x : {1, "123", S(45)}) g(x);
+}
+
+void f3() {
+  template for (auto x : {}) g(x);
+}
+
+void f4() {
+  template for (auto x : {1, 2})
+    template for (auto y : {3, 4})
+      h(x, y);
+}
+
+void f5() {
+  template for (auto x : {}) static_assert(false, "discarded");
+  template for (constexpr auto x : {}) static_assert(false, "discarded");
+  template for (auto x : {1}) g(x);
+  template for (auto x : {2, 3, 4}) g(x);
+  template for (constexpr auto x : {5}) g(x);
+  template for (constexpr auto x : {6, 7, 8}) g(x);
+  template for (constexpr auto x : {9}) tg<x>();
+  template for (constexpr auto x : {10, 11, 12})
+    static_assert(tg<x>());
+
+  template for (int x : {13, 14, 15}) g(x);
+  template for (S x : {16, 17, 18}) g(x.x);
+  template for (constexpr S x : {19, 20, 21}) tg<x.x>();
+}
+
+template <typename T>
+void t1() {
+  template for (T x : {}) g(x);
+  template for (constexpr T x : {}) g(x);
+  template for (auto x : {}) g(x);
+  template for (constexpr auto x : {}) g(x);
+  template for (T x : {1, 2}) g(x);
+  template for (T x : {T(3), T(4)}) g(x);
+  template for (auto x : {T(5), T(6)}) g(x);
+  template for (constexpr T x : {T(7), T(8)}) static_assert(tg<x>());
+  template for (constexpr auto x : {T(9), T(10)}) static_assert(tg<x>());
+}
+
+template <typename U>
+struct s1 {
+  template <typename T>
+  void tf() {
+    template for (T x : {}) g(x);
+    template for (constexpr T x : {}) g(x);
+    template for (U x : {}) g(x);
+    template for (constexpr U x : {}) g(x);
+    template for (auto x : {}) g(x);
+    template for (constexpr auto x : {}) g(x);
+    template for (T x : {1, 2}) g(x);
+    template for (U x : {3, 4}) g(x);
+    template for (U x : {T(5), T(6)}) g(x);
+    template for (T x : {U(7), U(8)}) g(x);
+    template for (auto x : {T(9), T(10)}) g(x);
+    template for (auto x : {U(11), T(12)}) g(x);
+    template for (constexpr U x : {T(13), T(14)}) static_assert(tg<x>());
+    template for (constexpr T x : {U(15), U(16)}) static_assert(tg<x>());
+    template for (constexpr auto x : {T(17), U(18)}) static_assert(tg<x>());
+  }
+};
+
+template <typename T>
+void t2() {
+  template for (T x : {}) g(x);
+}
+
+void f6() {
+  t1<int>();
+  t1<long>();
+  s1<long>().tf<long>();
+  s1<int>().tf<int>();
+  s1<int>().tf<long>();
+  s1<long>().tf<int>();
+  t2<S>();
+  t2<S[1231]>();
+  t2<S***>();
+}
+
+struct X {
+  int a, b, c;
+};
+
+template <typename ...Ts>
+void t3(Ts... ts) {
+  template for (auto x : {ts...}) g(x);
+  template for (auto x : {1, ts..., 2, ts..., 3}) g(x);
+  template for (auto x : {4, ts..., ts..., 5}) g(x);
+  template for (X x : {{ts...}, {ts...}, {6, 7, 8}}) g(x.a);
+  template for (X x : {X{ts...}}) g(x.a);
+}
+
+template <int ...is>
+void t4() {
+  template for (constexpr auto x : {is...}) {
+    g(x);
+    tg<x>();
+  }
+
+  template for (constexpr auto x : {1, is..., 2, is..., 3}) {
+    g(x);
+    tg<x>();
+  }
+
+  template for (constexpr auto x : {4, is..., is..., 5}) {
+    g(x);
+    tg<x>();
+  }
+
+  template for (constexpr X x : {{is...}, {is...}, {6, 7, 8}}) {
+    g(x.a);
+    tg<x.a>();
+  }
+
+  template for (constexpr X x : {X{is...}}) {
+    g(x.a);
+    tg<x.a>();
+  }
+}
+
+template <int ...is>
+struct s2 {
+  template <int ...js>
+  void tf() {
+    template for (auto x : {is..., js...}) g(x);
+    template for (X x : {{is...}, {js...}}) g(x.a);
+    template for (constexpr auto x : {is..., js...}) tg<x>();
+    template for (constexpr X x : {{is...}, {js...}}) tg<x.a>();
+  }
+};
+
+void f7() {
+  t3(42, 43, 44);
+  t4<42, 43, 44>();
+  s2<1, 2, 3>().tf<4, 5, 6>();
+}
+
+template <int ...is>
+void t5() {
+  ([] {
+    template for (constexpr auto x : {is}) {
+      g(x);
+      tg<x>();
+    }
+  }(), ...);
+}
+
+void f8() {
+  t5<1, 2, 3>();
+}
+
+int references_enumerating() {
+  int x = 1, y = 2, z = 3;
+  template for (auto& v : {x, y, z}) { ++v; }
+  template for (auto&& v : {x, y, z}) { ++v; }
+  return x + y + z;
+}
+
+// CHECK-LABEL: define {{.*}} void @_Z2f1v()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x1 = alloca i32, align 4
+// CHECK-NEXT:   %x3 = alloca i32, align 4
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %0)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 2, ptr %x1, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %x1, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.next2
+// CHECK: expand.next2:
+// CHECK-NEXT:   store i32 3, ptr %x3, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x3, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %2)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z2f2v()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x1 = alloca ptr, align 8
+// CHECK-NEXT:   %x3 = alloca %struct.S, align 4
+// CHECK-NEXT:   %agg.tmp = alloca %struct.S, align 4
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %0)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store ptr @.str, ptr %x1, align 8
+// CHECK-NEXT:   %1 = load ptr, ptr %x1, align 8
+// CHECK-NEXT:   call void @_Z1gPKc(ptr {{.*}} %1)
+// CHECK-NEXT:   br label %expand.next2
+// CHECK: expand.next2:
+// CHECK-NEXT:   call void @_ZN1SC1Ei(ptr {{.*}} %x3, i32 {{.*}} 45)
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %agg.tmp, ptr align 4 %x3, i64 4, i1 false)
+// CHECK-NEXT:   %coerce.dive = getelementptr inbounds nuw %struct.S, ptr %agg.tmp, i32 0, i32 0
+// CHECK-NEXT:   %2 = load i32, ptr %coerce.dive, align 4
+// CHECK-NEXT:   call void @_Z1g1S(i32 %2)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z2f3v()
+// CHECK: entry:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z2f4v()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %y = alloca i32, align 4
+// CHECK-NEXT:   %y1 = alloca i32, align 4
+// CHECK-NEXT:   %x3 = alloca i32, align 4
+// CHECK-NEXT:   %y4 = alloca i32, align 4
+// CHECK-NEXT:   %y6 = alloca i32, align 4
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   store i32 3, ptr %y, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %y, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} %0, i32 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 4, ptr %y1, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %y1, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} %2, i32 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   br label %expand.next2
+// CHECK: expand.next2:
+// CHECK-NEXT:   store i32 2, ptr %x3, align 4
+// CHECK-NEXT:   store i32 3, ptr %y4, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x3, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %y4, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} %4, i32 {{.*}} %5)
+// CHECK-NEXT:   br label %expand.next5
+// CHECK: expand.next5:
+// CHECK-NEXT:   store i32 4, ptr %y6, align 4
+// CHECK-NEXT:   %6 = load i32, ptr %x3, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %y6, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} %6, i32 {{.*}} %7)
+// CHECK-NEXT:   br label %expand.end7
+// CHECK: expand.end7:
+// CHECK-NEXT:   br label %expand.end8
+// CHECK: expand.end8:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z2f5v()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x1 = alloca i32, align 4
+// CHECK-NEXT:   %x2 = alloca i32, align 4
+// CHECK-NEXT:   %x4 = alloca i32, align 4
+// CHECK-NEXT:   %x6 = alloca i32, align 4
+// CHECK-NEXT:   %x8 = alloca i32, align 4
+// CHECK-NEXT:   %x10 = alloca i32, align 4
+// CHECK-NEXT:   %x12 = alloca i32, align 4
+// CHECK-NEXT:   %x14 = alloca i32, align 4
+// CHECK-NEXT:   %x16 = alloca i32, align 4
+// CHECK-NEXT:   %x18 = alloca i32, align 4
+// CHECK-NEXT:   %x20 = alloca i32, align 4
+// CHECK-NEXT:   %x22 = alloca i32, align 4
+// CHECK-NEXT:   %x24 = alloca i32, align 4
+// CHECK-NEXT:   %x26 = alloca i32, align 4
+// CHECK-NEXT:   %x28 = alloca %struct.S, align 4
+// CHECK-NEXT:   %x31 = alloca %struct.S, align 4
+// CHECK-NEXT:   %x34 = alloca %struct.S, align 4
+// CHECK-NEXT:   %x37 = alloca %struct.S, align 4
+// CHECK-NEXT:   %x40 = alloca %struct.S, align 4
+// CHECK-NEXT:   %x43 = alloca %struct.S, align 4
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %0)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store i32 2, ptr %x1, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %x1, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 3, ptr %x2, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x2, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %2)
+// CHECK-NEXT:   br label %expand.next3
+// CHECK: expand.next3:
+// CHECK-NEXT:   store i32 4, ptr %x4, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x4, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.end5
+// CHECK: expand.end5:
+// CHECK-NEXT:   store i32 5, ptr %x6, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 5)
+// CHECK-NEXT:   br label %expand.end7
+// CHECK: expand.end7:
+// CHECK-NEXT:   store i32 6, ptr %x8, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 6)
+// CHECK-NEXT:   br label %expand.next9
+// CHECK: expand.next9:
+// CHECK-NEXT:   store i32 7, ptr %x10, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 7)
+// CHECK-NEXT:   br label %expand.next11
+// CHECK: expand.next11:
+// CHECK-NEXT:   store i32 8, ptr %x12, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 8)
+// CHECK-NEXT:   br label %expand.end13
+// CHECK: expand.end13:
+// CHECK-NEXT:   store i32 9, ptr %x14, align 4
+// CHECK-NEXT:   %call = call {{.*}} i32 @_Z2tgILi9EEiv()
+// CHECK-NEXT:   br label %expand.end15
+// CHECK: expand.end15:
+// CHECK-NEXT:   store i32 10, ptr %x16, align 4
+// CHECK-NEXT:   br label %expand.next17
+// CHECK: expand.next17:
+// CHECK-NEXT:   store i32 11, ptr %x18, align 4
+// CHECK-NEXT:   br label %expand.next19
+// CHECK: expand.next19:
+// CHECK-NEXT:   store i32 12, ptr %x20, align 4
+// CHECK-NEXT:   br label %expand.end21
+// CHECK: expand.end21:
+// CHECK-NEXT:   store i32 13, ptr %x22, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x22, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %4)
+// CHECK-NEXT:   br label %expand.next23
+// CHECK: expand.next23:
+// CHECK-NEXT:   store i32 14, ptr %x24, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %x24, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %5)
+// CHECK-NEXT:   br label %expand.next25
+// CHECK: expand.next25:
+// CHECK-NEXT:   store i32 15, ptr %x26, align 4
+// CHECK-NEXT:   %6 = load i32, ptr %x26, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %6)
+// CHECK-NEXT:   br label %expand.end27
+// CHECK: expand.end27:
+// CHECK-NEXT:   call void @_ZN1SC1Ei(ptr {{.*}} %x28, i32 {{.*}} 16)
+// CHECK-NEXT:   %x29 = getelementptr inbounds nuw %struct.S, ptr %x28, i32 0, i32 0
+// CHECK-NEXT:   %7 = load i32, ptr %x29, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %7)
+// CHECK-NEXT:   br label %expand.next30
+// CHECK: expand.next30:
+// CHECK-NEXT:   call void @_ZN1SC1Ei(ptr {{.*}} %x31, i32 {{.*}} 17)
+// CHECK-NEXT:   %x32 = getelementptr inbounds nuw %struct.S, ptr %x31, i32 0, i32 0
+// CHECK-NEXT:   %8 = load i32, ptr %x32, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %8)
+// CHECK-NEXT:   br label %expand.next33
+// CHECK: expand.next33:
+// CHECK-NEXT:   call void @_ZN1SC1Ei(ptr {{.*}} %x34, i32 {{.*}} 18)
+// CHECK-NEXT:   %x35 = getelementptr inbounds nuw %struct.S, ptr %x34, i32 0, i32 0
+// CHECK-NEXT:   %9 = load i32, ptr %x35, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %9)
+// CHECK-NEXT:   br label %expand.end36
+// CHECK: expand.end36:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x37, ptr align 4 @__const._Z2f5v.x, i64 4, i1 false)
+// CHECK-NEXT:   %call38 = call {{.*}} i32 @_Z2tgILi19EEiv()
+// CHECK-NEXT:   br label %expand.next39
+// CHECK: expand.next39:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x40, ptr align 4 @__const._Z2f5v.x.1, i64 4, i1 false)
+// CHECK-NEXT:   %call41 = call {{.*}} i32 @_Z2tgILi20EEiv()
+// CHECK-NEXT:   br label %expand.next42
+// CHECK: expand.next42:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x43, ptr align 4 @__const._Z2f5v.x.2, i64 4, i1 false)
+// CHECK-NEXT:   %call44 = call {{.*}} i32 @_Z2tgILi21EEiv()
+// CHECK-NEXT:   br label %expand.end45
+// CHECK: expand.end45:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z2f6v()
+// CHECK: entry:
+// CHECK-NEXT:   %ref.tmp = alloca %struct.s1, align 1
+// CHECK-NEXT:   %ref.tmp1 = alloca %struct.s1.0, align 1
+// CHECK-NEXT:   %ref.tmp2 = alloca %struct.s1.0, align 1
+// CHECK-NEXT:   %ref.tmp3 = alloca %struct.s1, align 1
+// CHECK-NEXT:   call void @_Z2t1IiEvv()
+// CHECK-NEXT:   call void @_Z2t1IlEvv()
+// CHECK-NEXT:   call void @_ZN2s1IlE2tfIlEEvv(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   call void @_ZN2s1IiE2tfIiEEvv(ptr {{.*}} %ref.tmp1)
+// CHECK-NEXT:   call void @_ZN2s1IiE2tfIlEEvv(ptr {{.*}} %ref.tmp2)
+// CHECK-NEXT:   call void @_ZN2s1IlE2tfIiEEvv(ptr {{.*}} %ref.tmp3)
+// CHECK-NEXT:   call void @_Z2t2I1SEvv()
+// CHECK-NEXT:   call void @_Z2t2IA1231_1SEvv()
+// CHECK-NEXT:   call void @_Z2t2IPPP1SEvv()
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z2t1IiEvv()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x1 = alloca i32, align 4
+// CHECK-NEXT:   %x2 = alloca i32, align 4
+// CHECK-NEXT:   %x4 = alloca i32, align 4
+// CHECK-NEXT:   %x6 = alloca i32, align 4
+// CHECK-NEXT:   %x8 = alloca i32, align 4
+// CHECK-NEXT:   %x10 = alloca i32, align 4
+// CHECK-NEXT:   %x12 = alloca i32, align 4
+// CHECK-NEXT:   %x14 = alloca i32, align 4
+// CHECK-NEXT:   %x16 = alloca i32, align 4
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %0)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 2, ptr %x1, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %x1, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store i32 3, ptr %x2, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x2, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %2)
+// CHECK-NEXT:   br label %expand.next3
+// CHECK: expand.next3:
+// CHECK-NEXT:   store i32 4, ptr %x4, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x4, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.end5
+// CHECK: expand.end5:
+// CHECK-NEXT:   store i32 5, ptr %x6, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x6, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %4)
+// CHECK-NEXT:   br label %expand.next7
+// CHECK: expand.next7:
+// CHECK-NEXT:   store i32 6, ptr %x8, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %x8, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %5)
+// CHECK-NEXT:   br label %expand.end9
+// CHECK: expand.end9:
+// CHECK-NEXT:   store i32 7, ptr %x10, align 4
+// CHECK-NEXT:   br label %expand.next11
+// CHECK: expand.next11:
+// CHECK-NEXT:   store i32 8, ptr %x12, align 4
+// CHECK-NEXT:   br label %expand.end13
+// CHECK: expand.end13:
+// CHECK-NEXT:   store i32 9, ptr %x14, align 4
+// CHECK-NEXT:   br label %expand.next15
+// CHECK: expand.next15:
+// CHECK-NEXT:   store i32 10, ptr %x16, align 4
+// CHECK-NEXT:   br label %expand.end17
+// CHECK: expand.end17:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z2t1IlEvv()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i64, align 8
+// CHECK-NEXT:   %x1 = alloca i64, align 8
+// CHECK-NEXT:   %x2 = alloca i64, align 8
+// CHECK-NEXT:   %x4 = alloca i64, align 8
+// CHECK-NEXT:   %x6 = alloca i64, align 8
+// CHECK-NEXT:   %x8 = alloca i64, align 8
+// CHECK-NEXT:   %x10 = alloca i64, align 8
+// CHECK-NEXT:   %x12 = alloca i64, align 8
+// CHECK-NEXT:   %x14 = alloca i64, align 8
+// CHECK-NEXT:   %x16 = alloca i64, align 8
+// CHECK-NEXT:   store i64 1, ptr %x, align 8
+// CHECK-NEXT:   %0 = load i64, ptr %x, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %0)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i64 2, ptr %x1, align 8
+// CHECK-NEXT:   %1 = load i64, ptr %x1, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store i64 3, ptr %x2, align 8
+// CHECK-NEXT:   %2 = load i64, ptr %x2, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %2)
+// CHECK-NEXT:   br label %expand.next3
+// CHECK: expand.next3:
+// CHECK-NEXT:   store i64 4, ptr %x4, align 8
+// CHECK-NEXT:   %3 = load i64, ptr %x4, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.end5
+// CHECK: expand.end5:
+// CHECK-NEXT:   store i64 5, ptr %x6, align 8
+// CHECK-NEXT:   %4 = load i64, ptr %x6, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %4)
+// CHECK-NEXT:   br label %expand.next7
+// CHECK: expand.next7:
+// CHECK-NEXT:   store i64 6, ptr %x8, align 8
+// CHECK-NEXT:   %5 = load i64, ptr %x8, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %5)
+// CHECK-NEXT:   br label %expand.end9
+// CHECK: expand.end9:
+// CHECK-NEXT:   store i64 7, ptr %x10, align 8
+// CHECK-NEXT:   br label %expand.next11
+// CHECK: expand.next11:
+// CHECK-NEXT:   store i64 8, ptr %x12, align 8
+// CHECK-NEXT:   br label %expand.end13
+// CHECK: expand.end13:
+// CHECK-NEXT:   store i64 9, ptr %x14, align 8
+// CHECK-NEXT:   br label %expand.next15
+// CHECK: expand.next15:
+// CHECK-NEXT:   store i64 10, ptr %x16, align 8
+// CHECK-NEXT:   br label %expand.end17
+// CHECK: expand.end17:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_ZN2s1IlE2tfIlEEvv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i64, align 8
+// CHECK-NEXT:   %x2 = alloca i64, align 8
+// CHECK-NEXT:   %x3 = alloca i64, align 8
+// CHECK-NEXT:   %x5 = alloca i64, align 8
+// CHECK-NEXT:   %x7 = alloca i64, align 8
+// CHECK-NEXT:   %x9 = alloca i64, align 8
+// CHECK-NEXT:   %x11 = alloca i64, align 8
+// CHECK-NEXT:   %x13 = alloca i64, align 8
+// CHECK-NEXT:   %x15 = alloca i64, align 8
+// CHECK-NEXT:   %x17 = alloca i64, align 8
+// CHECK-NEXT:   %x19 = alloca i64, align 8
+// CHECK-NEXT:   %x21 = alloca i64, align 8
+// CHECK-NEXT:   %x23 = alloca i64, align 8
+// CHECK-NEXT:   %x25 = alloca i64, align 8
+// CHECK-NEXT:   %x27 = alloca i64, align 8
+// CHECK-NEXT:   %x29 = alloca i64, align 8
+// CHECK-NEXT:   %x31 = alloca i64, align 8
+// CHECK-NEXT:   %x33 = alloca i64, align 8
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   store i64 1, ptr %x, align 8
+// CHECK-NEXT:   %0 = load i64, ptr %x, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %0)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i64 2, ptr %x2, align 8
+// CHECK-NEXT:   %1 = load i64, ptr %x2, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store i64 3, ptr %x3, align 8
+// CHECK-NEXT:   %2 = load i64, ptr %x3, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %2)
+// CHECK-NEXT:   br label %expand.next4
+// CHECK: expand.next4:
+// CHECK-NEXT:   store i64 4, ptr %x5, align 8
+// CHECK-NEXT:   %3 = load i64, ptr %x5, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.end6
+// CHECK: expand.end6:
+// CHECK-NEXT:   store i64 5, ptr %x7, align 8
+// CHECK-NEXT:   %4 = load i64, ptr %x7, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %4)
+// CHECK-NEXT:   br label %expand.next8
+// CHECK: expand.next8:
+// CHECK-NEXT:   store i64 6, ptr %x9, align 8
+// CHECK-NEXT:   %5 = load i64, ptr %x9, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %5)
+// CHECK-NEXT:   br label %expand.end10
+// CHECK: expand.end10:
+// CHECK-NEXT:   store i64 7, ptr %x11, align 8
+// CHECK-NEXT:   %6 = load i64, ptr %x11, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %6)
+// CHECK-NEXT:   br label %expand.next12
+// CHECK: expand.next12:
+// CHECK-NEXT:   store i64 8, ptr %x13, align 8
+// CHECK-NEXT:   %7 = load i64, ptr %x13, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %7)
+// CHECK-NEXT:   br label %expand.end14
+// CHECK: expand.end14:
+// CHECK-NEXT:   store i64 9, ptr %x15, align 8
+// CHECK-NEXT:   %8 = load i64, ptr %x15, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %8)
+// CHECK-NEXT:   br label %expand.next16
+// CHECK: expand.next16:
+// CHECK-NEXT:   store i64 10, ptr %x17, align 8
+// CHECK-NEXT:   %9 = load i64, ptr %x17, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %9)
+// CHECK-NEXT:   br label %expand.end18
+// CHECK: expand.end18:
+// CHECK-NEXT:   store i64 11, ptr %x19, align 8
+// CHECK-NEXT:   %10 = load i64, ptr %x19, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %10)
+// CHECK-NEXT:   br label %expand.next20
+// CHECK: expand.next20:
+// CHECK-NEXT:   store i64 12, ptr %x21, align 8
+// CHECK-NEXT:   %11 = load i64, ptr %x21, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %11)
+// CHECK-NEXT:   br label %expand.end22
+// CHECK: expand.end22:
+// CHECK-NEXT:   store i64 13, ptr %x23, align 8
+// CHECK-NEXT:   br label %expand.next24
+// CHECK: expand.next24:
+// CHECK-NEXT:   store i64 14, ptr %x25, align 8
+// CHECK-NEXT:   br label %expand.end26
+// CHECK: expand.end26:
+// CHECK-NEXT:   store i64 15, ptr %x27, align 8
+// CHECK-NEXT:   br label %expand.next28
+// CHECK: expand.next28:
+// CHECK-NEXT:   store i64 16, ptr %x29, align 8
+// CHECK-NEXT:   br label %expand.end30
+// CHECK: expand.end30:
+// CHECK-NEXT:   store i64 17, ptr %x31, align 8
+// CHECK-NEXT:   br label %expand.next32
+// CHECK: expand.next32:
+// CHECK-NEXT:   store i64 18, ptr %x33, align 8
+// CHECK-NEXT:   br label %expand.end34
+// CHECK: expand.end34:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_ZN2s1IiE2tfIiEEvv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x2 = alloca i32, align 4
+// CHECK-NEXT:   %x3 = alloca i32, align 4
+// CHECK-NEXT:   %x5 = alloca i32, align 4
+// CHECK-NEXT:   %x7 = alloca i32, align 4
+// CHECK-NEXT:   %x9 = alloca i32, align 4
+// CHECK-NEXT:   %x11 = alloca i32, align 4
+// CHECK-NEXT:   %x13 = alloca i32, align 4
+// CHECK-NEXT:   %x15 = alloca i32, align 4
+// CHECK-NEXT:   %x17 = alloca i32, align 4
+// CHECK-NEXT:   %x19 = alloca i32, align 4
+// CHECK-NEXT:   %x21 = alloca i32, align 4
+// CHECK-NEXT:   %x23 = alloca i32, align 4
+// CHECK-NEXT:   %x25 = alloca i32, align 4
+// CHECK-NEXT:   %x27 = alloca i32, align 4
+// CHECK-NEXT:   %x29 = alloca i32, align 4
+// CHECK-NEXT:   %x31 = alloca i32, align 4
+// CHECK-NEXT:   %x33 = alloca i32, align 4
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %0)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 2, ptr %x2, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %x2, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store i32 3, ptr %x3, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x3, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %2)
+// CHECK-NEXT:   br label %expand.next4
+// CHECK: expand.next4:
+// CHECK-NEXT:   store i32 4, ptr %x5, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x5, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.end6
+// CHECK: expand.end6:
+// CHECK-NEXT:   store i32 5, ptr %x7, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x7, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %4)
+// CHECK-NEXT:   br label %expand.next8
+// CHECK: expand.next8:
+// CHECK-NEXT:   store i32 6, ptr %x9, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %x9, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %5)
+// CHECK-NEXT:   br label %expand.end10
+// CHECK: expand.end10:
+// CHECK-NEXT:   store i32 7, ptr %x11, align 4
+// CHECK-NEXT:   %6 = load i32, ptr %x11, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %6)
+// CHECK-NEXT:   br label %expand.next12
+// CHECK: expand.next12:
+// CHECK-NEXT:   store i32 8, ptr %x13, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %x13, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %7)
+// CHECK-NEXT:   br label %expand.end14
+// CHECK: expand.end14:
+// CHECK-NEXT:   store i32 9, ptr %x15, align 4
+// CHECK-NEXT:   %8 = load i32, ptr %x15, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %8)
+// CHECK-NEXT:   br label %expand.next16
+// CHECK: expand.next16:
+// CHECK-NEXT:   store i32 10, ptr %x17, align 4
+// CHECK-NEXT:   %9 = load i32, ptr %x17, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %9)
+// CHECK-NEXT:   br label %expand.end18
+// CHECK: expand.end18:
+// CHECK-NEXT:   store i32 11, ptr %x19, align 4
+// CHECK-NEXT:   %10 = load i32, ptr %x19, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %10)
+// CHECK-NEXT:   br label %expand.next20
+// CHECK: expand.next20:
+// CHECK-NEXT:   store i32 12, ptr %x21, align 4
+// CHECK-NEXT:   %11 = load i32, ptr %x21, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %11)
+// CHECK-NEXT:   br label %expand.end22
+// CHECK: expand.end22:
+// CHECK-NEXT:   store i32 13, ptr %x23, align 4
+// CHECK-NEXT:   br label %expand.next24
+// CHECK: expand.next24:
+// CHECK-NEXT:   store i32 14, ptr %x25, align 4
+// CHECK-NEXT:   br label %expand.end26
+// CHECK: expand.end26:
+// CHECK-NEXT:   store i32 15, ptr %x27, align 4
+// CHECK-NEXT:   br label %expand.next28
+// CHECK: expand.next28:
+// CHECK-NEXT:   store i32 16, ptr %x29, align 4
+// CHECK-NEXT:   br label %expand.end30
+// CHECK: expand.end30:
+// CHECK-NEXT:   store i32 17, ptr %x31, align 4
+// CHECK-NEXT:   br label %expand.next32
+// CHECK: expand.next32:
+// CHECK-NEXT:   store i32 18, ptr %x33, align 4
+// CHECK-NEXT:   br label %expand.end34
+// CHECK: expand.end34:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_ZN2s1IiE2tfIlEEvv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i64, align 8
+// CHECK-NEXT:   %x2 = alloca i64, align 8
+// CHECK-NEXT:   %x3 = alloca i32, align 4
+// CHECK-NEXT:   %x5 = alloca i32, align 4
+// CHECK-NEXT:   %x7 = alloca i32, align 4
+// CHECK-NEXT:   %x9 = alloca i32, align 4
+// CHECK-NEXT:   %x11 = alloca i64, align 8
+// CHECK-NEXT:   %x13 = alloca i64, align 8
+// CHECK-NEXT:   %x15 = alloca i64, align 8
+// CHECK-NEXT:   %x17 = alloca i64, align 8
+// CHECK-NEXT:   %x19 = alloca i32, align 4
+// CHECK-NEXT:   %x21 = alloca i64, align 8
+// CHECK-NEXT:   %x23 = alloca i32, align 4
+// CHECK-NEXT:   %x25 = alloca i32, align 4
+// CHECK-NEXT:   %x27 = alloca i64, align 8
+// CHECK-NEXT:   %x29 = alloca i64, align 8
+// CHECK-NEXT:   %x31 = alloca i64, align 8
+// CHECK-NEXT:   %x33 = alloca i32, align 4
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   store i64 1, ptr %x, align 8
+// CHECK-NEXT:   %0 = load i64, ptr %x, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %0)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i64 2, ptr %x2, align 8
+// CHECK-NEXT:   %1 = load i64, ptr %x2, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store i32 3, ptr %x3, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x3, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %2)
+// CHECK-NEXT:   br label %expand.next4
+// CHECK: expand.next4:
+// CHECK-NEXT:   store i32 4, ptr %x5, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x5, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.end6
+// CHECK: expand.end6:
+// CHECK-NEXT:   store i32 5, ptr %x7, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x7, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %4)
+// CHECK-NEXT:   br label %expand.next8
+// CHECK: expand.next8:
+// CHECK-NEXT:   store i32 6, ptr %x9, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %x9, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %5)
+// CHECK-NEXT:   br label %expand.end10
+// CHECK: expand.end10:
+// CHECK-NEXT:   store i64 7, ptr %x11, align 8
+// CHECK-NEXT:   %6 = load i64, ptr %x11, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %6)
+// CHECK-NEXT:   br label %expand.next12
+// CHECK: expand.next12:
+// CHECK-NEXT:   store i64 8, ptr %x13, align 8
+// CHECK-NEXT:   %7 = load i64, ptr %x13, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %7)
+// CHECK-NEXT:   br label %expand.end14
+// CHECK: expand.end14:
+// CHECK-NEXT:   store i64 9, ptr %x15, align 8
+// CHECK-NEXT:   %8 = load i64, ptr %x15, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %8)
+// CHECK-NEXT:   br label %expand.next16
+// CHECK: expand.next16:
+// CHECK-NEXT:   store i64 10, ptr %x17, align 8
+// CHECK-NEXT:   %9 = load i64, ptr %x17, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %9)
+// CHECK-NEXT:   br label %expand.end18
+// CHECK: expand.end18:
+// CHECK-NEXT:   store i32 11, ptr %x19, align 4
+// CHECK-NEXT:   %10 = load i32, ptr %x19, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %10)
+// CHECK-NEXT:   br label %expand.next20
+// CHECK: expand.next20:
+// CHECK-NEXT:   store i64 12, ptr %x21, align 8
+// CHECK-NEXT:   %11 = load i64, ptr %x21, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %11)
+// CHECK-NEXT:   br label %expand.end22
+// CHECK: expand.end22:
+// CHECK-NEXT:   store i32 13, ptr %x23, align 4
+// CHECK-NEXT:   br label %expand.next24
+// CHECK: expand.next24:
+// CHECK-NEXT:   store i32 14, ptr %x25, align 4
+// CHECK-NEXT:   br label %expand.end26
+// CHECK: expand.end26:
+// CHECK-NEXT:   store i64 15, ptr %x27, align 8
+// CHECK-NEXT:   br label %expand.next28
+// CHECK: expand.next28:
+// CHECK-NEXT:   store i64 16, ptr %x29, align 8
+// CHECK-NEXT:   br label %expand.end30
+// CHECK: expand.end30:
+// CHECK-NEXT:   store i64 17, ptr %x31, align 8
+// CHECK-NEXT:   br label %expand.next32
+// CHECK: expand.next32:
+// CHECK-NEXT:   store i32 18, ptr %x33, align 4
+// CHECK-NEXT:   br label %expand.end34
+// CHECK: expand.end34:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_ZN2s1IlE2tfIiEEvv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x2 = alloca i32, align 4
+// CHECK-NEXT:   %x3 = alloca i64, align 8
+// CHECK-NEXT:   %x5 = alloca i64, align 8
+// CHECK-NEXT:   %x7 = alloca i64, align 8
+// CHECK-NEXT:   %x9 = alloca i64, align 8
+// CHECK-NEXT:   %x11 = alloca i32, align 4
+// CHECK-NEXT:   %x13 = alloca i32, align 4
+// CHECK-NEXT:   %x15 = alloca i32, align 4
+// CHECK-NEXT:   %x17 = alloca i32, align 4
+// CHECK-NEXT:   %x19 = alloca i64, align 8
+// CHECK-NEXT:   %x21 = alloca i32, align 4
+// CHECK-NEXT:   %x23 = alloca i64, align 8
+// CHECK-NEXT:   %x25 = alloca i64, align 8
+// CHECK-NEXT:   %x27 = alloca i32, align 4
+// CHECK-NEXT:   %x29 = alloca i32, align 4
+// CHECK-NEXT:   %x31 = alloca i32, align 4
+// CHECK-NEXT:   %x33 = alloca i64, align 8
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %0)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 2, ptr %x2, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %x2, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store i64 3, ptr %x3, align 8
+// CHECK-NEXT:   %2 = load i64, ptr %x3, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %2)
+// CHECK-NEXT:   br label %expand.next4
+// CHECK: expand.next4:
+// CHECK-NEXT:   store i64 4, ptr %x5, align 8
+// CHECK-NEXT:   %3 = load i64, ptr %x5, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.end6
+// CHECK: expand.end6:
+// CHECK-NEXT:   store i64 5, ptr %x7, align 8
+// CHECK-NEXT:   %4 = load i64, ptr %x7, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %4)
+// CHECK-NEXT:   br label %expand.next8
+// CHECK: expand.next8:
+// CHECK-NEXT:   store i64 6, ptr %x9, align 8
+// CHECK-NEXT:   %5 = load i64, ptr %x9, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %5)
+// CHECK-NEXT:   br label %expand.end10
+// CHECK: expand.end10:
+// CHECK-NEXT:   store i32 7, ptr %x11, align 4
+// CHECK-NEXT:   %6 = load i32, ptr %x11, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %6)
+// CHECK-NEXT:   br label %expand.next12
+// CHECK: expand.next12:
+// CHECK-NEXT:   store i32 8, ptr %x13, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %x13, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %7)
+// CHECK-NEXT:   br label %expand.end14
+// CHECK: expand.end14:
+// CHECK-NEXT:   store i32 9, ptr %x15, align 4
+// CHECK-NEXT:   %8 = load i32, ptr %x15, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %8)
+// CHECK-NEXT:   br label %expand.next16
+// CHECK: expand.next16:
+// CHECK-NEXT:   store i32 10, ptr %x17, align 4
+// CHECK-NEXT:   %9 = load i32, ptr %x17, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %9)
+// CHECK-NEXT:   br label %expand.end18
+// CHECK: expand.end18:
+// CHECK-NEXT:   store i64 11, ptr %x19, align 8
+// CHECK-NEXT:   %10 = load i64, ptr %x19, align 8
+// CHECK-NEXT:   call void @_Z1gl(i64 {{.*}} %10)
+// CHECK-NEXT:   br label %expand.next20
+// CHECK: expand.next20:
+// CHECK-NEXT:   store i32 12, ptr %x21, align 4
+// CHECK-NEXT:   %11 = load i32, ptr %x21, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %11)
+// CHECK-NEXT:   br label %expand.end22
+// CHECK: expand.end22:
+// CHECK-NEXT:   store i64 13, ptr %x23, align 8
+// CHECK-NEXT:   br label %expand.next24
+// CHECK: expand.next24:
+// CHECK-NEXT:   store i64 14, ptr %x25, align 8
+// CHECK-NEXT:   br label %expand.end26
+// CHECK: expand.end26:
+// CHECK-NEXT:   store i32 15, ptr %x27, align 4
+// CHECK-NEXT:   br label %expand.next28
+// CHECK: expand.next28:
+// CHECK-NEXT:   store i32 16, ptr %x29, align 4
+// CHECK-NEXT:   br label %expand.end30
+// CHECK: expand.end30:
+// CHECK-NEXT:   store i32 17, ptr %x31, align 4
+// CHECK-NEXT:   br label %expand.next32
+// CHECK: expand.next32:
+// CHECK-NEXT:   store i64 18, ptr %x33, align 8
+// CHECK-NEXT:   br label %expand.end34
+// CHECK: expand.end34:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z2f7v()
+// CHECK: entry:
+// CHECK-NEXT:   %ref.tmp = alloca %struct.s2, align 1
+// CHECK-NEXT:   call void @_Z2t3IJiiiEEvDpT_(i32 {{.*}} 42, i32 {{.*}} 43, i32 {{.*}} 44)
+// CHECK-NEXT:   call void @_Z2t4IJLi42ELi43ELi44EEEvv()
+// CHECK-NEXT:   call void @_ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   ret void
+
+// CHECK-LABEL: define {{.*}} void @_Z2t3IJiiiEEvDpT_(i32 {{.*}} %ts, i32 {{.*}} %ts1, i32 {{.*}} %ts3)
+// CHECK: entry:
+// CHECK-NEXT:   %ts.addr = alloca i32, align 4
+// CHECK-NEXT:   %ts.addr2 = alloca i32, align 4
+// CHECK-NEXT:   %ts.addr4 = alloca i32, align 4
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x5 = alloca i32, align 4
+// CHECK-NEXT:   %x7 = alloca i32, align 4
+// CHECK-NEXT:   %x8 = alloca i32, align 4
+// CHECK-NEXT:   %x10 = alloca i32, align 4
+// CHECK-NEXT:   %x12 = alloca i32, align 4
+// CHECK-NEXT:   %x14 = alloca i32, align 4
+// CHECK-NEXT:   %x16 = alloca i32, align 4
+// CHECK-NEXT:   %x18 = alloca i32, align 4
+// CHECK-NEXT:   %x20 = alloca i32, align 4
+// CHECK-NEXT:   %x22 = alloca i32, align 4
+// CHECK-NEXT:   %x24 = alloca i32, align 4
+// CHECK-NEXT:   %x26 = alloca i32, align 4
+// CHECK-NEXT:   %x28 = alloca i32, align 4
+// CHECK-NEXT:   %x30 = alloca i32, align 4
+// CHECK-NEXT:   %x32 = alloca i32, align 4
+// CHECK-NEXT:   %x34 = alloca i32, align 4
+// CHECK-NEXT:   %x36 = alloca i32, align 4
+// CHECK-NEXT:   %x38 = alloca i32, align 4
+// CHECK-NEXT:   %x40 = alloca i32, align 4
+// CHECK-NEXT:   %x42 = alloca %struct.X, align 4
+// CHECK-NEXT:   %x45 = alloca %struct.X, align 4
+// CHECK-NEXT:   %x51 = alloca %struct.X, align 4
+// CHECK-NEXT:   %x54 = alloca %struct.X, align 4
+// CHECK-NEXT:   store i32 %ts, ptr %ts.addr, align 4
+// CHECK-NEXT:   store i32 %ts1, ptr %ts.addr2, align 4
+// CHECK-NEXT:   store i32 %ts3, ptr %ts.addr4, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %ts.addr, align 4
+// CHECK-NEXT:   store i32 %0, ptr %x, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   %2 = load i32, ptr %ts.addr2, align 4
+// CHECK-NEXT:   store i32 %2, ptr %x5, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x5, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.next6
+// CHECK: expand.next6:
+// CHECK-NEXT:   %4 = load i32, ptr %ts.addr4, align 4
+// CHECK-NEXT:   store i32 %4, ptr %x7, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %x7, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %5)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store i32 1, ptr %x8, align 4
+// CHECK-NEXT:   %6 = load i32, ptr %x8, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %6)
+// CHECK-NEXT:   br label %expand.next9
+// CHECK: expand.next9:
+// CHECK-NEXT:   %7 = load i32, ptr %ts.addr, align 4
+// CHECK-NEXT:   store i32 %7, ptr %x10, align 4
+// CHECK-NEXT:   %8 = load i32, ptr %x10, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %8)
+// CHECK-NEXT:   br label %expand.next11
+// CHECK: expand.next11:
+// CHECK-NEXT:   %9 = load i32, ptr %ts.addr2, align 4
+// CHECK-NEXT:   store i32 %9, ptr %x12, align 4
+// CHECK-NEXT:   %10 = load i32, ptr %x12, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %10)
+// CHECK-NEXT:   br label %expand.next13
+// CHECK: expand.next13:
+// CHECK-NEXT:   %11 = load i32, ptr %ts.addr4, align 4
+// CHECK-NEXT:   store i32 %11, ptr %x14, align 4
+// CHECK-NEXT:   %12 = load i32, ptr %x14, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %12)
+// CHECK-NEXT:   br label %expand.next15
+// CHECK: expand.next15:
+// CHECK-NEXT:   store i32 2, ptr %x16, align 4
+// CHECK-NEXT:   %13 = load i32, ptr %x16, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %13)
+// CHECK-NEXT:   br label %expand.next17
+// CHECK: expand.next17:
+// CHECK-NEXT:   %14 = load i32, ptr %ts.addr, align 4
+// CHECK-NEXT:   store i32 %14, ptr %x18, align 4
+// CHECK-NEXT:   %15 = load i32, ptr %x18, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %15)
+// CHECK-NEXT:   br label %expand.next19
+// CHECK: expand.next19:
+// CHECK-NEXT:   %16 = load i32, ptr %ts.addr2, align 4
+// CHECK-NEXT:   store i32 %16, ptr %x20, align 4
+// CHECK-NEXT:   %17 = load i32, ptr %x20, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %17)
+// CHECK-NEXT:   br label %expand.next21
+// CHECK: expand.next21:
+// CHECK-NEXT:   %18 = load i32, ptr %ts.addr4, align 4
+// CHECK-NEXT:   store i32 %18, ptr %x22, align 4
+// CHECK-NEXT:   %19 = load i32, ptr %x22, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %19)
+// CHECK-NEXT:   br label %expand.next23
+// CHECK: expand.next23:
+// CHECK-NEXT:   store i32 3, ptr %x24, align 4
+// CHECK-NEXT:   %20 = load i32, ptr %x24, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %20)
+// CHECK-NEXT:   br label %expand.end25
+// CHECK: expand.end25:
+// CHECK-NEXT:   store i32 4, ptr %x26, align 4
+// CHECK-NEXT:   %21 = load i32, ptr %x26, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %21)
+// CHECK-NEXT:   br label %expand.next27
+// CHECK: expand.next27:
+// CHECK-NEXT:   %22 = load i32, ptr %ts.addr, align 4
+// CHECK-NEXT:   store i32 %22, ptr %x28, align 4
+// CHECK-NEXT:   %23 = load i32, ptr %x28, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %23)
+// CHECK-NEXT:   br label %expand.next29
+// CHECK: expand.next29:
+// CHECK-NEXT:   %24 = load i32, ptr %ts.addr2, align 4
+// CHECK-NEXT:   store i32 %24, ptr %x30, align 4
+// CHECK-NEXT:   %25 = load i32, ptr %x30, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %25)
+// CHECK-NEXT:   br label %expand.next31
+// CHECK: expand.next31:
+// CHECK-NEXT:   %26 = load i32, ptr %ts.addr4, align 4
+// CHECK-NEXT:   store i32 %26, ptr %x32, align 4
+// CHECK-NEXT:   %27 = load i32, ptr %x32, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %27)
+// CHECK-NEXT:   br label %expand.next33
+// CHECK: expand.next33:
+// CHECK-NEXT:   %28 = load i32, ptr %ts.addr, align 4
+// CHECK-NEXT:   store i32 %28, ptr %x34, align 4
+// CHECK-NEXT:   %29 = load i32, ptr %x34, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %29)
+// CHECK-NEXT:   br label %expand.next35
+// CHECK: expand.next35:
+// CHECK-NEXT:   %30 = load i32, ptr %ts.addr2, align 4
+// CHECK-NEXT:   store i32 %30, ptr %x36, align 4
+// CHECK-NEXT:   %31 = load i32, ptr %x36, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %31)
+// CHECK-NEXT:   br label %expand.next37
+// CHECK: expand.next37:
+// CHECK-NEXT:   %32 = load i32, ptr %ts.addr4, align 4
+// CHECK-NEXT:   store i32 %32, ptr %x38, align 4
+// CHECK-NEXT:   %33 = load i32, ptr %x38, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %33)
+// CHECK-NEXT:   br label %expand.next39
+// CHECK: expand.next39:
+// CHECK-NEXT:   store i32 5, ptr %x40, align 4
+// CHECK-NEXT:   %34 = load i32, ptr %x40, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %34)
+// CHECK-NEXT:   br label %expand.end41
+// CHECK: expand.end41:
+// CHECK-NEXT:   %a = getelementptr inbounds nuw %struct.X, ptr %x42, i32 0, i32 0
+// CHECK-NEXT:   %35 = load i32, ptr %ts.addr, align 4
+// CHECK-NEXT:   store i32 %35, ptr %a, align 4
+// CHECK-NEXT:   %b = getelementptr inbounds nuw %struct.X, ptr %x42, i32 0, i32 1
+// CHECK-NEXT:   %36 = load i32, ptr %ts.addr2, align 4
+// CHECK-NEXT:   store i32 %36, ptr %b, align 4
+// CHECK-NEXT:   %c = getelementptr inbounds nuw %struct.X, ptr %x42, i32 0, i32 2
+// CHECK-NEXT:   %37 = load i32, ptr %ts.addr4, align 4
+// CHECK-NEXT:   store i32 %37, ptr %c, align 4
+// CHECK-NEXT:   %a43 = getelementptr inbounds nuw %struct.X, ptr %x42, i32 0, i32 0
+// CHECK-NEXT:   %38 = load i32, ptr %a43, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %38)
+// CHECK-NEXT:   br label %expand.next44
+// CHECK: expand.next44:
+// CHECK-NEXT:   %a46 = getelementptr inbounds nuw %struct.X, ptr %x45, i32 0, i32 0
+// CHECK-NEXT:   %39 = load i32, ptr %ts.addr, align 4
+// CHECK-NEXT:   store i32 %39, ptr %a46, align 4
+// CHECK-NEXT:   %b47 = getelementptr inbounds nuw %struct.X, ptr %x45, i32 0, i32 1
+// CHECK-NEXT:   %40 = load i32, ptr %ts.addr2, align 4
+// CHECK-NEXT:   store i32 %40, ptr %b47, align 4
+// CHECK-NEXT:   %c48 = getelementptr inbounds nuw %struct.X, ptr %x45, i32 0, i32 2
+// CHECK-NEXT:   %41 = load i32, ptr %ts.addr4, align 4
+// CHECK-NEXT:   store i32 %41, ptr %c48, align 4
+// CHECK-NEXT:   %a49 = getelementptr inbounds nuw %struct.X, ptr %x45, i32 0, i32 0
+// CHECK-NEXT:   %42 = load i32, ptr %a49, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %42)
+// CHECK-NEXT:   br label %expand.next50
+// CHECK: expand.next50:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x51, ptr align 4 @__const._Z2t3IJiiiEEvDpT_.x, i64 12, i1 false)
+// CHECK-NEXT:   %a52 = getelementptr inbounds nuw %struct.X, ptr %x51, i32 0, i32 0
+// CHECK-NEXT:   %43 = load i32, ptr %a52, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %43)
+// CHECK-NEXT:   br label %expand.end53
+// CHECK: expand.end53:
+// CHECK-NEXT:   %a55 = getelementptr inbounds nuw %struct.X, ptr %x54, i32 0, i32 0
+// CHECK-NEXT:   %44 = load i32, ptr %ts.addr, align 4
+// CHECK-NEXT:   store i32 %44, ptr %a55, align 4
+// CHECK-NEXT:   %b56 = getelementptr inbounds nuw %struct.X, ptr %x54, i32 0, i32 1
+// CHECK-NEXT:   %45 = load i32, ptr %ts.addr2, align 4
+// CHECK-NEXT:   store i32 %45, ptr %b56, align 4
+// CHECK-NEXT:   %c57 = getelementptr inbounds nuw %struct.X, ptr %x54, i32 0, i32 2
+// CHECK-NEXT:   %46 = load i32, ptr %ts.addr4, align 4
+// CHECK-NEXT:   store i32 %46, ptr %c57, align 4
+// CHECK-NEXT:   %a58 = getelementptr inbounds nuw %struct.X, ptr %x54, i32 0, i32 0
+// CHECK-NEXT:   %47 = load i32, ptr %a58, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %47)
+// CHECK-NEXT:   br label %expand.end59
+// CHECK: expand.end59:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z2t4IJLi42ELi43ELi44EEEvv()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x1 = alloca i32, align 4
+// CHECK-NEXT:   %x4 = alloca i32, align 4
+// CHECK-NEXT:   %x6 = alloca i32, align 4
+// CHECK-NEXT:   %x9 = alloca i32, align 4
+// CHECK-NEXT:   %x12 = alloca i32, align 4
+// CHECK-NEXT:   %x15 = alloca i32, align 4
+// CHECK-NEXT:   %x18 = alloca i32, align 4
+// CHECK-NEXT:   %x21 = alloca i32, align 4
+// CHECK-NEXT:   %x24 = alloca i32, align 4
+// CHECK-NEXT:   %x27 = alloca i32, align 4
+// CHECK-NEXT:   %x30 = alloca i32, align 4
+// CHECK-NEXT:   %x33 = alloca i32, align 4
+// CHECK-NEXT:   %x36 = alloca i32, align 4
+// CHECK-NEXT:   %x39 = alloca i32, align 4
+// CHECK-NEXT:   %x42 = alloca i32, align 4
+// CHECK-NEXT:   %x45 = alloca i32, align 4
+// CHECK-NEXT:   %x48 = alloca i32, align 4
+// CHECK-NEXT:   %x51 = alloca i32, align 4
+// CHECK-NEXT:   %x54 = alloca i32, align 4
+// CHECK-NEXT:   %x57 = alloca %struct.X, align 4
+// CHECK-NEXT:   %x60 = alloca %struct.X, align 4
+// CHECK-NEXT:   %x63 = alloca %struct.X, align 4
+// CHECK-NEXT:   %x66 = alloca %struct.X, align 4
+// CHECK-NEXT:   store i32 42, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 42)
+// CHECK-NEXT:   %call = call {{.*}} i32 @_Z2tgILi42EEiv()
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 43, ptr %x1, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 43)
+// CHECK-NEXT:   %call2 = call {{.*}} i32 @_Z2tgILi43EEiv()
+// CHECK-NEXT:   br label %expand.next3
+// CHECK: expand.next3:
+// CHECK-NEXT:   store i32 44, ptr %x4, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 44)
+// CHECK-NEXT:   %call5 = call {{.*}} i32 @_Z2tgILi44EEiv()
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store i32 1, ptr %x6, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 1)
+// CHECK-NEXT:   %call7 = call {{.*}} i32 @_Z2tgILi1EEiv()
+// CHECK-NEXT:   br label %expand.next8
+// CHECK: expand.next8:
+// CHECK-NEXT:   store i32 42, ptr %x9, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 42)
+// CHECK-NEXT:   %call10 = call {{.*}} i32 @_Z2tgILi42EEiv()
+// CHECK-NEXT:   br label %expand.next11
+// CHECK: expand.next11:
+// CHECK-NEXT:   store i32 43, ptr %x12, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 43)
+// CHECK-NEXT:   %call13 = call {{.*}} i32 @_Z2tgILi43EEiv()
+// CHECK-NEXT:   br label %expand.next14
+// CHECK: expand.next14:
+// CHECK-NEXT:   store i32 44, ptr %x15, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 44)
+// CHECK-NEXT:   %call16 = call {{.*}} i32 @_Z2tgILi44EEiv()
+// CHECK-NEXT:   br label %expand.next17
+// CHECK: expand.next17:
+// CHECK-NEXT:   store i32 2, ptr %x18, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 2)
+// CHECK-NEXT:   %call19 = call {{.*}} i32 @_Z2tgILi2EEiv()
+// CHECK-NEXT:   br label %expand.next20
+// CHECK: expand.next20:
+// CHECK-NEXT:   store i32 42, ptr %x21, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 42)
+// CHECK-NEXT:   %call22 = call {{.*}} i32 @_Z2tgILi42EEiv()
+// CHECK-NEXT:   br label %expand.next23
+// CHECK: expand.next23:
+// CHECK-NEXT:   store i32 43, ptr %x24, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 43)
+// CHECK-NEXT:   %call25 = call {{.*}} i32 @_Z2tgILi43EEiv()
+// CHECK-NEXT:   br label %expand.next26
+// CHECK: expand.next26:
+// CHECK-NEXT:   store i32 44, ptr %x27, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 44)
+// CHECK-NEXT:   %call28 = call {{.*}} i32 @_Z2tgILi44EEiv()
+// CHECK-NEXT:   br label %expand.next29
+// CHECK: expand.next29:
+// CHECK-NEXT:   store i32 3, ptr %x30, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 3)
+// CHECK-NEXT:   %call31 = call {{.*}} i32 @_Z2tgILi3EEiv()
+// CHECK-NEXT:   br label %expand.end32
+// CHECK: expand.end32:
+// CHECK-NEXT:   store i32 4, ptr %x33, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 4)
+// CHECK-NEXT:   %call34 = call {{.*}} i32 @_Z2tgILi4EEiv()
+// CHECK-NEXT:   br label %expand.next35
+// CHECK: expand.next35:
+// CHECK-NEXT:   store i32 42, ptr %x36, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 42)
+// CHECK-NEXT:   %call37 = call {{.*}} i32 @_Z2tgILi42EEiv()
+// CHECK-NEXT:   br label %expand.next38
+// CHECK: expand.next38:
+// CHECK-NEXT:   store i32 43, ptr %x39, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 43)
+// CHECK-NEXT:   %call40 = call {{.*}} i32 @_Z2tgILi43EEiv()
+// CHECK-NEXT:   br label %expand.next41
+// CHECK: expand.next41:
+// CHECK-NEXT:   store i32 44, ptr %x42, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 44)
+// CHECK-NEXT:   %call43 = call {{.*}} i32 @_Z2tgILi44EEiv()
+// CHECK-NEXT:   br label %expand.next44
+// CHECK: expand.next44:
+// CHECK-NEXT:   store i32 42, ptr %x45, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 42)
+// CHECK-NEXT:   %call46 = call {{.*}} i32 @_Z2tgILi42EEiv()
+// CHECK-NEXT:   br label %expand.next47
+// CHECK: expand.next47:
+// CHECK-NEXT:   store i32 43, ptr %x48, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 43)
+// CHECK-NEXT:   %call49 = call {{.*}} i32 @_Z2tgILi43EEiv()
+// CHECK-NEXT:   br label %expand.next50
+// CHECK: expand.next50:
+// CHECK-NEXT:   store i32 44, ptr %x51, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 44)
+// CHECK-NEXT:   %call52 = call {{.*}} i32 @_Z2tgILi44EEiv()
+// CHECK-NEXT:   br label %expand.next53
+// CHECK: expand.next53:
+// CHECK-NEXT:   store i32 5, ptr %x54, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 5)
+// CHECK-NEXT:   %call55 = call {{.*}} i32 @_Z2tgILi5EEiv()
+// CHECK-NEXT:   br label %expand.end56
+// CHECK: expand.end56:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x57, ptr align 4 @__const._Z2t4IJLi42ELi43ELi44EEEvv.x, i64 12, i1 false)
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 42)
+// CHECK-NEXT:   %call58 = call {{.*}} i32 @_Z2tgILi42EEiv()
+// CHECK-NEXT:   br label %expand.next59
+// CHECK: expand.next59:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x60, ptr align 4 @__const._Z2t4IJLi42ELi43ELi44EEEvv.x.3, i64 12, i1 false)
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 42)
+// CHECK-NEXT:   %call61 = call {{.*}} i32 @_Z2tgILi42EEiv()
+// CHECK-NEXT:   br label %expand.next62
+// CHECK: expand.next62:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x63, ptr align 4 @__const._Z2t4IJLi42ELi43ELi44EEEvv.x.4, i64 12, i1 false)
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 6)
+// CHECK-NEXT:   %call64 = call {{.*}} i32 @_Z2tgILi6EEiv()
+// CHECK-NEXT:   br label %expand.end65
+// CHECK: expand.end65:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x66, ptr align 4 @__const._Z2t4IJLi42ELi43ELi44EEEvv.x.5, i64 12, i1 false)
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 42)
+// CHECK-NEXT:   %call67 = call {{.*}} i32 @_Z2tgILi42EEiv()
+// CHECK-NEXT:   br label %expand.end68
+// CHECK: expand.end68:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x2 = alloca i32, align 4
+// CHECK-NEXT:   %x4 = alloca i32, align 4
+// CHECK-NEXT:   %x6 = alloca i32, align 4
+// CHECK-NEXT:   %x8 = alloca i32, align 4
+// CHECK-NEXT:   %x10 = alloca i32, align 4
+// CHECK-NEXT:   %x11 = alloca %struct.X, align 4
+// CHECK-NEXT:   %x13 = alloca %struct.X, align 4
+// CHECK-NEXT:   %x16 = alloca i32, align 4
+// CHECK-NEXT:   %x18 = alloca i32, align 4
+// CHECK-NEXT:   %x21 = alloca i32, align 4
+// CHECK-NEXT:   %x24 = alloca i32, align 4
+// CHECK-NEXT:   %x27 = alloca i32, align 4
+// CHECK-NEXT:   %x30 = alloca i32, align 4
+// CHECK-NEXT:   %x33 = alloca %struct.X, align 4
+// CHECK-NEXT:   %x36 = alloca %struct.X, align 4
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %0)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 2, ptr %x2, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %x2, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.next3
+// CHECK: expand.next3:
+// CHECK-NEXT:   store i32 3, ptr %x4, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x4, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %2)
+// CHECK-NEXT:   br label %expand.next5
+// CHECK: expand.next5:
+// CHECK-NEXT:   store i32 4, ptr %x6, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x6, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.next7
+// CHECK: expand.next7:
+// CHECK-NEXT:   store i32 5, ptr %x8, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x8, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %4)
+// CHECK-NEXT:   br label %expand.next9
+// CHECK: expand.next9:
+// CHECK-NEXT:   store i32 6, ptr %x10, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %x10, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %5)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x11, ptr align 4 @__const._ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv.x, i64 12, i1 false)
+// CHECK-NEXT:   %a = getelementptr inbounds nuw %struct.X, ptr %x11, i32 0, i32 0
+// CHECK-NEXT:   %6 = load i32, ptr %a, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %6)
+// CHECK-NEXT:   br label %expand.next12
+// CHECK: expand.next12:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x13, ptr align 4 @__const._ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv.x.6, i64 12, i1 false)
+// CHECK-NEXT:   %a14 = getelementptr inbounds nuw %struct.X, ptr %x13, i32 0, i32 0
+// CHECK-NEXT:   %7 = load i32, ptr %a14, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} %7)
+// CHECK-NEXT:   br label %expand.end15
+// CHECK: expand.end15:
+// CHECK-NEXT:   store i32 1, ptr %x16, align 4
+// CHECK-NEXT:   %call = call {{.*}} i32 @_Z2tgILi1EEiv()
+// CHECK-NEXT:   br label %expand.next17
+// CHECK: expand.next17:
+// CHECK-NEXT:   store i32 2, ptr %x18, align 4
+// CHECK-NEXT:   %call19 = call {{.*}} i32 @_Z2tgILi2EEiv()
+// CHECK-NEXT:   br label %expand.next20
+// CHECK: expand.next20:
+// CHECK-NEXT:   store i32 3, ptr %x21, align 4
+// CHECK-NEXT:   %call22 = call {{.*}} i32 @_Z2tgILi3EEiv()
+// CHECK-NEXT:   br label %expand.next23
+// CHECK: expand.next23:
+// CHECK-NEXT:   store i32 4, ptr %x24, align 4
+// CHECK-NEXT:   %call25 = call {{.*}} i32 @_Z2tgILi4EEiv()
+// CHECK-NEXT:   br label %expand.next26
+// CHECK: expand.next26:
+// CHECK-NEXT:   store i32 5, ptr %x27, align 4
+// CHECK-NEXT:   %call28 = call {{.*}} i32 @_Z2tgILi5EEiv()
+// CHECK-NEXT:   br label %expand.next29
+// CHECK: expand.next29:
+// CHECK-NEXT:   store i32 6, ptr %x30, align 4
+// CHECK-NEXT:   %call31 = call {{.*}} i32 @_Z2tgILi6EEiv()
+// CHECK-NEXT:   br label %expand.end32
+// CHECK: expand.end32:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x33, ptr align 4 @__const._ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv.x.7, i64 12, i1 false)
+// CHECK-NEXT:   %call34 = call {{.*}} i32 @_Z2tgILi1EEiv()
+// CHECK-NEXT:   br label %expand.next35
+// CHECK: expand.next35:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x36, ptr align 4 @__const._ZN2s2IJLi1ELi2ELi3EEE2tfIJLi4ELi5ELi6EEEEvv.x.8, i64 12, i1 false)
+// CHECK-NEXT:   %call37 = call {{.*}} i32 @_Z2tgILi4EEiv()
+// CHECK-NEXT:   br label %expand.end38
+// CHECK: expand.end38:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z2f8v()
+// CHECK: entry:
+// CHECK-NEXT:   call void @_Z2t5IJLi1ELi2ELi3EEEvv()
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z2t5IJLi1ELi2ELi3EEEvv()
+// CHECK: entry:
+// CHECK-NEXT:   %ref.tmp = alloca %class.anon, align 1
+// CHECK-NEXT:   %ref.tmp1 = alloca %class.anon.1, align 1
+// CHECK-NEXT:   %ref.tmp2 = alloca %class.anon.3, align 1
+// CHECK-NEXT:   call void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE1_clEv(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   call void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE0_clEv(ptr {{.*}} %ref.tmp1)
+// CHECK-NEXT:   call void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE_clEv(ptr {{.*}} %ref.tmp2)
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z22references_enumeratingv()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %y = alloca i32, align 4
+// CHECK-NEXT:   %z = alloca i32, align 4
+// CHECK-NEXT:   %v = alloca ptr, align 8
+// CHECK-NEXT:   %v1 = alloca ptr, align 8
+// CHECK-NEXT:   %v4 = alloca ptr, align 8
+// CHECK-NEXT:   %v6 = alloca ptr, align 8
+// CHECK-NEXT:   %v9 = alloca ptr, align 8
+// CHECK-NEXT:   %v12 = alloca ptr, align 8
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   store i32 2, ptr %y, align 4
+// CHECK-NEXT:   store i32 3, ptr %z, align 4
+// CHECK-NEXT:   store ptr %x, ptr %v, align 8
+// CHECK-NEXT:   %0 = load ptr, ptr %v, align 8
+// CHECK-NEXT:   %1 = load i32, ptr %0, align 4
+// CHECK-NEXT:   %inc = add nsw i32 %1, 1
+// CHECK-NEXT:   store i32 %inc, ptr %0, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store ptr %y, ptr %v1, align 8
+// CHECK-NEXT:   %2 = load ptr, ptr %v1, align 8
+// CHECK-NEXT:   %3 = load i32, ptr %2, align 4
+// CHECK-NEXT:   %inc2 = add nsw i32 %3, 1
+// CHECK-NEXT:   store i32 %inc2, ptr %2, align 4
+// CHECK-NEXT:   br label %expand.next3
+// CHECK: expand.next3:
+// CHECK-NEXT:   store ptr %z, ptr %v4, align 8
+// CHECK-NEXT:   %4 = load ptr, ptr %v4, align 8
+// CHECK-NEXT:   %5 = load i32, ptr %4, align 4
+// CHECK-NEXT:   %inc5 = add nsw i32 %5, 1
+// CHECK-NEXT:   store i32 %inc5, ptr %4, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store ptr %x, ptr %v6, align 8
+// CHECK-NEXT:   %6 = load ptr, ptr %v6, align 8
+// CHECK-NEXT:   %7 = load i32, ptr %6, align 4
+// CHECK-NEXT:   %inc7 = add nsw i32 %7, 1
+// CHECK-NEXT:   store i32 %inc7, ptr %6, align 4
+// CHECK-NEXT:   br label %expand.next8
+// CHECK: expand.next8:
+// CHECK-NEXT:   store ptr %y, ptr %v9, align 8
+// CHECK-NEXT:   %8 = load ptr, ptr %v9, align 8
+// CHECK-NEXT:   %9 = load i32, ptr %8, align 4
+// CHECK-NEXT:   %inc10 = add nsw i32 %9, 1
+// CHECK-NEXT:   store i32 %inc10, ptr %8, align 4
+// CHECK-NEXT:   br label %expand.next11
+// CHECK: expand.next11:
+// CHECK-NEXT:   store ptr %z, ptr %v12, align 8
+// CHECK-NEXT:   %10 = load ptr, ptr %v12, align 8
+// CHECK-NEXT:   %11 = load i32, ptr %10, align 4
+// CHECK-NEXT:   %inc13 = add nsw i32 %11, 1
+// CHECK-NEXT:   store i32 %inc13, ptr %10, align 4
+// CHECK-NEXT:   br label %expand.end14
+// CHECK: expand.end14:
+// CHECK-NEXT:   %12 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %13 = load i32, ptr %y, align 4
+// CHECK-NEXT:   %add = add nsw i32 %12, %13
+// CHECK-NEXT:   %14 = load i32, ptr %z, align 4
+// CHECK-NEXT:   %add15 = add nsw i32 %add, %14
+// CHECK-NEXT:   ret i32 %add15
+
+
+// CHECK-LABEL: define {{.*}} void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE1_clEv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 1)
+// CHECK-NEXT:   %call = call {{.*}} i32 @_Z2tgILi1EEiv()
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE0_clEv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   store i32 2, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 2)
+// CHECK-NEXT:   %call = call {{.*}} i32 @_Z2tgILi2EEiv()
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_ZZ2t5IJLi1ELi2ELi3EEEvvENKUlvE_clEv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   store i32 3, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1gi(i32 {{.*}} 3)
+// CHECK-NEXT:   %call = call {{.*}} i32 @_Z2tgILi3EEiv()
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   ret void
diff --git a/clang/test/CodeGenCXX/cxx2c-expansion-stmts-control-flow.cpp b/clang/test/CodeGenCXX/cxx2c-expansion-stmts-control-flow.cpp
new file mode 100644
index 0000000000000..7bcaf56adf652
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx2c-expansion-stmts-control-flow.cpp
@@ -0,0 +1,430 @@
+// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+void h(int, int);
+
+void break_continue() {
+  template for (auto x : {1, 2}) {
+    break;
+    h(1, x);
+  }
+
+  template for (auto x : {3, 4}) {
+    continue;
+    h(2, x);
+  }
+
+  template for (auto x : {5, 6}) {
+    if (x == 2) break;
+    h(3, x);
+  }
+
+  template for (auto x : {7, 8}) {
+    if (x == 2) continue;
+    h(4, x);
+  }
+}
+
+int break_continue_nested() {
+  int sum = 0;
+
+  template for (auto x : {1, 2}) {
+    template for (auto y : {3, 4}) {
+      if (x == 2) break;
+      sum += y;
+    }
+    sum += x;
+  }
+
+  template for (auto x : {5, 6}) {
+    template for (auto y : {7, 8}) {
+      if (x == 6) continue;
+      sum += y;
+    }
+    sum += x;
+  }
+
+  return sum;
+}
+
+void label() {
+  // Only local labels are allowed in expansion statements.
+  template for (auto x : {1, 2, 3}) {
+    __label__ a;
+    if (x == 1) goto a;
+    h(1, x);
+    a:;
+  }
+}
+
+void nested_label() {
+  template for (auto x : {1, 2}) {
+    __label__ a;
+    template for (auto y : {3, 4}) {
+      if (y == 3) goto a;
+      if (y == 4) goto end;
+      h(x, y);
+    }
+    a:;
+  }
+  end:
+}
+
+
+// CHECK-LABEL: define {{.*}} void @_Z14break_continuev()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x1 = alloca i32, align 4
+// CHECK-NEXT:   %x2 = alloca i32, align 4
+// CHECK-NEXT:   %x3 = alloca i32, align 4
+// CHECK-NEXT:   %x5 = alloca i32, align 4
+// CHECK-NEXT:   %x7 = alloca i32, align 4
+// CHECK-NEXT:   %x12 = alloca i32, align 4
+// CHECK-NEXT:   %x17 = alloca i32, align 4
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store i32 3, ptr %x2, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 4, ptr %x3, align 4
+// CHECK-NEXT:   br label %expand.end4
+// CHECK: expand.end4:
+// CHECK-NEXT:   store i32 5, ptr %x5, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x5, align 4
+// CHECK-NEXT:   %cmp = icmp eq i32 %0, 2
+// CHECK-NEXT:   br i1 %cmp, label %if.then, label %if.end
+// CHECK: if.then:
+// CHECK-NEXT:   br label %expand.end11
+// CHECK: if.end:
+// CHECK-NEXT:   %1 = load i32, ptr %x5, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} 3, i32 {{.*}} %1)
+// CHECK-NEXT:   br label %expand.next6
+// CHECK: expand.next6:
+// CHECK-NEXT:   store i32 6, ptr %x7, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x7, align 4
+// CHECK-NEXT:   %cmp8 = icmp eq i32 %2, 2
+// CHECK-NEXT:   br i1 %cmp8, label %if.then9, label %if.end10
+// CHECK: if.then9:
+// CHECK-NEXT:   br label %expand.end11
+// CHECK: if.end10:
+// CHECK-NEXT:   %3 = load i32, ptr %x7, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} 3, i32 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.end11
+// CHECK: expand.end11:
+// CHECK-NEXT:   store i32 7, ptr %x12, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x12, align 4
+// CHECK-NEXT:   %cmp13 = icmp eq i32 %4, 2
+// CHECK-NEXT:   br i1 %cmp13, label %if.then14, label %if.end15
+// CHECK: if.then14:
+// CHECK-NEXT:   br label %expand.next16
+// CHECK: if.end15:
+// CHECK-NEXT:   %5 = load i32, ptr %x12, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} 4, i32 {{.*}} %5)
+// CHECK-NEXT:   br label %expand.next16
+// CHECK: expand.next16:
+// CHECK-NEXT:   store i32 8, ptr %x17, align 4
+// CHECK-NEXT:   %6 = load i32, ptr %x17, align 4
+// CHECK-NEXT:   %cmp18 = icmp eq i32 %6, 2
+// CHECK-NEXT:   br i1 %cmp18, label %if.then19, label %if.end20
+// CHECK: if.then19:
+// CHECK-NEXT:   br label %expand.end21
+// CHECK: if.end20:
+// CHECK-NEXT:   %7 = load i32, ptr %x17, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} 4, i32 {{.*}} %7)
+// CHECK-NEXT:   br label %expand.end21
+// CHECK: expand.end21:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z21break_continue_nestedv()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %y = alloca i32, align 4
+// CHECK-NEXT:   %y1 = alloca i32, align 4
+// CHECK-NEXT:   %x8 = alloca i32, align 4
+// CHECK-NEXT:   %y9 = alloca i32, align 4
+// CHECK-NEXT:   %y15 = alloca i32, align 4
+// CHECK-NEXT:   %x23 = alloca i32, align 4
+// CHECK-NEXT:   %y24 = alloca i32, align 4
+// CHECK-NEXT:   %y30 = alloca i32, align 4
+// CHECK-NEXT:   %x38 = alloca i32, align 4
+// CHECK-NEXT:   %y39 = alloca i32, align 4
+// CHECK-NEXT:   %y45 = alloca i32, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   store i32 3, ptr %y, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %cmp = icmp eq i32 %0, 2
+// CHECK-NEXT:   br i1 %cmp, label %if.then, label %if.end
+// CHECK: if.then:
+// CHECK-NEXT:   br label %expand.end
+// CHECK: if.end:
+// CHECK-NEXT:   %1 = load i32, ptr %y, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %2, %1
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 4, ptr %y1, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %cmp2 = icmp eq i32 %3, 2
+// CHECK-NEXT:   br i1 %cmp2, label %if.then3, label %if.end4
+// CHECK: if.then3:
+// CHECK-NEXT:   br label %expand.end
+// CHECK: if.end4:
+// CHECK-NEXT:   %4 = load i32, ptr %y1, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add5 = add nsw i32 %5, %4
+// CHECK-NEXT:   store i32 %add5, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   %6 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add6 = add nsw i32 %7, %6
+// CHECK-NEXT:   store i32 %add6, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next7
+// CHECK: expand.next7:
+// CHECK-NEXT:   store i32 2, ptr %x8, align 4
+// CHECK-NEXT:   store i32 3, ptr %y9, align 4
+// CHECK-NEXT:   %8 = load i32, ptr %x8, align 4
+// CHECK-NEXT:   %cmp10 = icmp eq i32 %8, 2
+// CHECK-NEXT:   br i1 %cmp10, label %if.then11, label %if.end12
+// CHECK: if.then11:
+// CHECK-NEXT:   br label %expand.end20
+// CHECK: if.end12:
+// CHECK-NEXT:   %9 = load i32, ptr %y9, align 4
+// CHECK-NEXT:   %10 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add13 = add nsw i32 %10, %9
+// CHECK-NEXT:   store i32 %add13, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next14
+// CHECK: expand.next14:
+// CHECK-NEXT:   store i32 4, ptr %y15, align 4
+// CHECK-NEXT:   %11 = load i32, ptr %x8, align 4
+// CHECK-NEXT:   %cmp16 = icmp eq i32 %11, 2
+// CHECK-NEXT:   br i1 %cmp16, label %if.then17, label %if.end18
+// CHECK: if.then17:
+// CHECK-NEXT:   br label %expand.end20
+// CHECK: if.end18:
+// CHECK-NEXT:   %12 = load i32, ptr %y15, align 4
+// CHECK-NEXT:   %13 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add19 = add nsw i32 %13, %12
+// CHECK-NEXT:   store i32 %add19, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end20
+// CHECK: expand.end20:
+// CHECK-NEXT:   %14 = load i32, ptr %x8, align 4
+// CHECK-NEXT:   %15 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add21 = add nsw i32 %15, %14
+// CHECK-NEXT:   store i32 %add21, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end22
+// CHECK: expand.end22:
+// CHECK-NEXT:   store i32 5, ptr %x23, align 4
+// CHECK-NEXT:   store i32 7, ptr %y24, align 4
+// CHECK-NEXT:   %16 = load i32, ptr %x23, align 4
+// CHECK-NEXT:   %cmp25 = icmp eq i32 %16, 6
+// CHECK-NEXT:   br i1 %cmp25, label %if.then26, label %if.end27
+// CHECK: if.then26:
+// CHECK-NEXT:   br label %expand.next29
+// CHECK: if.end27:
+// CHECK-NEXT:   %17 = load i32, ptr %y24, align 4
+// CHECK-NEXT:   %18 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add28 = add nsw i32 %18, %17
+// CHECK-NEXT:   store i32 %add28, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next29
+// CHECK: expand.next29:
+// CHECK-NEXT:   store i32 8, ptr %y30, align 4
+// CHECK-NEXT:   %19 = load i32, ptr %x23, align 4
+// CHECK-NEXT:   %cmp31 = icmp eq i32 %19, 6
+// CHECK-NEXT:   br i1 %cmp31, label %if.then32, label %if.end33
+// CHECK: if.then32:
+// CHECK-NEXT:   br label %expand.end35
+// CHECK: if.end33:
+// CHECK-NEXT:   %20 = load i32, ptr %y30, align 4
+// CHECK-NEXT:   %21 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add34 = add nsw i32 %21, %20
+// CHECK-NEXT:   store i32 %add34, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end35
+// CHECK: expand.end35:
+// CHECK-NEXT:   %22 = load i32, ptr %x23, align 4
+// CHECK-NEXT:   %23 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add36 = add nsw i32 %23, %22
+// CHECK-NEXT:   store i32 %add36, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next37
+// CHECK: expand.next37:
+// CHECK-NEXT:   store i32 6, ptr %x38, align 4
+// CHECK-NEXT:   store i32 7, ptr %y39, align 4
+// CHECK-NEXT:   %24 = load i32, ptr %x38, align 4
+// CHECK-NEXT:   %cmp40 = icmp eq i32 %24, 6
+// CHECK-NEXT:   br i1 %cmp40, label %if.then41, label %if.end42
+// CHECK: if.then41:
+// CHECK-NEXT:   br label %expand.next44
+// CHECK: if.end42:
+// CHECK-NEXT:   %25 = load i32, ptr %y39, align 4
+// CHECK-NEXT:   %26 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add43 = add nsw i32 %26, %25
+// CHECK-NEXT:   store i32 %add43, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next44
+// CHECK: expand.next44:
+// CHECK-NEXT:   store i32 8, ptr %y45, align 4
+// CHECK-NEXT:   %27 = load i32, ptr %x38, align 4
+// CHECK-NEXT:   %cmp46 = icmp eq i32 %27, 6
+// CHECK-NEXT:   br i1 %cmp46, label %if.then47, label %if.end48
+// CHECK: if.then47:
+// CHECK-NEXT:   br label %expand.end50
+// CHECK: if.end48:
+// CHECK-NEXT:   %28 = load i32, ptr %y45, align 4
+// CHECK-NEXT:   %29 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add49 = add nsw i32 %29, %28
+// CHECK-NEXT:   store i32 %add49, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end50
+// CHECK: expand.end50:
+// CHECK-NEXT:   %30 = load i32, ptr %x38, align 4
+// CHECK-NEXT:   %31 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add51 = add nsw i32 %31, %30
+// CHECK-NEXT:   store i32 %add51, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end52
+// CHECK: expand.end52:
+// CHECK-NEXT:   %32 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %32
+
+
+// CHECK-LABEL: define {{.*}} void @_Z5labelv()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x1 = alloca i32, align 4
+// CHECK-NEXT:   %x7 = alloca i32, align 4
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %cmp = icmp eq i32 %0, 1
+// CHECK-NEXT:   br i1 %cmp, label %if.then, label %if.end
+// CHECK: if.then:
+// CHECK-NEXT:   br label %a
+// CHECK: if.end:
+// CHECK-NEXT:   %1 = load i32, ptr %x, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} 1, i32 {{.*}} %1)
+// CHECK-NEXT:   br label %a
+// CHECK: a:
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 2, ptr %x1, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x1, align 4
+// CHECK-NEXT:   %cmp2 = icmp eq i32 %2, 1
+// CHECK-NEXT:   br i1 %cmp2, label %if.then3, label %if.end4
+// CHECK: if.then3:
+// CHECK-NEXT:   br label %a5
+// CHECK: if.end4:
+// CHECK-NEXT:   %3 = load i32, ptr %x1, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} 1, i32 {{.*}} %3)
+// CHECK-NEXT:   br label %a5
+// CHECK: a5:
+// CHECK-NEXT:   br label %expand.next6
+// CHECK: expand.next6:
+// CHECK-NEXT:   store i32 3, ptr %x7, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x7, align 4
+// CHECK-NEXT:   %cmp8 = icmp eq i32 %4, 1
+// CHECK-NEXT:   br i1 %cmp8, label %if.then9, label %if.end10
+// CHECK: if.then9:
+// CHECK-NEXT:   br label %a11
+// CHECK: if.end10:
+// CHECK-NEXT:   %5 = load i32, ptr %x7, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} 1, i32 {{.*}} %5)
+// CHECK-NEXT:   br label %a11
+// CHECK: a11:
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_Z12nested_labelv()
+// CHECK: entry:
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %y = alloca i32, align 4
+// CHECK-NEXT:   %y4 = alloca i32, align 4
+// CHECK-NEXT:   %x12 = alloca i32, align 4
+// CHECK-NEXT:   %y13 = alloca i32, align 4
+// CHECK-NEXT:   %y21 = alloca i32, align 4
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   store i32 3, ptr %y, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %y, align 4
+// CHECK-NEXT:   %cmp = icmp eq i32 %0, 3
+// CHECK-NEXT:   br i1 %cmp, label %if.then, label %if.end
+// CHECK: if.then:
+// CHECK-NEXT:   br label %a
+// CHECK: if.end:
+// CHECK-NEXT:   %1 = load i32, ptr %y, align 4
+// CHECK-NEXT:   %cmp1 = icmp eq i32 %1, 4
+// CHECK-NEXT:   br i1 %cmp1, label %if.then2, label %if.end3
+// CHECK: if.then2:
+// CHECK-NEXT:   br label %end
+// CHECK: if.end3:
+// CHECK-NEXT:   %2 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %y, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} %2, i32 {{.*}} %3)
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 4, ptr %y4, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %y4, align 4
+// CHECK-NEXT:   %cmp5 = icmp eq i32 %4, 3
+// CHECK-NEXT:   br i1 %cmp5, label %if.then6, label %if.end7
+// CHECK: if.then6:
+// CHECK-NEXT:   br label %a
+// CHECK: if.end7:
+// CHECK-NEXT:   %5 = load i32, ptr %y4, align 4
+// CHECK-NEXT:   %cmp8 = icmp eq i32 %5, 4
+// CHECK-NEXT:   br i1 %cmp8, label %if.then9, label %if.end10
+// CHECK: if.then9:
+// CHECK-NEXT:   br label %end
+// CHECK: if.end10:
+// CHECK-NEXT:   %6 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %y4, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} %6, i32 {{.*}} %7)
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   br label %a
+// CHECK: a:
+// CHECK-NEXT:   br label %expand.next11
+// CHECK: expand.next11:
+// CHECK-NEXT:   store i32 2, ptr %x12, align 4
+// CHECK-NEXT:   store i32 3, ptr %y13, align 4
+// CHECK-NEXT:   %8 = load i32, ptr %y13, align 4
+// CHECK-NEXT:   %cmp14 = icmp eq i32 %8, 3
+// CHECK-NEXT:   br i1 %cmp14, label %if.then15, label %if.end16
+// CHECK: if.then15:
+// CHECK-NEXT:   br label %a29
+// CHECK: if.end16:
+// CHECK-NEXT:   %9 = load i32, ptr %y13, align 4
+// CHECK-NEXT:   %cmp17 = icmp eq i32 %9, 4
+// CHECK-NEXT:   br i1 %cmp17, label %if.then18, label %if.end19
+// CHECK: if.then18:
+// CHECK-NEXT:   br label %end
+// CHECK: if.end19:
+// CHECK-NEXT:   %10 = load i32, ptr %x12, align 4
+// CHECK-NEXT:   %11 = load i32, ptr %y13, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} %10, i32 {{.*}} %11)
+// CHECK-NEXT:   br label %expand.next20
+// CHECK: expand.next20:
+// CHECK-NEXT:   store i32 4, ptr %y21, align 4
+// CHECK-NEXT:   %12 = load i32, ptr %y21, align 4
+// CHECK-NEXT:   %cmp22 = icmp eq i32 %12, 3
+// CHECK-NEXT:   br i1 %cmp22, label %if.then23, label %if.end24
+// CHECK: if.then23:
+// CHECK-NEXT:   br label %a29
+// CHECK: if.end24:
+// CHECK-NEXT:   %13 = load i32, ptr %y21, align 4
+// CHECK-NEXT:   %cmp25 = icmp eq i32 %13, 4
+// CHECK-NEXT:   br i1 %cmp25, label %if.then26, label %if.end27
+// CHECK: if.then26:
+// CHECK-NEXT:   br label %end
+// CHECK: if.end27:
+// CHECK-NEXT:   %14 = load i32, ptr %x12, align 4
+// CHECK-NEXT:   %15 = load i32, ptr %y21, align 4
+// CHECK-NEXT:   call void @_Z1hii(i32 {{.*}} %14, i32 {{.*}} %15)
+// CHECK-NEXT:   br label %expand.end28
+// CHECK: expand.end28:
+// CHECK-NEXT:   br label %a29
+// CHECK: a29:
+// CHECK-NEXT:   br label %expand.end30
+// CHECK: expand.end30:
+// CHECK-NEXT:   br label %end
+// CHECK: end:
+// CHECK-NEXT:   ret void
diff --git a/clang/test/CodeGenCXX/cxx2c-expansion-stmts-mangling.cpp b/clang/test/CodeGenCXX/cxx2c-expansion-stmts-mangling.cpp
new file mode 100644
index 0000000000000..5616bc65c7853
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx2c-expansion-stmts-mangling.cpp
@@ -0,0 +1,134 @@
+// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: @_ZZ2f1vE1y = internal global i32 1, align 4
+// CHECK: @_ZZ2f1vE1y_0 = internal global i32 2, align 4
+// CHECK: @_ZZ2f1vE1y_1 = internal global i32 3, align 4
+// CHECK: @_ZZ2f1vE1y_2 = internal global i32 4, align 4
+
+// CHECK-LABEL: define {{.*}} i32 @_Z2f1v()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x1 = alloca i32, align 4
+// CHECK-NEXT:   %x4 = alloca i32, align 4
+// CHECK-NEXT:   %x7 = alloca i32, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %0 = load i32, ptr @_ZZ2f1vE1y, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %1, %0
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 2, ptr %x1, align 4
+// CHECK-NEXT:   %2 = load i32, ptr @_ZZ2f1vE1y_0, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add2 = add nsw i32 %3, %2
+// CHECK-NEXT:   store i32 %add2, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next3
+// CHECK: expand.next3:
+// CHECK-NEXT:   store i32 3, ptr %x4, align 4
+// CHECK-NEXT:   %4 = load i32, ptr @_ZZ2f1vE1y_1, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add5 = add nsw i32 %5, %4
+// CHECK-NEXT:   store i32 %add5, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next6
+// CHECK: expand.next6:
+// CHECK-NEXT:   store i32 4, ptr %x7, align 4
+// CHECK-NEXT:   %6 = load i32, ptr @_ZZ2f1vE1y_2, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add8 = add nsw i32 %7, %6
+// CHECK-NEXT:   store i32 %add8, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   %8 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %8
+int f1() {
+  int sum = 0;
+  template for (constexpr auto x : {1, 2, 3, 4}) {
+    static int y = x;
+    sum += y;
+  }
+  return sum;
+}
+
+// CHECK-LABEL: define {{.*}} i32 @_Z2f2v()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %ref.tmp = alloca %class.anon, align 1
+// CHECK-NEXT:   %x1 = alloca i32, align 4
+// CHECK-NEXT:   %ref.tmp2 = alloca %class.anon.0, align 1
+// CHECK-NEXT:   %x6 = alloca i32, align 4
+// CHECK-NEXT:   %ref.tmp7 = alloca %class.anon.2, align 1
+// CHECK-NEXT:   %x11 = alloca i32, align 4
+// CHECK-NEXT:   %ref.tmp12 = alloca %class.anon.4, align 1
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %call = call {{.*}} i32 @_ZZ2f2vENKUlvE_clEv(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   %0 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %0, %call
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 2, ptr %x1, align 4
+// CHECK-NEXT:   %call3 = call {{.*}} i32 @_ZZ2f2vENKUlvE0_clEv(ptr {{.*}} %ref.tmp2)
+// CHECK-NEXT:   %1 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add4 = add nsw i32 %1, %call3
+// CHECK-NEXT:   store i32 %add4, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next5
+// CHECK: expand.next5:
+// CHECK-NEXT:   store i32 3, ptr %x6, align 4
+// CHECK-NEXT:   %call8 = call {{.*}} i32 @_ZZ2f2vENKUlvE1_clEv(ptr {{.*}} %ref.tmp7)
+// CHECK-NEXT:   %2 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add9 = add nsw i32 %2, %call8
+// CHECK-NEXT:   store i32 %add9, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next10
+// CHECK: expand.next10:
+// CHECK-NEXT:   store i32 4, ptr %x11, align 4
+// CHECK-NEXT:   %call13 = call {{.*}} i32 @_ZZ2f2vENKUlvE2_clEv(ptr {{.*}} %ref.tmp12)
+// CHECK-NEXT:   %3 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add14 = add nsw i32 %3, %call13
+// CHECK-NEXT:   store i32 %add14, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   %4 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %4
+int f2() {
+  int sum = 0;
+  template for (constexpr auto x : {1, 2, 3, 4}) {
+    sum += []{ return x; }();
+  }
+  return sum;
+}
+
+// CHECK-LABEL: define {{.*}} i32 @_ZZ2f2vENKUlvE_clEv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   ret i32 1
+
+
+// CHECK-LABEL: define {{.*}} i32 @_ZZ2f2vENKUlvE0_clEv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   ret i32 2
+
+
+// CHECK-LABEL: define {{.*}} i32 @_ZZ2f2vENKUlvE1_clEv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   ret i32 3
+
+
+// CHECK-LABEL: define {{.*}} i32 @_ZZ2f2vENKUlvE2_clEv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   ret i32 4
diff --git a/clang/test/CodeGenCXX/cxx2c-expansion-stmts-templates.cpp b/clang/test/CodeGenCXX/cxx2c-expansion-stmts-templates.cpp
new file mode 100644
index 0000000000000..e0de7ced5baee
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx2c-expansion-stmts-templates.cpp
@@ -0,0 +1,208 @@
+// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+struct E {
+  int x, y;
+  constexpr E(int x, int y) : x{x}, y{y} {}
+};
+
+template <typename ...Es>
+int unexpanded_pack_good(Es ...es) {
+  int sum = 0;
+  ([&] {
+    template for (auto x : es) sum += x;
+    template for (Es e : {{5, 6}, {7, 8}}) sum += e.x + e.y;
+  }(), ...);
+  return sum;
+}
+
+int unexpanded_pack() {
+  return unexpanded_pack_good(E{1, 2}, E{3, 4});
+}
+
+
+// CHECK: %struct.E = type { i32, i32 }
+// CHECK: %class.anon = type { ptr, ptr }
+// CHECK: %class.anon.0 = type { ptr, ptr }
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z15unexpanded_packv()
+// CHECK: entry:
+// CHECK-NEXT:   %agg.tmp = alloca %struct.E, align 4
+// CHECK-NEXT:   %agg.tmp1 = alloca %struct.E, align 4
+// CHECK-NEXT:   call void @_ZN1EC1Eii(ptr {{.*}} %agg.tmp, i32 {{.*}} 1, i32 {{.*}} 2)
+// CHECK-NEXT:   call void @_ZN1EC1Eii(ptr {{.*}} %agg.tmp1, i32 {{.*}} 3, i32 {{.*}} 4)
+// CHECK-NEXT:   %0 = load i64, ptr %agg.tmp, align 4
+// CHECK-NEXT:   %1 = load i64, ptr %agg.tmp1, align 4
+// CHECK-NEXT:   %call = call {{.*}} i32 @_Z20unexpanded_pack_goodIJ1ES0_EEiDpT_(i64 %0, i64 %1)
+// CHECK-NEXT:   ret i32 %call
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z20unexpanded_pack_goodIJ1ES0_EEiDpT_(i64 %es.coerce, i64 %es.coerce2)
+// CHECK: entry:
+// CHECK-NEXT:   %es = alloca %struct.E, align 4
+// CHECK-NEXT:   %es3 = alloca %struct.E, align 4
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %ref.tmp = alloca %class.anon, align 8
+// CHECK-NEXT:   %ref.tmp4 = alloca %class.anon.0, align 8
+// CHECK-NEXT:   store i64 %es.coerce, ptr %es, align 4
+// CHECK-NEXT:   store i64 %es.coerce2, ptr %es3, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   %0 = getelementptr inbounds nuw %class.anon, ptr %ref.tmp, i32 0, i32 0
+// CHECK-NEXT:   store ptr %es, ptr %0, align 8
+// CHECK-NEXT:   %1 = getelementptr inbounds nuw %class.anon, ptr %ref.tmp, i32 0, i32 1
+// CHECK-NEXT:   store ptr %sum, ptr %1, align 8
+// CHECK-NEXT:   call void @_ZZ20unexpanded_pack_goodIJ1ES0_EEiDpT_ENKUlvE0_clEv(ptr {{.*}} %ref.tmp)
+// CHECK-NEXT:   %2 = getelementptr inbounds nuw %class.anon.0, ptr %ref.tmp4, i32 0, i32 0
+// CHECK-NEXT:   store ptr %es3, ptr %2, align 8
+// CHECK-NEXT:   %3 = getelementptr inbounds nuw %class.anon.0, ptr %ref.tmp4, i32 0, i32 1
+// CHECK-NEXT:   store ptr %sum, ptr %3, align 8
+// CHECK-NEXT:   call void @_ZZ20unexpanded_pack_goodIJ1ES0_EEiDpT_ENKUlvE_clEv(ptr {{.*}} %ref.tmp4)
+// CHECK-NEXT:   %4 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %4
+
+
+// CHECK-LABEL: define {{.*}} void @_ZN1EC1Eii(ptr {{.*}} %this, i32 {{.*}} %x, i32 {{.*}} %y) {{.*}}
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %x.addr = alloca i32, align 4
+// CHECK-NEXT:   %y.addr = alloca i32, align 4
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   store i32 %x, ptr %x.addr, align 4
+// CHECK-NEXT:   store i32 %y, ptr %y.addr, align 4
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   %0 = load i32, ptr %x.addr, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %y.addr, align 4
+// CHECK-NEXT:   call void @_ZN1EC2Eii(ptr {{.*}} %this1, i32 {{.*}} %0, i32 {{.*}} %1)
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_ZZ20unexpanded_pack_goodIJ1ES0_EEiDpT_ENKUlvE0_clEv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x3 = alloca i32, align 4
+// CHECK-NEXT:   %e = alloca %struct.E, align 4
+// CHECK-NEXT:   %e10 = alloca %struct.E, align 4
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   %1 = getelementptr inbounds nuw %class.anon, ptr %this1, i32 0, i32 0
+// CHECK-NEXT:   %2 = load ptr, ptr %1, align 8
+// CHECK-NEXT:   store ptr %2, ptr %0, align 8
+// CHECK-NEXT:   %3 = load ptr, ptr %0, align 8
+// CHECK-NEXT:   %x2 = getelementptr inbounds nuw %struct.E, ptr %3, i32 0, i32 0
+// CHECK-NEXT:   %4 = load i32, ptr %x2, align 4
+// CHECK-NEXT:   store i32 %4, ptr %x, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %6 = getelementptr inbounds nuw %class.anon, ptr %this1, i32 0, i32 1
+// CHECK-NEXT:   %7 = load ptr, ptr %6, align 8
+// CHECK-NEXT:   %8 = load i32, ptr %7, align 4
+// CHECK-NEXT:   %add = add nsw i32 %8, %5
+// CHECK-NEXT:   store i32 %add, ptr %7, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   %9 = load ptr, ptr %0, align 8
+// CHECK-NEXT:   %y = getelementptr inbounds nuw %struct.E, ptr %9, i32 0, i32 1
+// CHECK-NEXT:   %10 = load i32, ptr %y, align 4
+// CHECK-NEXT:   store i32 %10, ptr %x3, align 4
+// CHECK-NEXT:   %11 = load i32, ptr %x3, align 4
+// CHECK-NEXT:   %12 = getelementptr inbounds nuw %class.anon, ptr %this1, i32 0, i32 1
+// CHECK-NEXT:   %13 = load ptr, ptr %12, align 8
+// CHECK-NEXT:   %14 = load i32, ptr %13, align 4
+// CHECK-NEXT:   %add4 = add nsw i32 %14, %11
+// CHECK-NEXT:   store i32 %add4, ptr %13, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   call void @_ZN1EC1Eii(ptr {{.*}} %e, i32 {{.*}} 5, i32 {{.*}} 6)
+// CHECK-NEXT:   %x5 = getelementptr inbounds nuw %struct.E, ptr %e, i32 0, i32 0
+// CHECK-NEXT:   %15 = load i32, ptr %x5, align 4
+// CHECK-NEXT:   %y6 = getelementptr inbounds nuw %struct.E, ptr %e, i32 0, i32 1
+// CHECK-NEXT:   %16 = load i32, ptr %y6, align 4
+// CHECK-NEXT:   %add7 = add nsw i32 %15, %16
+// CHECK-NEXT:   %17 = getelementptr inbounds nuw %class.anon, ptr %this1, i32 0, i32 1
+// CHECK-NEXT:   %18 = load ptr, ptr %17, align 8
+// CHECK-NEXT:   %19 = load i32, ptr %18, align 4
+// CHECK-NEXT:   %add8 = add nsw i32 %19, %add7
+// CHECK-NEXT:   store i32 %add8, ptr %18, align 4
+// CHECK-NEXT:   br label %expand.next9
+// CHECK: expand.next9:
+// CHECK-NEXT:   call void @_ZN1EC1Eii(ptr {{.*}} %e10, i32 {{.*}} 7, i32 {{.*}} 8)
+// CHECK-NEXT:   %x11 = getelementptr inbounds nuw %struct.E, ptr %e10, i32 0, i32 0
+// CHECK-NEXT:   %20 = load i32, ptr %x11, align 4
+// CHECK-NEXT:   %y12 = getelementptr inbounds nuw %struct.E, ptr %e10, i32 0, i32 1
+// CHECK-NEXT:   %21 = load i32, ptr %y12, align 4
+// CHECK-NEXT:   %add13 = add nsw i32 %20, %21
+// CHECK-NEXT:   %22 = getelementptr inbounds nuw %class.anon, ptr %this1, i32 0, i32 1
+// CHECK-NEXT:   %23 = load ptr, ptr %22, align 8
+// CHECK-NEXT:   %24 = load i32, ptr %23, align 4
+// CHECK-NEXT:   %add14 = add nsw i32 %24, %add13
+// CHECK-NEXT:   store i32 %add14, ptr %23, align 4
+// CHECK-NEXT:   br label %expand.end15
+// CHECK: expand.end15:
+// CHECK-NEXT:   ret void
+
+
+// CHECK-LABEL: define {{.*}} void @_ZZ20unexpanded_pack_goodIJ1ES0_EEiDpT_ENKUlvE_clEv(ptr {{.*}} %this)
+// CHECK: entry:
+// CHECK-NEXT:   %this.addr = alloca ptr, align 8
+// CHECK-NEXT:   %0 = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %x3 = alloca i32, align 4
+// CHECK-NEXT:   %e = alloca %struct.E, align 4
+// CHECK-NEXT:   %e10 = alloca %struct.E, align 4
+// CHECK-NEXT:   store ptr %this, ptr %this.addr, align 8
+// CHECK-NEXT:   %this1 = load ptr, ptr %this.addr, align 8
+// CHECK-NEXT:   %1 = getelementptr inbounds nuw %class.anon.0, ptr %this1, i32 0, i32 0
+// CHECK-NEXT:   %2 = load ptr, ptr %1, align 8
+// CHECK-NEXT:   store ptr %2, ptr %0, align 8
+// CHECK-NEXT:   %3 = load ptr, ptr %0, align 8
+// CHECK-NEXT:   %x2 = getelementptr inbounds nuw %struct.E, ptr %3, i32 0, i32 0
+// CHECK-NEXT:   %4 = load i32, ptr %x2, align 4
+// CHECK-NEXT:   store i32 %4, ptr %x, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %6 = getelementptr inbounds nuw %class.anon.0, ptr %this1, i32 0, i32 1
+// CHECK-NEXT:   %7 = load ptr, ptr %6, align 8
+// CHECK-NEXT:   %8 = load i32, ptr %7, align 4
+// CHECK-NEXT:   %add = add nsw i32 %8, %5
+// CHECK-NEXT:   store i32 %add, ptr %7, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   %9 = load ptr, ptr %0, align 8
+// CHECK-NEXT:   %y = getelementptr inbounds nuw %struct.E, ptr %9, i32 0, i32 1
+// CHECK-NEXT:   %10 = load i32, ptr %y, align 4
+// CHECK-NEXT:   store i32 %10, ptr %x3, align 4
+// CHECK-NEXT:   %11 = load i32, ptr %x3, align 4
+// CHECK-NEXT:   %12 = getelementptr inbounds nuw %class.anon.0, ptr %this1, i32 0, i32 1
+// CHECK-NEXT:   %13 = load ptr, ptr %12, align 8
+// CHECK-NEXT:   %14 = load i32, ptr %13, align 4
+// CHECK-NEXT:   %add4 = add nsw i32 %14, %11
+// CHECK-NEXT:   store i32 %add4, ptr %13, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   call void @_ZN1EC1Eii(ptr {{.*}} %e, i32 {{.*}} 5, i32 {{.*}} 6)
+// CHECK-NEXT:   %x5 = getelementptr inbounds nuw %struct.E, ptr %e, i32 0, i32 0
+// CHECK-NEXT:   %15 = load i32, ptr %x5, align 4
+// CHECK-NEXT:   %y6 = getelementptr inbounds nuw %struct.E, ptr %e, i32 0, i32 1
+// CHECK-NEXT:   %16 = load i32, ptr %y6, align 4
+// CHECK-NEXT:   %add7 = add nsw i32 %15, %16
+// CHECK-NEXT:   %17 = getelementptr inbounds nuw %class.anon.0, ptr %this1, i32 0, i32 1
+// CHECK-NEXT:   %18 = load ptr, ptr %17, align 8
+// CHECK-NEXT:   %19 = load i32, ptr %18, align 4
+// CHECK-NEXT:   %add8 = add nsw i32 %19, %add7
+// CHECK-NEXT:   store i32 %add8, ptr %18, align 4
+// CHECK-NEXT:   br label %expand.next9
+// CHECK: expand.next9:
+// CHECK-NEXT:   call void @_ZN1EC1Eii(ptr {{.*}} %e10, i32 {{.*}} 7, i32 {{.*}} 8)
+// CHECK-NEXT:   %x11 = getelementptr inbounds nuw %struct.E, ptr %e10, i32 0, i32 0
+// CHECK-NEXT:   %20 = load i32, ptr %x11, align 4
+// CHECK-NEXT:   %y12 = getelementptr inbounds nuw %struct.E, ptr %e10, i32 0, i32 1
+// CHECK-NEXT:   %21 = load i32, ptr %y12, align 4
+// CHECK-NEXT:   %add13 = add nsw i32 %20, %21
+// CHECK-NEXT:   %22 = getelementptr inbounds nuw %class.anon.0, ptr %this1, i32 0, i32 1
+// CHECK-NEXT:   %23 = load ptr, ptr %22, align 8
+// CHECK-NEXT:   %24 = load i32, ptr %23, align 4
+// CHECK-NEXT:   %add14 = add nsw i32 %24, %add13
+// CHECK-NEXT:   store i32 %add14, ptr %23, align 4
+// CHECK-NEXT:   br label %expand.end15
+// CHECK: expand.end15:
+// CHECK-NEXT:   ret void
diff --git a/clang/test/CodeGenCXX/cxx2c-iterating-expansion-stmt.cpp b/clang/test/CodeGenCXX/cxx2c-iterating-expansion-stmt.cpp
new file mode 100644
index 0000000000000..12c8328f41be0
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx2c-iterating-expansion-stmt.cpp
@@ -0,0 +1,551 @@
+// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// Iterating expansion statements are currently not supported.
+// XFAIL: *
+
+template <typename T, __SIZE_TYPE__ size>
+struct Array {
+  T data[size]{};
+  constexpr const T* begin() const { return data; }
+  constexpr const T* end() const { return data + size; }
+};
+
+int f1() {
+  static constexpr Array<int, 3> integers{1, 2, 3};
+  int sum = 0;
+  template for (auto x : integers) sum += x;
+  return sum;
+}
+
+int f2() {
+  static constexpr Array<int, 3> integers{1, 2, 3};
+  int sum = 0;
+  template for (constexpr auto x : integers) sum += x;
+  return sum;
+}
+
+int f3() {
+  static constexpr Array<int, 0> integers{};
+  int sum = 0;
+  template for (constexpr auto x : integers) {
+    static_assert(false, "not expanded");
+    sum += x;
+  }
+  return sum;
+}
+
+int f4() {
+  static constexpr Array<int, 2> a{1, 2};
+  static constexpr Array<int, 2> b{3, 4};
+  int sum = 0;
+
+  template for (auto x : a)
+    template for (auto y : b)
+      sum += x + y;
+
+  template for (constexpr auto x : a)
+    template for (constexpr auto y : b)
+      sum += x + y;
+
+  return sum;
+}
+
+struct Private {
+  static constexpr Array<int, 3> integers{1, 2, 3};
+  friend constexpr int friend_func();
+
+private:
+  constexpr const int* begin() const { return integers.begin(); }
+  constexpr const int* end() const { return integers.end(); }
+
+public:
+  static int member_func();
+};
+
+int Private::member_func() {
+  int sum = 0;
+  static constexpr Private p1;
+  template for (auto x : p1) sum += x;
+  return sum;
+}
+
+struct CustomIterator {
+  struct iterator {
+    int n;
+
+    constexpr iterator operator+(int m) const {
+      return {n + m};
+    }
+
+    constexpr void operator++() { ++n; }
+
+    constexpr int operator*() const {
+      return n;
+    }
+
+    friend constexpr bool operator!=(iterator a, iterator b) {
+      return a.n != b.n;
+    }
+
+    friend constexpr int operator-(iterator a, iterator b) {
+      return a.n - b.n;
+    }
+  };
+
+   constexpr iterator begin() const { return iterator(1); }
+   constexpr iterator end() const { return iterator(5); }
+};
+
+int custom_iterator() {
+  static constexpr CustomIterator c;
+  int sum = 0;
+  template for (auto x : c) sum += x;
+  template for (constexpr auto x : c) sum += x;
+  return sum;
+}
+
+// CHECK: @_ZZ2f1vE8integers = internal constant %struct.Array { [3 x i32] [i32 1, i32 2, i32 3] }, align 4
+// CHECK: @_ZZ2f2vE8integers = internal constant %struct.Array { [3 x i32] [i32 1, i32 2, i32 3] }, align 4
+// CHECK: @_ZZ2f3vE8integers = internal constant %struct.Array.0 zeroinitializer, align 4
+// CHECK: @_ZZ2f4vE1a = internal constant %struct.Array.1 { [2 x i32] [i32 1, i32 2] }, align 4
+// CHECK: @_ZZ2f4vE1b = internal constant %struct.Array.1 { [2 x i32] [i32 3, i32 4] }, align 4
+// CHECK: @_ZZN7Private11member_funcEvE2p1 = internal constant %struct.Private zeroinitializer, align 1
+// CHECK: @_ZZ15custom_iteratorvE1c = internal constant %struct.CustomIterator zeroinitializer, align 1
+// CHECK: @__const._Z15custom_iteratorv.__begin1 = private {{.*}} constant %"struct.CustomIterator::iterator" { i32 1 }, align 4
+// CHECK: @__const._Z15custom_iteratorv.__begin1.1 = private {{.*}} constant %"struct.CustomIterator::iterator" { i32 1 }, align 4
+// CHECK: @__const._Z15custom_iteratorv.__iter1 = private {{.*}} constant %"struct.CustomIterator::iterator" { i32 1 }, align 4
+// CHECK: @__const._Z15custom_iteratorv.__iter1.2 = private {{.*}} constant %"struct.CustomIterator::iterator" { i32 2 }, align 4
+// CHECK: @__const._Z15custom_iteratorv.__iter1.3 = private {{.*}} constant %"struct.CustomIterator::iterator" { i32 3 }, align 4
+// CHECK: @__const._Z15custom_iteratorv.__iter1.4 = private {{.*}} constant %"struct.CustomIterator::iterator" { i32 4 }, align 4
+// CHECK: @_ZN7Private8integersE = {{.*}} constant %struct.Array { [3 x i32] [i32 1, i32 2, i32 3] }, comdat, align 4
+
+// CHECK-LABEL: define {{.*}} i32 @_Z2f1v()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %__range1 = alloca ptr, align 8
+// CHECK-NEXT:   %__begin1 = alloca ptr, align 8
+// CHECK-NEXT:   %__iter1 = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %__iter11 = alloca ptr, align 8
+// CHECK-NEXT:   %x3 = alloca i32, align 4
+// CHECK-NEXT:   %__iter16 = alloca ptr, align 8
+// CHECK-NEXT:   %x8 = alloca i32, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store ptr @_ZZ2f1vE8integers, ptr %__range1, align 8
+// CHECK-NEXT:   %call = call {{.*}} ptr @_ZNK5ArrayIiLm3EE5beginEv(ptr {{.*}} @_ZZ2f1vE8integers)
+// CHECK-NEXT:   store ptr %call, ptr %__begin1, align 8
+// CHECK-NEXT:   %0 = load ptr, ptr %__begin1, align 8
+// CHECK-NEXT:   %add.ptr = getelementptr inbounds i32, ptr %0, i64 0
+// CHECK-NEXT:   store ptr %add.ptr, ptr %__iter1, align 8
+// CHECK-NEXT:   %1 = load ptr, ptr %__iter1, align 8
+// CHECK-NEXT:   %2 = load i32, ptr %1, align 4
+// CHECK-NEXT:   store i32 %2, ptr %x, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %4, %3
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   %5 = load ptr, ptr %__begin1, align 8
+// CHECK-NEXT:   %add.ptr2 = getelementptr inbounds i32, ptr %5, i64 1
+// CHECK-NEXT:   store ptr %add.ptr2, ptr %__iter11, align 8
+// CHECK-NEXT:   %6 = load ptr, ptr %__iter11, align 8
+// CHECK-NEXT:   %7 = load i32, ptr %6, align 4
+// CHECK-NEXT:   store i32 %7, ptr %x3, align 4
+// CHECK-NEXT:   %8 = load i32, ptr %x3, align 4
+// CHECK-NEXT:   %9 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add4 = add nsw i32 %9, %8
+// CHECK-NEXT:   store i32 %add4, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next5
+// CHECK: expand.next5:
+// CHECK-NEXT:   %10 = load ptr, ptr %__begin1, align 8
+// CHECK-NEXT:   %add.ptr7 = getelementptr inbounds i32, ptr %10, i64 2
+// CHECK-NEXT:   store ptr %add.ptr7, ptr %__iter16, align 8
+// CHECK-NEXT:   %11 = load ptr, ptr %__iter16, align 8
+// CHECK-NEXT:   %12 = load i32, ptr %11, align 4
+// CHECK-NEXT:   store i32 %12, ptr %x8, align 4
+// CHECK-NEXT:   %13 = load i32, ptr %x8, align 4
+// CHECK-NEXT:   %14 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add9 = add nsw i32 %14, %13
+// CHECK-NEXT:   store i32 %add9, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   %15 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %15
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z2f2v()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %__range1 = alloca ptr, align 8
+// CHECK-NEXT:   %__begin1 = alloca ptr, align 8
+// CHECK-NEXT:   %__iter1 = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %__iter11 = alloca ptr, align 8
+// CHECK-NEXT:   %x2 = alloca i32, align 4
+// CHECK-NEXT:   %__iter15 = alloca ptr, align 8
+// CHECK-NEXT:   %x6 = alloca i32, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store ptr @_ZZ2f2vE8integers, ptr %__range1, align 8
+// CHECK-NEXT:   store ptr @_ZZ2f2vE8integers, ptr %__begin1, align 8
+// CHECK-NEXT:   store ptr @_ZZ2f2vE8integers, ptr %__iter1, align 8
+// CHECK-NEXT:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %0, 1
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store ptr getelementptr (i8, ptr @_ZZ2f2vE8integers, i64 4), ptr %__iter11, align 8
+// CHECK-NEXT:   store i32 2, ptr %x2, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add3 = add nsw i32 %1, 2
+// CHECK-NEXT:   store i32 %add3, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next4
+// CHECK: expand.next4:
+// CHECK-NEXT:   store ptr getelementptr (i8, ptr @_ZZ2f2vE8integers, i64 8), ptr %__iter15, align 8
+// CHECK-NEXT:   store i32 3, ptr %x6, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add7 = add nsw i32 %2, 3
+// CHECK-NEXT:   store i32 %add7, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   %3 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %3
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z2f3v()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %__range1 = alloca ptr, align 8
+// CHECK-NEXT:   %__begin1 = alloca ptr, align 8
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store ptr @_ZZ2f3vE8integers, ptr %__range1, align 8
+// CHECK-NEXT:   store ptr @_ZZ2f3vE8integers, ptr %__begin1, align 8
+// CHECK-NEXT:   %0 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %0
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z2f4v()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %__range1 = alloca ptr, align 8
+// CHECK-NEXT:   %__begin1 = alloca ptr, align 8
+// CHECK-NEXT:   %__iter1 = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %__range2 = alloca ptr, align 8
+// CHECK-NEXT:   %__begin2 = alloca ptr, align 8
+// CHECK-NEXT:   %__iter2 = alloca ptr, align 8
+// CHECK-NEXT:   %y = alloca i32, align 4
+// CHECK-NEXT:   %__iter24 = alloca ptr, align 8
+// CHECK-NEXT:   %y6 = alloca i32, align 4
+// CHECK-NEXT:   %__iter110 = alloca ptr, align 8
+// CHECK-NEXT:   %x12 = alloca i32, align 4
+// CHECK-NEXT:   %__range213 = alloca ptr, align 8
+// CHECK-NEXT:   %__begin214 = alloca ptr, align 8
+// CHECK-NEXT:   %__iter216 = alloca ptr, align 8
+// CHECK-NEXT:   %y18 = alloca i32, align 4
+// CHECK-NEXT:   %__iter222 = alloca ptr, align 8
+// CHECK-NEXT:   %y24 = alloca i32, align 4
+// CHECK-NEXT:   %__range129 = alloca ptr, align 8
+// CHECK-NEXT:   %__begin130 = alloca ptr, align 8
+// CHECK-NEXT:   %__iter131 = alloca ptr, align 8
+// CHECK-NEXT:   %x32 = alloca i32, align 4
+// CHECK-NEXT:   %__range233 = alloca ptr, align 8
+// CHECK-NEXT:   %__begin234 = alloca ptr, align 8
+// CHECK-NEXT:   %__iter235 = alloca ptr, align 8
+// CHECK-NEXT:   %y36 = alloca i32, align 4
+// CHECK-NEXT:   %__iter239 = alloca ptr, align 8
+// CHECK-NEXT:   %y40 = alloca i32, align 4
+// CHECK-NEXT:   %__iter144 = alloca ptr, align 8
+// CHECK-NEXT:   %x45 = alloca i32, align 4
+// CHECK-NEXT:   %__range246 = alloca ptr, align 8
+// CHECK-NEXT:   %__begin247 = alloca ptr, align 8
+// CHECK-NEXT:   %__iter248 = alloca ptr, align 8
+// CHECK-NEXT:   %y49 = alloca i32, align 4
+// CHECK-NEXT:   %__iter252 = alloca ptr, align 8
+// CHECK-NEXT:   %y53 = alloca i32, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1a, ptr %__range1, align 8
+// CHECK-NEXT:   %call = call {{.*}} ptr @_ZNK5ArrayIiLm2EE5beginEv(ptr {{.*}} @_ZZ2f4vE1a)
+// CHECK-NEXT:   store ptr %call, ptr %__begin1, align 8
+// CHECK-NEXT:   %0 = load ptr, ptr %__begin1, align 8
+// CHECK-NEXT:   %add.ptr = getelementptr inbounds i32, ptr %0, i64 0
+// CHECK-NEXT:   store ptr %add.ptr, ptr %__iter1, align 8
+// CHECK-NEXT:   %1 = load ptr, ptr %__iter1, align 8
+// CHECK-NEXT:   %2 = load i32, ptr %1, align 4
+// CHECK-NEXT:   store i32 %2, ptr %x, align 4
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1b, ptr %__range2, align 8
+// CHECK-NEXT:   %call1 = call {{.*}} ptr @_ZNK5ArrayIiLm2EE5beginEv(ptr {{.*}} @_ZZ2f4vE1b)
+// CHECK-NEXT:   store ptr %call1, ptr %__begin2, align 8
+// CHECK-NEXT:   %3 = load ptr, ptr %__begin2, align 8
+// CHECK-NEXT:   %add.ptr2 = getelementptr inbounds i32, ptr %3, i64 0
+// CHECK-NEXT:   store ptr %add.ptr2, ptr %__iter2, align 8
+// CHECK-NEXT:   %4 = load ptr, ptr %__iter2, align 8
+// CHECK-NEXT:   %5 = load i32, ptr %4, align 4
+// CHECK-NEXT:   store i32 %5, ptr %y, align 4
+// CHECK-NEXT:   %6 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %y, align 4
+// CHECK-NEXT:   %add = add nsw i32 %6, %7
+// CHECK-NEXT:   %8 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add3 = add nsw i32 %8, %add
+// CHECK-NEXT:   store i32 %add3, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   %9 = load ptr, ptr %__begin2, align 8
+// CHECK-NEXT:   %add.ptr5 = getelementptr inbounds i32, ptr %9, i64 1
+// CHECK-NEXT:   store ptr %add.ptr5, ptr %__iter24, align 8
+// CHECK-NEXT:   %10 = load ptr, ptr %__iter24, align 8
+// CHECK-NEXT:   %11 = load i32, ptr %10, align 4
+// CHECK-NEXT:   store i32 %11, ptr %y6, align 4
+// CHECK-NEXT:   %12 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %13 = load i32, ptr %y6, align 4
+// CHECK-NEXT:   %add7 = add nsw i32 %12, %13
+// CHECK-NEXT:   %14 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add8 = add nsw i32 %14, %add7
+// CHECK-NEXT:   store i32 %add8, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   br label %expand.next9
+// CHECK: expand.next9:
+// CHECK-NEXT:   %15 = load ptr, ptr %__begin1, align 8
+// CHECK-NEXT:   %add.ptr11 = getelementptr inbounds i32, ptr %15, i64 1
+// CHECK-NEXT:   store ptr %add.ptr11, ptr %__iter110, align 8
+// CHECK-NEXT:   %16 = load ptr, ptr %__iter110, align 8
+// CHECK-NEXT:   %17 = load i32, ptr %16, align 4
+// CHECK-NEXT:   store i32 %17, ptr %x12, align 4
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1b, ptr %__range213, align 8
+// CHECK-NEXT:   %call15 = call {{.*}} ptr @_ZNK5ArrayIiLm2EE5beginEv(ptr {{.*}} @_ZZ2f4vE1b)
+// CHECK-NEXT:   store ptr %call15, ptr %__begin214, align 8
+// CHECK-NEXT:   %18 = load ptr, ptr %__begin214, align 8
+// CHECK-NEXT:   %add.ptr17 = getelementptr inbounds i32, ptr %18, i64 0
+// CHECK-NEXT:   store ptr %add.ptr17, ptr %__iter216, align 8
+// CHECK-NEXT:   %19 = load ptr, ptr %__iter216, align 8
+// CHECK-NEXT:   %20 = load i32, ptr %19, align 4
+// CHECK-NEXT:   store i32 %20, ptr %y18, align 4
+// CHECK-NEXT:   %21 = load i32, ptr %x12, align 4
+// CHECK-NEXT:   %22 = load i32, ptr %y18, align 4
+// CHECK-NEXT:   %add19 = add nsw i32 %21, %22
+// CHECK-NEXT:   %23 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add20 = add nsw i32 %23, %add19
+// CHECK-NEXT:   store i32 %add20, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next21
+// CHECK: expand.next21:
+// CHECK-NEXT:   %24 = load ptr, ptr %__begin214, align 8
+// CHECK-NEXT:   %add.ptr23 = getelementptr inbounds i32, ptr %24, i64 1
+// CHECK-NEXT:   store ptr %add.ptr23, ptr %__iter222, align 8
+// CHECK-NEXT:   %25 = load ptr, ptr %__iter222, align 8
+// CHECK-NEXT:   %26 = load i32, ptr %25, align 4
+// CHECK-NEXT:   store i32 %26, ptr %y24, align 4
+// CHECK-NEXT:   %27 = load i32, ptr %x12, align 4
+// CHECK-NEXT:   %28 = load i32, ptr %y24, align 4
+// CHECK-NEXT:   %add25 = add nsw i32 %27, %28
+// CHECK-NEXT:   %29 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add26 = add nsw i32 %29, %add25
+// CHECK-NEXT:   store i32 %add26, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end27
+// CHECK: expand.end27:
+// CHECK-NEXT:   br label %expand.end28
+// CHECK: expand.end28:
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1a, ptr %__range129, align 8
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1a, ptr %__begin130, align 8
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1a, ptr %__iter131, align 8
+// CHECK-NEXT:   store i32 1, ptr %x32, align 4
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1b, ptr %__range233, align 8
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1b, ptr %__begin234, align 8
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1b, ptr %__iter235, align 8
+// CHECK-NEXT:   store i32 3, ptr %y36, align 4
+// CHECK-NEXT:   %30 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add37 = add nsw i32 %30, 4
+// CHECK-NEXT:   store i32 %add37, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next38
+// CHECK: expand.next38:
+// CHECK-NEXT:   store ptr getelementptr (i8, ptr @_ZZ2f4vE1b, i64 4), ptr %__iter239, align 8
+// CHECK-NEXT:   store i32 4, ptr %y40, align 4
+// CHECK-NEXT:   %31 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add41 = add nsw i32 %31, 5
+// CHECK-NEXT:   store i32 %add41, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end42
+// CHECK: expand.end42:
+// CHECK-NEXT:   br label %expand.next43
+// CHECK: expand.next43:
+// CHECK-NEXT:   store ptr getelementptr (i8, ptr @_ZZ2f4vE1a, i64 4), ptr %__iter144, align 8
+// CHECK-NEXT:   store i32 2, ptr %x45, align 4
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1b, ptr %__range246, align 8
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1b, ptr %__begin247, align 8
+// CHECK-NEXT:   store ptr @_ZZ2f4vE1b, ptr %__iter248, align 8
+// CHECK-NEXT:   store i32 3, ptr %y49, align 4
+// CHECK-NEXT:   %32 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add50 = add nsw i32 %32, 5
+// CHECK-NEXT:   store i32 %add50, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next51
+// CHECK: expand.next51:
+// CHECK-NEXT:   store ptr getelementptr (i8, ptr @_ZZ2f4vE1b, i64 4), ptr %__iter252, align 8
+// CHECK-NEXT:   store i32 4, ptr %y53, align 4
+// CHECK-NEXT:   %33 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add54 = add nsw i32 %33, 6
+// CHECK-NEXT:   store i32 %add54, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end55
+// CHECK: expand.end55:
+// CHECK-NEXT:   br label %expand.end56
+// CHECK: expand.end56:
+// CHECK-NEXT:   %34 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %34
+
+
+// CHECK-LABEL: define {{.*}} i32 @_ZN7Private11member_funcEv()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %__range1 = alloca ptr, align 8
+// CHECK-NEXT:   %__begin1 = alloca ptr, align 8
+// CHECK-NEXT:   %__iter1 = alloca ptr, align 8
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK-NEXT:   %__iter11 = alloca ptr, align 8
+// CHECK-NEXT:   %x3 = alloca i32, align 4
+// CHECK-NEXT:   %__iter16 = alloca ptr, align 8
+// CHECK-NEXT:   %x8 = alloca i32, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store ptr @_ZZN7Private11member_funcEvE2p1, ptr %__range1, align 8
+// CHECK-NEXT:   %call = call {{.*}} ptr @_ZNK7Private5beginEv(ptr {{.*}} @_ZZN7Private11member_funcEvE2p1)
+// CHECK-NEXT:   store ptr %call, ptr %__begin1, align 8
+// CHECK-NEXT:   %0 = load ptr, ptr %__begin1, align 8
+// CHECK-NEXT:   %add.ptr = getelementptr inbounds i32, ptr %0, i64 0
+// CHECK-NEXT:   store ptr %add.ptr, ptr %__iter1, align 8
+// CHECK-NEXT:   %1 = load ptr, ptr %__iter1, align 8
+// CHECK-NEXT:   %2 = load i32, ptr %1, align 4
+// CHECK-NEXT:   store i32 %2, ptr %x, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %4, %3
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   %5 = load ptr, ptr %__begin1, align 8
+// CHECK-NEXT:   %add.ptr2 = getelementptr inbounds i32, ptr %5, i64 1
+// CHECK-NEXT:   store ptr %add.ptr2, ptr %__iter11, align 8
+// CHECK-NEXT:   %6 = load ptr, ptr %__iter11, align 8
+// CHECK-NEXT:   %7 = load i32, ptr %6, align 4
+// CHECK-NEXT:   store i32 %7, ptr %x3, align 4
+// CHECK-NEXT:   %8 = load i32, ptr %x3, align 4
+// CHECK-NEXT:   %9 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add4 = add nsw i32 %9, %8
+// CHECK-NEXT:   store i32 %add4, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next5
+// CHECK: expand.next5:
+// CHECK-NEXT:   %10 = load ptr, ptr %__begin1, align 8
+// CHECK-NEXT:   %add.ptr7 = getelementptr inbounds i32, ptr %10, i64 2
+// CHECK-NEXT:   store ptr %add.ptr7, ptr %__iter16, align 8
+// CHECK-NEXT:   %11 = load ptr, ptr %__iter16, align 8
+// CHECK-NEXT:   %12 = load i32, ptr %11, align 4
+// CHECK-NEXT:   store i32 %12, ptr %x8, align 4
+// CHECK-NEXT:   %13 = load i32, ptr %x8, align 4
+// CHECK-NEXT:   %14 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add9 = add nsw i32 %14, %13
+// CHECK-NEXT:   store i32 %add9, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   %15 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %15
+
+
+// CHECK-LABEL: define {{.*}} i32 @_Z15custom_iteratorv()
+// CHECK: entry:
+// CHECK-NEXT:   %sum = alloca i32, align 4
+// CHECK-NEXT:   %__range1 = alloca ptr, align 8
+// CHECK: %__begin1 = alloca %"struct.CustomIterator::iterator", align 4
+// CHECK: %__iter1 = alloca %"struct.CustomIterator::iterator", align 4
+// CHECK-NEXT:   %x = alloca i32, align 4
+// CHECK: %__iter12 = alloca %"struct.CustomIterator::iterator", align 4
+// CHECK-NEXT:   %x5 = alloca i32, align 4
+// CHECK: %__iter19 = alloca %"struct.CustomIterator::iterator", align 4
+// CHECK-NEXT:   %x12 = alloca i32, align 4
+// CHECK: %__iter116 = alloca %"struct.CustomIterator::iterator", align 4
+// CHECK-NEXT:   %x19 = alloca i32, align 4
+// CHECK-NEXT:   %__range122 = alloca ptr, align 8
+// CHECK: %__begin123 = alloca %"struct.CustomIterator::iterator", align 4
+// CHECK: %__iter124 = alloca %"struct.CustomIterator::iterator", align 4
+// CHECK-NEXT:   %x25 = alloca i32, align 4
+// CHECK: %__iter128 = alloca %"struct.CustomIterator::iterator", align 4
+// CHECK-NEXT:   %x29 = alloca i32, align 4
+// CHECK: %__iter132 = alloca %"struct.CustomIterator::iterator", align 4
+// CHECK-NEXT:   %x33 = alloca i32, align 4
+// CHECK: %__iter136 = alloca %"struct.CustomIterator::iterator", align 4
+// CHECK-NEXT:   %x37 = alloca i32, align 4
+// CHECK-NEXT:   store i32 0, ptr %sum, align 4
+// CHECK-NEXT:   store ptr @_ZZ15custom_iteratorvE1c, ptr %__range1, align 8
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %__begin1, ptr align 4 @__const._Z15custom_iteratorv.__begin1, i64 4, i1 false)
+// CHECK-NEXT:   %call = call i32 @_ZNK14CustomIterator8iteratorplEi(ptr {{.*}} %__begin1, i32 {{.*}} 0)
+// CHECK: %coerce.dive = getelementptr inbounds nuw %"struct.CustomIterator::iterator", ptr %__iter1, i32 0, i32 0
+// CHECK-NEXT:   store i32 %call, ptr %coerce.dive, align 4
+// CHECK-NEXT:   %call1 = call {{.*}} i32 @_ZNK14CustomIterator8iteratordeEv(ptr {{.*}} %__iter1)
+// CHECK-NEXT:   store i32 %call1, ptr %x, align 4
+// CHECK-NEXT:   %0 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %1 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %1, %0
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   %call3 = call i32 @_ZNK14CustomIterator8iteratorplEi(ptr {{.*}} %__begin1, i32 {{.*}} 1)
+// CHECK: %coerce.dive4 = getelementptr inbounds nuw %"struct.CustomIterator::iterator", ptr %__iter12, i32 0, i32 0
+// CHECK-NEXT:   store i32 %call3, ptr %coerce.dive4, align 4
+// CHECK-NEXT:   %call6 = call {{.*}} i32 @_ZNK14CustomIterator8iteratordeEv(ptr {{.*}} %__iter12)
+// CHECK-NEXT:   store i32 %call6, ptr %x5, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x5, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add7 = add nsw i32 %3, %2
+// CHECK-NEXT:   store i32 %add7, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next8
+// CHECK: expand.next8:
+// CHECK-NEXT:   %call10 = call i32 @_ZNK14CustomIterator8iteratorplEi(ptr {{.*}} %__begin1, i32 {{.*}} 2)
+// CHECK: %coerce.dive11 = getelementptr inbounds nuw %"struct.CustomIterator::iterator", ptr %__iter19, i32 0, i32 0
+// CHECK-NEXT:   store i32 %call10, ptr %coerce.dive11, align 4
+// CHECK-NEXT:   %call13 = call {{.*}} i32 @_ZNK14CustomIterator8iteratordeEv(ptr {{.*}} %__iter19)
+// CHECK-NEXT:   store i32 %call13, ptr %x12, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x12, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add14 = add nsw i32 %5, %4
+// CHECK-NEXT:   store i32 %add14, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next15
+// CHECK: expand.next15:
+// CHECK-NEXT:   %call17 = call i32 @_ZNK14CustomIterator8iteratorplEi(ptr {{.*}} %__begin1, i32 {{.*}} 3)
+// CHECK: %coerce.dive18 = getelementptr inbounds nuw %"struct.CustomIterator::iterator", ptr %__iter116, i32 0, i32 0
+// CHECK-NEXT:   store i32 %call17, ptr %coerce.dive18, align 4
+// CHECK-NEXT:   %call20 = call {{.*}} i32 @_ZNK14CustomIterator8iteratordeEv(ptr {{.*}} %__iter116)
+// CHECK-NEXT:   store i32 %call20, ptr %x19, align 4
+// CHECK-NEXT:   %6 = load i32, ptr %x19, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add21 = add nsw i32 %7, %6
+// CHECK-NEXT:   store i32 %add21, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end
+// CHECK: expand.end:
+// CHECK-NEXT:   store ptr @_ZZ15custom_iteratorvE1c, ptr %__range122, align 8
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %__begin123, ptr align 4 @__const._Z15custom_iteratorv.__begin1.1, i64 4, i1 false)
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %__iter124, ptr align 4 @__const._Z15custom_iteratorv.__iter1, i64 4, i1 false)
+// CHECK-NEXT:   store i32 1, ptr %x25, align 4
+// CHECK-NEXT:   %8 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add26 = add nsw i32 %8, 1
+// CHECK-NEXT:   store i32 %add26, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next27
+// CHECK: expand.next27:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %__iter128, ptr align 4 @__const._Z15custom_iteratorv.__iter1.2, i64 4, i1 false)
+// CHECK-NEXT:   store i32 2, ptr %x29, align 4
+// CHECK-NEXT:   %9 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add30 = add nsw i32 %9, 2
+// CHECK-NEXT:   store i32 %add30, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next31
+// CHECK: expand.next31:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %__iter132, ptr align 4 @__const._Z15custom_iteratorv.__iter1.3, i64 4, i1 false)
+// CHECK-NEXT:   store i32 3, ptr %x33, align 4
+// CHECK-NEXT:   %10 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add34 = add nsw i32 %10, 3
+// CHECK-NEXT:   store i32 %add34, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next35
+// CHECK: expand.next35:
+// CHECK-NEXT:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %__iter136, ptr align 4 @__const._Z15custom_iteratorv.__iter1.4, i64 4, i1 false)
+// CHECK-NEXT:   store i32 4, ptr %x37, align 4
+// CHECK-NEXT:   %11 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add38 = add nsw i32 %11, 4
+// CHECK-NEXT:   store i32 %add38, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end39
+// CHECK: expand.end39:
+// CHECK-NEXT:   %12 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %12
diff --git a/clang/test/SemaCXX/cxx2c-expansion-stmts-control-flow.cpp b/clang/test/SemaCXX/cxx2c-expansion-stmts-control-flow.cpp
new file mode 100644
index 0000000000000..51b383d63cdcb
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-expansion-stmts-control-flow.cpp
@@ -0,0 +1,135 @@
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fblocks -verify
+
+void g(int);
+
+void label() {
+  template for (auto x : {1, 2}) {
+    invalid1:; // expected-error {{labels are not allowed in expansion statements}}
+    invalid2:; // expected-error {{labels are not allowed in expansion statements}}
+    goto invalid1; // expected-error {{use of undeclared label 'invalid1'}}
+  }
+
+  template for (auto x : {1, 2}) {
+    (void) [] {
+      template for (auto x : {1, 2}) {
+        invalid3:; // expected-error {{labels are not allowed in expansion statements}}
+      }
+      ok:;
+    };
+
+    (void) ^{
+      template for (auto x : {1, 2}) {
+        invalid4:; // expected-error {{labels are not allowed in expansion statements}}
+      }
+      ok:;
+    };
+
+    struct X {
+      void f() {
+        ok:;
+      }
+    };
+  }
+
+  // GNU local labels are allowed.
+  template for (auto x : {1, 2}) {
+    __label__ a;
+    if (x == 1) goto a;
+    a:;
+    if (x == 1) goto a;
+  }
+
+  // Likewise, jumping *out* of an expansion statement is fine.
+  template for (auto x : {1, 2}) {
+    if (x == 1) goto lbl;
+    g(x);
+  }
+  lbl:;
+  template for (auto x : {1, 2}) {
+    if (x == 1) goto lbl;
+    g(x);
+  }
+
+  // Jumping into one is not possible, as local labels aren't visible
+  // outside the block that declares them, and non-local labels are invalid.
+  goto exp1; // expected-error {{use of undeclared label 'exp1'}}
+  goto exp3; // expected-error {{use of undeclared label 'exp3'}}
+  template for (auto x : {1, 2}) {
+    __label__ exp1, exp2;
+    exp1:;
+    exp2:;
+    exp3:; // expected-error {{labels are not allowed in expansion statements}}
+  }
+  goto exp2; // expected-error {{use of undeclared label 'exp2'}}
+
+  // Allow jumping from inside an expansion statement to a local label in
+  // one of its parents.
+  out1:;
+  template for (auto x : {1, 2}) {
+    __label__ x, y;
+    x:
+    goto out1;
+    goto out2;
+    template for (auto x : {3, 4}) {
+      goto x;
+      goto y;
+      goto out1;
+      goto out2;
+    }
+    y:
+  }
+  out2:;
+}
+
+
+void case_default(int i) {
+  switch (i) { // expected-note 3 {{switch statement is here}}
+    template for (auto x : {1, 2}) {
+      case 1:; // expected-error {{'case' belongs to 'switch' outside enclosing expansion statement}}
+        template for (auto x : {1, 2}) {
+          case 2:; // expected-error {{'case' belongs to 'switch' outside enclosing expansion statement}}
+        }
+      default: // expected-error {{'default' belongs to 'switch' outside enclosing expansion statement}}
+        switch (i) {  // expected-note {{switch statement is here}}
+          case 3:;
+          default:
+            template for (auto x : {1, 2}) {
+              case 4:; // expected-error {{'case' belongs to 'switch' outside enclosing expansion statement}}
+            }
+        }
+    }
+  }
+
+  template for (auto x : {1, 2}) {
+    switch (i) {
+      case 1:;
+      default:
+    }
+  }
+
+  // Ensure that we diagnose this even if the statements would be discarded.
+  switch (i) { // expected-note 2 {{switch statement is here}}
+    template for (auto x : {}) {
+      case 1:; // expected-error {{'case' belongs to 'switch' outside enclosing expansion statement}}
+      default:; // expected-error {{'default' belongs to 'switch' outside enclosing expansion statement}}
+    }
+  }
+}
+
+void case_constexpr(int i) {
+  template for (constexpr auto x : {1, 2, 3}) { // expected-note {{in instantiation of expansion statement requested here}}
+    switch (i) {
+      case x:; // expected-note {{previous case defined here}}
+      case 2:; // expected-error {{duplicate case value: 'x' and '2' both equal '2'}}
+      default:;
+    }
+  }
+
+  template for (constexpr auto x : {1, 2, 3}) {
+    switch (i) {
+      case x:;
+      case 4:;
+      default:;
+    }
+  }
+}
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 2c834b07f9a8f..9ff43c713d5b3 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -320,7 +320,13 @@ <h2 id="cxx26">C++2c implementation status</h2>
  <tr>
   <td>Expansion Statements</td>
   <td><a href="https://wg21.link/P1306">P1306R5</a></td>
-  <td class="none" align="center">No</td>
+  <td class="partial" align="center">
+    <details>
+      <summary>Clang 23 (Partial)</summary>
+      Iterating expansion statements currently cannot be expanded and will
+      result in a diagnostic, but other types of expansion statements work.
+    </details>
+  </td>
  </tr>
  <tr>
    <td>constexpr virtual inheritance</td>



More information about the llvm-branch-commits mailing list