diff --git a/releasenotes.md b/releasenotes.md index 60750a109..ea4e9b553 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -146,6 +146,8 @@ - Converting static "make_slice" to array failed to be handled #2866 - Narrowing a not expression was incorrectly handled #2867 - Vector shift by optional scalar failed #2868 +- Initializer did not correctly handle second rethrow #2870 +- Crash encountering panic in if-else style switch #2871 ### Stdlib changes - Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads. diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index cf2f68a7a..e572468f9 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1727,7 +1727,9 @@ static void llvm_emit_initialize_designated_element(GenContext *c, BEValue *ref, return; } BEValue val; + RETURN_ON_EMPTY_BLOCK(ref); llvm_emit_expr(c, &val, expr); + RETURN_ON_EMPTY_BLOCK(ref); llvm_store(c, ref, &val); return; } @@ -1884,6 +1886,7 @@ static inline void llvm_emit_initialize_reference_designated(GenContext *c, BEVa { BEValue splat_value; llvm_emit_expr(c, &splat_value, splat); + RETURN_ON_EMPTY_BLOCK(ref); llvm_store(c, ref, &splat_value); } else @@ -1897,6 +1900,7 @@ static inline void llvm_emit_initialize_reference_designated(GenContext *c, BEVa DesignatorElement **last_element = designator->designator_expr.path + vec_size(designator->designator_expr.path) - 1; llvm_emit_initialize_designated_element(c, ref, 0, designator->designator_expr.path, last_element, designator->designator_expr.value, NULL); + RETURN_ON_EMPTY_BLOCK(ref); } } @@ -4622,9 +4626,11 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr) // Generate condition and conditional branch Expr *cond = exprptr(expr->ternary_expr.cond); - llvm_emit_expr(c, value, cond); - llvm_value_rvalue(c, value); - RETURN_ON_EMPTY_BLOCK(value); + if (!llvm_emit_rvalue_in_block(c, value, cond)) + { + llvm_value_set_empty(value); + return; + } Expr *else_expr = exprptr(expr->ternary_expr.else_expr); Expr *then_expr = exprptr(expr->ternary_expr.then_expr); @@ -5877,9 +5883,7 @@ INLINE void llvm_emit_varargs_expr(GenContext *c, BEValue *value_ref, Expr **var BEValue array_ref = llvm_emit_alloca_b(c, array, varargslots_name); FOREACH_IDX(foreach_index, Expr *, val, varargs) { - llvm_emit_expr(c, &inner_temp, val); - RETURN_ON_EMPTY_BLOCK(value_ref); - llvm_value_fold_optional(c, &inner_temp); + if (!llvm_emit_folded_in_block(c, &inner_temp, val)) RETURN_EMPTY_BLOCK(value_ref); BEValue slot = llvm_emit_array_gep(c, &array_ref, foreach_index); llvm_store(c, &slot, &inner_temp); } @@ -6001,9 +6005,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr Expr *arg = args[i]; if (arg) { - llvm_emit_expr(c, value_ref, arg); - llvm_value_fold_optional(c, value_ref); - RETURN_ON_EMPTY_BLOCK(result_value); + if (!llvm_emit_folded_in_block(c, value_ref, arg)) RETURN_EMPTY_BLOCK(result_value); continue; } Decl *decl = sig->params[i]; @@ -6029,9 +6031,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr FOREACH_IDX(i, Expr *, vararg, varargs) { BEValue *value_ref = &values[arg_count + i]; - llvm_emit_expr(c, value_ref, vararg); - llvm_value_fold_optional(c, value_ref); - RETURN_ON_EMPTY_BLOCK(result_value); + if (!llvm_emit_folded_in_block(c, value_ref, vararg)) RETURN_EMPTY_BLOCK(result_value); } } @@ -6777,9 +6777,7 @@ static inline void llvm_emit_type_from_any(GenContext *c, BEValue *be_value) static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Expr *expr) { Expr *inner = exprptr(expr->builtin_access_expr.inner); - llvm_emit_expr(c, be_value, inner); - llvm_value_fold_optional(c, be_value); - RETURN_ON_EMPTY_BLOCK(be_value); + if (!llvm_emit_folded_in_block(c, be_value, inner)) RETURN_EMPTY_BLOCK(be_value); switch (expr->builtin_access_expr.kind) { case ACCESS_FAULTNAME: @@ -7028,22 +7026,16 @@ static void llvm_emit_ptr_access(GenContext *c, BEValue *value, Expr *expr) static void llvm_emit_make_any(GenContext *c, BEValue *value, Expr *expr) { - - llvm_emit_expr(c, value, expr->make_any_expr.inner); - llvm_value_rvalue(c, value); - RETURN_ON_EMPTY_BLOCK(value); + if (!llvm_emit_rvalue_in_block(c, value, expr->make_any_expr.inner)) RETURN_EMPTY_BLOCK(value); BEValue typeid_val; Expr *typeid = expr->make_any_expr.typeid; - llvm_emit_expr(c, &typeid_val, typeid); - llvm_value_rvalue(c, &typeid_val); - RETURN_ON_EMPTY_BLOCK(value); + if (!llvm_emit_rvalue_in_block(c, &typeid_val, typeid)) RETURN_EMPTY_BLOCK(value); llvm_value_aggregate_two(c, value, expr->type, value->value, typeid_val.value); } static void llvm_emit_ext_trunc(GenContext *c, BEValue *value, Expr *expr) { - llvm_emit_expr(c, value, expr->ext_trunc_expr.inner); - llvm_value_rvalue(c, value); + if (!llvm_emit_rvalue_in_block(c, value, expr->ext_trunc_expr.inner)) RETURN_EMPTY_BLOCK(value); Type *to_type = type_lowering(expr->type); LLVMTypeRef to = llvm_get_type(c, to_type); LLVMValueRef val; @@ -7131,9 +7123,7 @@ static inline void llvm_emit_vector_to_array(GenContext *c, BEValue *value, Expr void llvm_emit_slice_to_vec_array(GenContext *c, BEValue *value, Expr *expr) { - llvm_emit_expr(c, value, expr->inner_expr); - RETURN_ON_EMPTY_BLOCK(value); - llvm_value_rvalue(c, value); + if (!llvm_emit_rvalue_in_block(c, value, expr->inner_expr)) RETURN_EMPTY_BLOCK(value); BEValue pointer; Type *base = value->type->array.base; AlignSize element_alignment = type_abi_alignment(base); @@ -7164,6 +7154,36 @@ static inline void llvm_emit_make_slice(GenContext *c, BEValue *value, Expr *exp llvm_value_aggregate_two(c, value, expr->type, pointer, llvm_const_int(c, type_usz, size)); } +bool llvm_emit_folded_in_block(GenContext *c, BEValue *value, Expr *expr) +{ + if (llvm_is_global_eval(c)) + { + llvm_emit_expr(c, value, expr); + llvm_value_fold_optional(c, value); + return true; + } + llvm_emit_expr(c, value, expr); + if (!c->current_block) return false; + llvm_value_fold_optional(c, value); + if (!c->current_block) return false; + return true; +} + +bool llvm_emit_rvalue_in_block(GenContext *c, BEValue *value, Expr *expr) +{ + if (llvm_is_global_eval(c)) + { + llvm_emit_expr(c, value, expr); + llvm_value_rvalue(c, value); + return true; + } + llvm_emit_expr(c, value, expr); + if (!c->current_block) return false; + llvm_value_rvalue(c, value); + if (!c->current_block) return false; + return true; +} + void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) { EMIT_EXPR_LOC(c, expr); diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 83e6ff1fd..2654e6a0b 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -529,6 +529,8 @@ LLVMValueRef llvm_get_selector(GenContext *c, const char *name); // -- C3 Lowering -- void llvm_emit_expr_global_value(GenContext *c, BEValue *value, Expr *expr); void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr); +bool llvm_emit_rvalue_in_block(GenContext *c, BEValue *value, Expr *expr); +bool llvm_emit_folded_in_block(GenContext *c, BEValue *value, Expr *expr); LLVMValueRef llvm_emit_expr_to_rvalue(GenContext *c, Expr *expr); LLVMValueRef llvm_emit_exprid_to_rvalue(GenContext *c, ExprId expr_id); void llvm_emit_ignored_expr(GenContext *c, Expr *expr); @@ -596,6 +598,7 @@ void llvm_emit_debug_local_var(GenContext *c, Decl *var); #define POP_DEFER_ERROR() c->defer_error_var = def_err__ #define RETURN_ON_EMPTY_BLOCK(value__) do { if (!llvm_is_global_eval(c) && !c->current_block) { llvm_value_set_empty(value__); return; }} while(0) #define RETURN_ON_EMPTY_BLOCK_VOID() do { if (!llvm_is_global_eval(c) && !c->current_block) { return; }} while(0) +#define RETURN_EMPTY_BLOCK(value__) do { llvm_value_set_empty(value__); return; } while(0) LLVMAtomicOrdering llvm_atomic_ordering(Atomicity atomicity); diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index ec20f323b..97c973034 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -699,16 +699,14 @@ static void llvm_emit_switch_body_if_chain(GenContext *c, if (case_stmt == default_case) continue; BEValue be_value; Expr *expr = exprptr(case_stmt->case_stmt.expr); - llvm_emit_expr(c, &be_value, expr); - llvm_value_rvalue(c, &be_value); + if (!llvm_emit_rvalue_in_block(c, &be_value, expr)) goto DONE; BEValue equals; Expr *to_expr = exprptrzero(case_stmt->case_stmt.to_expr); if (to_expr) { ASSERT(!is_type_switch); BEValue to_value; - llvm_emit_expr(c, &to_value, to_expr); - llvm_value_rvalue(c, &to_value); + if (!llvm_emit_rvalue_in_block(c, &to_value, to_expr)) goto DONE; BEValue le; llvm_emit_comp(c, &le, &be_value, switch_value, BINARYOP_LE); BEValue ge; @@ -748,6 +746,7 @@ static void llvm_emit_switch_body_if_chain(GenContext *c, { llvm_emit_br(c, exit_block); } +DONE: llvm_emit_block(c, exit_block); } diff --git a/test/test_suite/expressions/optional_in_init_2.c3t b/test/test_suite/expressions/optional_in_init_2.c3t new file mode 100644 index 000000000..f5b86b01d --- /dev/null +++ b/test/test_suite/expressions/optional_in_init_2.c3t @@ -0,0 +1,73 @@ +module abc_faults; +module abc ; +import std::io, abc_faults, std::collections::list; +struct TextTemplate +{ + Allocator allocator; + String template; +} +fn void? TextTemplate.init(&self, String , String tag_start = "", String tag_end = "", Allocator using ) +{ + *self = { .allocator = io::EOF~!, .template = io::EOF~!, }; +} +module text_test; +import abc; +alias FooTmpl = TextTemplate{Foo}; +alias BarTmpl = TextTemplate{Bar}; +struct Foo +{ + BarTmpl bar; +} +struct Bar +{ + String bar; +} +fn void main() +{ + String foo_tmpl = ""; + FooTmpl ft; + ft.init(foo_tmpl, using: tmem)!!; +} + +/* #expect: abc.ll + +define weak i64 @"abc.TextTemplate$text_test.Foo$.init"(ptr %0, [2 x i64] %1, [2 x i64] %2, [2 x i64] %3, [2 x i64] %4) #0 { +entry: + %.anon = alloca %"char[]", align 8 + %tag_start = alloca %"char[]", align 8 + %tag_end = alloca %"char[]", align 8 + %using = alloca %any, align 8 + %.assign_list = alloca %"TextTemplate{Foo}", align 8 + %error_var = alloca i64, align 8 + store [2 x i64] %1, ptr %.anon, align 8 + store [2 x i64] %2, ptr %tag_start, align 8 + store [2 x i64] %3, ptr %tag_end, align 8 + store [2 x i64] %4, ptr %using, align 8 + call void @llvm.memset.p0.i64(ptr align 8 %.assign_list, i8 0, i64 32, i1 false) + store i64 ptrtoint (ptr @std.io.EOF to i64), ptr %error_var, align 8 + br label %guard_block + +guard_block: ; preds = %entry + %5 = load i64, ptr %error_var, align 8 + ret i64 %5 +} +define weak i64 @"abc.TextTemplate$text_test.Bar$.init"(ptr %0, [2 x i64] %1, [2 x i64] %2, [2 x i64] %3, [2 x i64] %4) #0 { +entry: + %.anon = alloca %"char[]", align 8 + %tag_start = alloca %"char[]", align 8 + %tag_end = alloca %"char[]", align 8 + %using = alloca %any, align 8 + %.assign_list = alloca %"TextTemplate{Bar}", align 8 + %error_var = alloca i64, align 8 + store [2 x i64] %1, ptr %.anon, align 8 + store [2 x i64] %2, ptr %tag_start, align 8 + store [2 x i64] %3, ptr %tag_end, align 8 + store [2 x i64] %4, ptr %using, align 8 + call void @llvm.memset.p0.i64(ptr align 8 %.assign_list, i8 0, i64 32, i1 false) + store i64 ptrtoint (ptr @std.io.EOF to i64), ptr %error_var, align 8 + br label %guard_block + +guard_block: ; preds = %entry + %5 = load i64, ptr %error_var, align 8 + ret i64 %5 +} diff --git a/test/test_suite/expressions/optional_panic_in_switch.c3t b/test/test_suite/expressions/optional_panic_in_switch.c3t new file mode 100644 index 000000000..aba20555e --- /dev/null +++ b/test/test_suite/expressions/optional_panic_in_switch.c3t @@ -0,0 +1,20 @@ +faultdef BAD_STUFF, WORSE_STUFF, THE_WORST_STUFF; +fn int exitcode(fault ) +{ + switch + { + case THE_WORST_STUFF~!!: + default: return 70; + } +} +fn void? canFail() +{ +} +fn int main() +{ + if (catch err = canFail()) + { + return exitcode(err); + } + return 0; +}