[clang] 484b955 - [CIR] Implement throw within an aggregate expression (#203404)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 12 09:24:44 PDT 2026
Author: Andy Kaylor
Date: 2026-06-12T09:24:38-07:00
New Revision: 484b955581d976f97a47ef621c441e21c231aa23
URL: https://github.com/llvm/llvm-project/commit/484b955581d976f97a47ef621c441e21c231aa23
DIFF: https://github.com/llvm/llvm-project/commit/484b955581d976f97a47ef621c441e21c231aa23.diff
LOG: [CIR] Implement throw within an aggregate expression (#203404)
This implements CIR support for throwing an exception from within a
branch of a ternary expression that represents an aggregate prvalue. We
previously had support for throwing an exception within a ternary
aggregate expression, but when the expression uses a prvalue, it goes
through a different code path. The new implementation is just calling an
existing function from a different place. The bulk of what's being added
here is the testing.
Added:
Modified:
clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
clang/test/CIR/CodeGen/ternary-throw.cpp
Removed:
################################################################################
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 1b5654c4d0d59..44f481508cd7e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -627,9 +627,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
emitFinalDestCopy(e->getType(), tmpLValue);
}
- void VisitCXXThrowExpr(const CXXThrowExpr *e) {
- cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXThrowExpr");
- }
+ void VisitCXXThrowExpr(const CXXThrowExpr *e) { cgf.emitCXXThrowExpr(e); }
void VisitAtomicExpr(AtomicExpr *e) {
RValue result = cgf.emitAtomicExpr(e);
emitFinalDestCopy(e->getType(), result);
diff --git a/clang/test/CIR/CodeGen/ternary-throw.cpp b/clang/test/CIR/CodeGen/ternary-throw.cpp
index ef9f2aaea4c9f..fbafa9811d76e 100644
--- a/clang/test/CIR/CodeGen/ternary-throw.cpp
+++ b/clang/test/CIR/CodeGen/ternary-throw.cpp
@@ -521,3 +521,132 @@ const int test_agg_cond_const_false_throw_true(struct s6 a1, struct s6 a2) {
// OGCG: %[[F0_PTR:.*]] = getelementptr inbounds nuw %struct.s6, ptr %[[A1]], i32 0, i32 0
// OGCG: %[[F0_VAL:.*]] = load i32, ptr %[[F0_PTR]]
// OGCG: ret i32 %{{.*}}
+
+struct Agg {
+ int x;
+ int y;
+};
+
+void test_agg_throw_true(bool flag) {
+ Agg a = flag ? throw 0 : Agg{1, 2};
+}
+
+// CIR-LABEL: cir.func{{.*}} @_Z19test_agg_throw_trueb(
+// CIR: %[[FLAG:.*]] = cir.alloca "flag"
+// CIR: %[[A:.*]] = cir.alloca "a"
+// CIR: %[[FLAG_VAL:.*]] = cir.load{{.*}} %[[FLAG]] : !cir.ptr<!cir.bool>, !cir.bool
+// CIR: cir.if %[[FLAG_VAL]] {
+// CIR: %[[EXC:.*]] = cir.alloc.exception{{.*}} -> !cir.ptr<!s32i>
+// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: cir.store{{.*}} %[[ZERO]], %[[EXC]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.throw %[[EXC]] : !cir.ptr<!s32i>, @_ZTIi
+// CIR: cir.unreachable
+// CIR: } else {
+// CIR: %[[X:.*]] = cir.get_member %[[A]][0] {name = "x"} : !cir.ptr<!rec_Agg> -> !cir.ptr<!s32i>
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
+// CIR: cir.store{{.*}} %[[ONE]], %[[X]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[Y:.*]] = cir.get_member %[[A]][1] {name = "y"} : !cir.ptr<!rec_Agg> -> !cir.ptr<!s32i>
+// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
+// CIR: cir.store{{.*}} %[[TWO]], %[[Y]] : !s32i, !cir.ptr<!s32i>
+// CIR: }
+// CIR: cir.return
+
+// LLVM-LABEL: define{{.*}} void @_Z19test_agg_throw_trueb(
+// LLVM: %[[FLAG_ALLOCA:.*]] = alloca i8
+// LLVM: %[[A_ALLOCA:.*]] = alloca %struct.Agg
+// LLVM: %[[BOOL:.*]] = trunc i8 %{{.*}} to i1
+// LLVM: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]]
+// LLVM: [[TRUE_BB]]:
+// LLVM: %[[EXC:.*]] = call{{.*}} ptr @__cxa_allocate_exception
+// LLVM: store i32 0, ptr %[[EXC]]
+// LLVM: call void @__cxa_throw(ptr %[[EXC]], ptr @_ZTIi
+// LLVM: unreachable
+// LLVM: [[FALSE_BB]]:
+// LLVM: %[[X:.*]] = getelementptr inbounds nuw %struct.Agg, ptr %[[A_ALLOCA]], i32 0, i32 0
+// LLVM: store i32 1, ptr %[[X]]
+// LLVM: %[[Y:.*]] = getelementptr inbounds nuw %struct.Agg, ptr %[[A_ALLOCA]], i32 0, i32 1
+// LLVM: store i32 2, ptr %[[Y]]
+// LLVM: br label %[[END:.*]]
+// LLVM: [[END]]:
+// LLVM: ret void
+
+// OGCG-LABEL: define{{.*}} void @_Z19test_agg_throw_trueb(
+// OGCG: %[[A:.*]] = alloca %struct.Agg
+// OGCG: %[[FLAG:.*]] = load i8, ptr %{{.*}}
+// OGCG: %[[BOOL:.*]] = icmp ne i8 %[[FLAG]], 0
+// OGCG: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]]
+// OGCG: [[TRUE_BB]]:
+// OGCG: %[[EXC:.*]] = call{{.*}} ptr @__cxa_allocate_exception
+// OGCG: store i32 0, ptr %[[EXC]]
+// OGCG: call void @__cxa_throw(ptr %[[EXC]], ptr @_ZTIi
+// OGCG: unreachable
+// OGCG: [[FALSE_BB]]:
+// OGCG: %[[X:.*]] = getelementptr inbounds nuw %struct.Agg, ptr %[[A]], i32 0, i32 0
+// OGCG: store i32 1, ptr %[[X]]
+// OGCG: %[[Y:.*]] = getelementptr inbounds nuw %struct.Agg, ptr %[[A]], i32 0, i32 1
+// OGCG: store i32 2, ptr %[[Y]]
+// OGCG: br label %[[END:.*]]
+// OGCG: [[END]]:
+// OGCG: ret void
+
+void test_agg_throw_false(bool flag) {
+ Agg a = flag ? Agg{1, 2} : throw 0;
+}
+
+// CIR-LABEL: cir.func{{.*}} @_Z20test_agg_throw_falseb(
+// CIR: %[[FLAG:.*]] = cir.alloca "flag"
+// CIR: %[[A:.*]] = cir.alloca "a"
+// CIR: %[[FLAG_VAL:.*]] = cir.load{{.*}} %[[FLAG]] : !cir.ptr<!cir.bool>, !cir.bool
+// CIR: cir.if %[[FLAG_VAL]] {
+// CIR: %[[X:.*]] = cir.get_member %[[A]][0] {name = "x"} : !cir.ptr<!rec_Agg> -> !cir.ptr<!s32i>
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
+// CIR: cir.store{{.*}} %[[ONE]], %[[X]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[Y:.*]] = cir.get_member %[[A]][1] {name = "y"} : !cir.ptr<!rec_Agg> -> !cir.ptr<!s32i>
+// CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
+// CIR: cir.store{{.*}} %[[TWO]], %[[Y]] : !s32i, !cir.ptr<!s32i>
+// CIR: } else {
+// CIR: %[[EXC:.*]] = cir.alloc.exception{{.*}} -> !cir.ptr<!s32i>
+// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR: cir.store{{.*}} %[[ZERO]], %[[EXC]] : !s32i, !cir.ptr<!s32i>
+// CIR: cir.throw %[[EXC]] : !cir.ptr<!s32i>, @_ZTIi
+// CIR: cir.unreachable
+// CIR: }
+// CIR: cir.return
+
+// LLVM-LABEL: define{{.*}} void @_Z20test_agg_throw_falseb(
+// LLVM: %[[FLAG_ALLOCA:.*]] = alloca i8
+// LLVM: %[[A_ALLOCA:.*]] = alloca %struct.Agg
+// LLVM: %[[BOOL:.*]] = trunc i8 %{{.*}} to i1
+// LLVM: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]]
+// LLVM: [[TRUE_BB]]:
+// LLVM: %[[X:.*]] = getelementptr inbounds nuw %struct.Agg, ptr %[[A_ALLOCA]], i32 0, i32 0
+// LLVM: store i32 1, ptr %[[X]]
+// LLVM: %[[Y:.*]] = getelementptr inbounds nuw %struct.Agg, ptr %[[A_ALLOCA]], i32 0, i32 1
+// LLVM: store i32 2, ptr %[[Y]]
+// LLVM: br label %[[END:.*]]
+// LLVM: [[FALSE_BB]]:
+// LLVM: %[[EXC:.*]] = call{{.*}} ptr @__cxa_allocate_exception
+// LLVM: store i32 0, ptr %[[EXC]]
+// LLVM: call void @__cxa_throw(ptr %[[EXC]], ptr @_ZTIi
+// LLVM: unreachable
+// LLVM: [[END]]:
+// LLVM: ret void
+
+// OGCG-LABEL: define{{.*}} void @_Z20test_agg_throw_falseb(
+// OGCG: %[[A:.*]] = alloca %struct.Agg
+// OGCG: %[[FLAG:.*]] = load i8, ptr %{{.*}}
+// OGCG: %[[BOOL:.*]] = icmp ne i8 %[[FLAG]], 0
+// OGCG: br i1 %[[BOOL]], label %[[TRUE_BB:.*]], label %[[FALSE_BB:.*]]
+// OGCG: [[TRUE_BB]]:
+// OGCG: %[[X:.*]] = getelementptr inbounds nuw %struct.Agg, ptr %[[A]], i32 0, i32 0
+// OGCG: store i32 1, ptr %[[X]]
+// OGCG: %[[Y:.*]] = getelementptr inbounds nuw %struct.Agg, ptr %[[A]], i32 0, i32 1
+// OGCG: store i32 2, ptr %[[Y]]
+// OGCG: br label %[[END:.*]]
+// OGCG: [[FALSE_BB]]:
+// OGCG: %[[EXC:.*]] = call{{.*}} ptr @__cxa_allocate_exception
+// OGCG: store i32 0, ptr %[[EXC]]
+// OGCG: call void @__cxa_throw(ptr %[[EXC]], ptr @_ZTIi
+// OGCG: unreachable
+// OGCG: [[END]]:
+// OGCG: ret void
More information about the cfe-commits
mailing list