[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
Wed Nov 26 09:47:04 PST 2025
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
More information about the llvm-branch-commits
mailing list