-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[Clang] [C++26] Expansion Statements (Part 8: Codegen) #169687
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Sirraide
wants to merge
2
commits into
users/Sirraide/expansion-stmts-7-constexpr-and-tests
Choose a base branch
from
users/Sirraide/expansion-stmts-8-codegen
base: users/Sirraide/expansion-stmts-7-constexpr-and-tests
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
[Clang] [C++26] Expansion Statements (Part 8: Codegen) #169687
Sirraide
wants to merge
2
commits into
users/Sirraide/expansion-stmts-7-constexpr-and-tests
from
users/Sirraide/expansion-stmts-8-codegen
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This was referenced Nov 26, 2025
Member
Author
This was referenced Nov 26, 2025
Member
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-codegen Author: None (Sirraide) ChangesThis 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:
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]
|
d3761e5 to
f1a507f
Compare
c93a279 to
89aec47
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
c++26
clang:codegen
IR generation bugs: mangling, exceptions, etc.
clang:frontend
Language frontend issues, e.g. anything involving "Sema"
clang
Clang issues not falling into any other category
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.

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