- Initializer did not correctly handle second rethrow #2870

- Crash encountering panic in if-else style switch #2871
This commit is contained in:
Christoffer Lerno
2026-01-28 22:56:59 +01:00
parent 362d5680e4
commit 414c0c9438
6 changed files with 148 additions and 31 deletions

View File

@@ -146,6 +146,8 @@
- Converting static "make_slice" to array failed to be handled #2866 - Converting static "make_slice" to array failed to be handled #2866
- Narrowing a not expression was incorrectly handled #2867 - Narrowing a not expression was incorrectly handled #2867
- Vector shift by optional scalar failed #2868 - 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 ### Stdlib changes
- Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads. - Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads.

View File

@@ -1727,7 +1727,9 @@ static void llvm_emit_initialize_designated_element(GenContext *c, BEValue *ref,
return; return;
} }
BEValue val; BEValue val;
RETURN_ON_EMPTY_BLOCK(ref);
llvm_emit_expr(c, &val, expr); llvm_emit_expr(c, &val, expr);
RETURN_ON_EMPTY_BLOCK(ref);
llvm_store(c, ref, &val); llvm_store(c, ref, &val);
return; return;
} }
@@ -1884,6 +1886,7 @@ static inline void llvm_emit_initialize_reference_designated(GenContext *c, BEVa
{ {
BEValue splat_value; BEValue splat_value;
llvm_emit_expr(c, &splat_value, splat); llvm_emit_expr(c, &splat_value, splat);
RETURN_ON_EMPTY_BLOCK(ref);
llvm_store(c, ref, &splat_value); llvm_store(c, ref, &splat_value);
} }
else 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; 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, llvm_emit_initialize_designated_element(c, ref, 0, designator->designator_expr.path, last_element,
designator->designator_expr.value, NULL); 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 // Generate condition and conditional branch
Expr *cond = exprptr(expr->ternary_expr.cond); Expr *cond = exprptr(expr->ternary_expr.cond);
llvm_emit_expr(c, value, cond); if (!llvm_emit_rvalue_in_block(c, value, cond))
llvm_value_rvalue(c, value); {
RETURN_ON_EMPTY_BLOCK(value); llvm_value_set_empty(value);
return;
}
Expr *else_expr = exprptr(expr->ternary_expr.else_expr); Expr *else_expr = exprptr(expr->ternary_expr.else_expr);
Expr *then_expr = exprptr(expr->ternary_expr.then_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); BEValue array_ref = llvm_emit_alloca_b(c, array, varargslots_name);
FOREACH_IDX(foreach_index, Expr *, val, varargs) FOREACH_IDX(foreach_index, Expr *, val, varargs)
{ {
llvm_emit_expr(c, &inner_temp, val); if (!llvm_emit_folded_in_block(c, &inner_temp, val)) RETURN_EMPTY_BLOCK(value_ref);
RETURN_ON_EMPTY_BLOCK(value_ref);
llvm_value_fold_optional(c, &inner_temp);
BEValue slot = llvm_emit_array_gep(c, &array_ref, foreach_index); BEValue slot = llvm_emit_array_gep(c, &array_ref, foreach_index);
llvm_store(c, &slot, &inner_temp); 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]; Expr *arg = args[i];
if (arg) if (arg)
{ {
llvm_emit_expr(c, value_ref, arg); if (!llvm_emit_folded_in_block(c, value_ref, arg)) RETURN_EMPTY_BLOCK(result_value);
llvm_value_fold_optional(c, value_ref);
RETURN_ON_EMPTY_BLOCK(result_value);
continue; continue;
} }
Decl *decl = sig->params[i]; 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) FOREACH_IDX(i, Expr *, vararg, varargs)
{ {
BEValue *value_ref = &values[arg_count + i]; BEValue *value_ref = &values[arg_count + i];
llvm_emit_expr(c, value_ref, vararg); if (!llvm_emit_folded_in_block(c, value_ref, vararg)) RETURN_EMPTY_BLOCK(result_value);
llvm_value_fold_optional(c, value_ref);
RETURN_ON_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) static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Expr *expr)
{ {
Expr *inner = exprptr(expr->builtin_access_expr.inner); Expr *inner = exprptr(expr->builtin_access_expr.inner);
llvm_emit_expr(c, be_value, inner); if (!llvm_emit_folded_in_block(c, be_value, inner)) RETURN_EMPTY_BLOCK(be_value);
llvm_value_fold_optional(c, be_value);
RETURN_ON_EMPTY_BLOCK(be_value);
switch (expr->builtin_access_expr.kind) switch (expr->builtin_access_expr.kind)
{ {
case ACCESS_FAULTNAME: 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) static void llvm_emit_make_any(GenContext *c, BEValue *value, Expr *expr)
{ {
if (!llvm_emit_rvalue_in_block(c, value, expr->make_any_expr.inner)) RETURN_EMPTY_BLOCK(value);
llvm_emit_expr(c, value, expr->make_any_expr.inner);
llvm_value_rvalue(c, value);
RETURN_ON_EMPTY_BLOCK(value);
BEValue typeid_val; BEValue typeid_val;
Expr *typeid = expr->make_any_expr.typeid; Expr *typeid = expr->make_any_expr.typeid;
llvm_emit_expr(c, &typeid_val, typeid); if (!llvm_emit_rvalue_in_block(c, &typeid_val, typeid)) RETURN_EMPTY_BLOCK(value);
llvm_value_rvalue(c, &typeid_val);
RETURN_ON_EMPTY_BLOCK(value);
llvm_value_aggregate_two(c, value, expr->type, value->value, typeid_val.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) static void llvm_emit_ext_trunc(GenContext *c, BEValue *value, Expr *expr)
{ {
llvm_emit_expr(c, value, expr->ext_trunc_expr.inner); if (!llvm_emit_rvalue_in_block(c, value, expr->ext_trunc_expr.inner)) RETURN_EMPTY_BLOCK(value);
llvm_value_rvalue(c, value);
Type *to_type = type_lowering(expr->type); Type *to_type = type_lowering(expr->type);
LLVMTypeRef to = llvm_get_type(c, to_type); LLVMTypeRef to = llvm_get_type(c, to_type);
LLVMValueRef val; 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) void llvm_emit_slice_to_vec_array(GenContext *c, BEValue *value, Expr *expr)
{ {
llvm_emit_expr(c, value, expr->inner_expr); if (!llvm_emit_rvalue_in_block(c, value, expr->inner_expr)) RETURN_EMPTY_BLOCK(value);
RETURN_ON_EMPTY_BLOCK(value);
llvm_value_rvalue(c, value);
BEValue pointer; BEValue pointer;
Type *base = value->type->array.base; Type *base = value->type->array.base;
AlignSize element_alignment = type_abi_alignment(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)); 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) void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
{ {
EMIT_EXPR_LOC(c, expr); EMIT_EXPR_LOC(c, expr);

View File

@@ -529,6 +529,8 @@ LLVMValueRef llvm_get_selector(GenContext *c, const char *name);
// -- C3 Lowering -- // -- C3 Lowering --
void llvm_emit_expr_global_value(GenContext *c, BEValue *value, Expr *expr); void llvm_emit_expr_global_value(GenContext *c, BEValue *value, Expr *expr);
void llvm_emit_expr(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_expr_to_rvalue(GenContext *c, Expr *expr);
LLVMValueRef llvm_emit_exprid_to_rvalue(GenContext *c, ExprId expr_id); LLVMValueRef llvm_emit_exprid_to_rvalue(GenContext *c, ExprId expr_id);
void llvm_emit_ignored_expr(GenContext *c, Expr *expr); 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 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(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_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); LLVMAtomicOrdering llvm_atomic_ordering(Atomicity atomicity);

View File

@@ -699,16 +699,14 @@ static void llvm_emit_switch_body_if_chain(GenContext *c,
if (case_stmt == default_case) continue; if (case_stmt == default_case) continue;
BEValue be_value; BEValue be_value;
Expr *expr = exprptr(case_stmt->case_stmt.expr); Expr *expr = exprptr(case_stmt->case_stmt.expr);
llvm_emit_expr(c, &be_value, expr); if (!llvm_emit_rvalue_in_block(c, &be_value, expr)) goto DONE;
llvm_value_rvalue(c, &be_value);
BEValue equals; BEValue equals;
Expr *to_expr = exprptrzero(case_stmt->case_stmt.to_expr); Expr *to_expr = exprptrzero(case_stmt->case_stmt.to_expr);
if (to_expr) if (to_expr)
{ {
ASSERT(!is_type_switch); ASSERT(!is_type_switch);
BEValue to_value; BEValue to_value;
llvm_emit_expr(c, &to_value, to_expr); if (!llvm_emit_rvalue_in_block(c, &to_value, to_expr)) goto DONE;
llvm_value_rvalue(c, &to_value);
BEValue le; BEValue le;
llvm_emit_comp(c, &le, &be_value, switch_value, BINARYOP_LE); llvm_emit_comp(c, &le, &be_value, switch_value, BINARYOP_LE);
BEValue ge; BEValue ge;
@@ -748,6 +746,7 @@ static void llvm_emit_switch_body_if_chain(GenContext *c,
{ {
llvm_emit_br(c, exit_block); llvm_emit_br(c, exit_block);
} }
DONE:
llvm_emit_block(c, exit_block); llvm_emit_block(c, exit_block);
} }

View File

@@ -0,0 +1,73 @@
module abc_faults;
module abc <Type>;
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
}

View File

@@ -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;
}