llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-codegen

Author: None (Sirraide)

<details>
<summary>Changes</summary>

This implements codegen for expansion statements and adds some codegen tests.

---

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


7 Files Affected:

- (modified) clang/lib/CodeGen/CGStmt.cpp (+46) 
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+3) 
- (added) clang/test/CodeGenCXX/cxx2c-destructuring-expansion-stmt.cpp (+471) 
- (added) clang/test/CodeGenCXX/cxx2c-enumerating-expansion-statements.cpp 
(+1518) 
- (added) clang/test/CodeGenCXX/cxx2c-expansion-stmts-control-flow.cpp (+429) 
- (added) clang/test/CodeGenCXX/cxx2c-expansion-stmts-templates.cpp (+208) 
- (added) clang/test/CodeGenCXX/cxx2c-iterating-expansion-stmt.cpp (+474) 


``````````diff
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 36be3295950b8..d6c6d159a5438 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -204,6 +204,14 @@ void CodeGenFunction::EmitStmt(const Stmt *S, 
ArrayRef<const Attr *> Attrs) {
   case Stmt::CXXForRangeStmtClass:
     EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S), Attrs);
     break;
+  case Stmt::CXXEnumeratingExpansionStmtPatternClass:
+  case Stmt::CXXIteratingExpansionStmtPatternClass:
+  case Stmt::CXXDestructuringExpansionStmtPatternClass:
+  case Stmt::CXXDependentExpansionStmtPatternClass:
+    llvm_unreachable("unexpanded expansion statements should not be emitted");
+  case Stmt::CXXExpansionStmtInstantiationClass:
+    EmitCXXExpansionStmtInstantiation(cast<CXXExpansionStmtInstantiation>(*S));
+    break;
   case Stmt::SEHTryStmtClass:
     EmitSEHTryStmt(cast<SEHTryStmt>(*S));
     break;
@@ -1556,6 +1564,44 @@ CodeGenFunction::EmitCXXForRangeStmt(const 
CXXForRangeStmt &S,
   }
 }
 
+void CodeGenFunction::EmitCXXExpansionStmtInstantiation(
+    const CXXExpansionStmtInstantiation &S) {
+  // FIXME: For reasons beyond my understanding, two scopes are required to 
emit
+  // the destructors of lifetime-extended temporaries in the right place, but
+  // only in some templates. There are some other issues with lifetime-extended
+  // temporaries currently 
(https://github.com/llvm/llvm-project/issues/165182);
+  // perhaps resolving those will allow us to remove the second scope here
+  // because there really ought to be a better way of doing this.
+  LexicalScope Scope(*this, S.getSourceRange());
+  LexicalScope Scope2(*this, S.getSourceRange());
+
+  for (const Stmt *DS : S.getSharedStmts())
+    EmitStmt(DS);
+
+  if (S.getInstantiations().empty() || !HaveInsertPoint())
+    return;
+
+  JumpDest ExpandExit = getJumpDestInCurrentScope("expand.end");
+  JumpDest ContinueDest;
+  for (auto [N, Inst] : enumerate(S.getInstantiations())) {
+    if (!HaveInsertPoint()) {
+      EmitBlock(ExpandExit.getBlock(), true);
+      return;
+    }
+
+    if (N == S.getInstantiations().size() - 1)
+      ContinueDest = ExpandExit;
+    else
+      ContinueDest = getJumpDestInCurrentScope("expand.next");
+
+    LexicalScope ExpansionScope(*this, S.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 8c4c1c8c2dc95..a895f187f3946 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3690,6 +3690,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..16d8c370a9d3f
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx2c-destructuring-expansion-stmt.cpp
@@ -0,0 +1,471 @@
+// 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>();
+}
+}
+
+// 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:   store i32 10, ptr %x, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %3, %2
+// 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:   %4 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add2 = add nsw i32 %4, 10
+// CHECK-NEXT:   store i32 %add2, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end3
+// CHECK: expand.end3:
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %5
+
+
+// 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:   store i32 1, ptr %x, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %3, %2
+// 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:   %4 = load i32, ptr %x1, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add2 = add nsw i32 %5, %4
+// 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:   %6 = load i32, ptr %x4, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add5 = add nsw i32 %7, %6
+// 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:   %8 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add7 = add nsw i32 %8, 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:   %9 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add10 = add nsw i32 %9, 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:   %10 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add13 = add nsw i32 %10, 3
+// CHECK-NEXT:   store i32 %add13, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end14
+// CHECK: expand.end14:
+// CHECK-NEXT:   %11 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %11
+
+
+// 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:   store i32 3, ptr %x, align 4
+// CHECK-NEXT:   %2 = load i32, ptr %x, align 4
+// CHECK-NEXT:   %3 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add = add nsw i32 %3, %2
+// CHECK-NEXT:   store i32 %add, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next
+// CHECK: expand.next:
+// CHECK-NEXT:   store i32 4, ptr %x1, align 4
+// CHECK-NEXT:   %4 = load i32, ptr %x1, align 4
+// CHECK-NEXT:   %5 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add2 = add nsw i32 %5, %4
+// CHECK-NEXT:   store i32 %add2, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.next3
+// CHECK: expand.next3:
+// CHECK-NEXT:   store i32 5, ptr %x4, align 4
+// CHECK-NEXT:   %6 = load i32, ptr %x4, align 4
+// CHECK-NEXT:   %7 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add5 = add nsw i32 %7, %6
+// 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:   %8 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add7 = add nsw i32 %8, 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:   %9 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add10 = add nsw i32 %9, 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:   %10 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   %add13 = add nsw i32 %10, 5
+// CHECK-NEXT:   store i32 %add13, ptr %sum, align 4
+// CHECK-NEXT:   br label %expand.end14
+// CHECK: expand.end14:
+// CHECK-NEXT:   %11 = load i32, ptr %sum, align 4
+// CHECK-NEXT:   ret i32 %11
+
+
+// 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
+// CHEC...
[truncated]

``````````

</details>


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

Reply via email to