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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
