[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 8: Codegen) (PR #169687)

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


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

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

---
 clang/lib/CodeGen/CGDecl.cpp                  |    8 +-
 clang/lib/CodeGen/CGStmt.cpp                  |   29 +-
 clang/lib/CodeGen/CodeGenFunction.h           |    3 +
 .../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 ++++++
 9 files changed, 3410 insertions(+), 3 deletions(-)
 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

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/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

>From 992424ffc8c9ae45a973fd3d0242aa2db175dae4 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Fri, 10 Jul 2026 22:01:05 +0200
Subject: [PATCH 2/2] [Clang] [C++26] Expansion Statements (Part 9: Control
 Flow) (#169688)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This disallows certain `switch`-`case` constructs and labels in
expansion statements.

GNU local labels are supported as an extension. My reasoning for
allowing this is that:
1. I’d argue it makes sense: the main reason for disallowing labels is
that you’d end up w/ more than one label w/ the same name in a single
function, and jumping to such a label from outside an expansion
statement becomes rather ill-defined as a result (which instantiation
does it jump to? what if the statement expands to nothing at all?). Both
of these issues don’t exist with local labels since they aren’t scoped
to the entire function and as a result can only be jumped to from inside
their respective instantiation.
2. Codegen and constant evaluation for this basically just works.
3. Disallowing this in the most straight-forward manner (e.g. by just
dropping the label) leads to rather poor QOI and a lot of diagnostics,
so even if we wanted to disallow local labels... we’d basically still
have to do everything I’m doing in this patch in addition to then
issuing a diagnostic for good QOI.
---
 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/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-expansion-stmts-control-flow.cpp    | 135 ++++++++++++++++++
 clang/www/cxx_status.html                     |   8 +-
 12 files changed, 404 insertions(+), 22 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/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/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/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