- Crash in slice expression when it contains a rethrow #2872

- Multiple issues when rethrowing inside of expressions #2873
This commit is contained in:
Christoffer Lerno
2026-01-29 00:42:20 +01:00
parent 414c0c9438
commit 50718cb905
5 changed files with 327 additions and 85 deletions

View File

@@ -148,6 +148,8 @@
- Vector shift by optional scalar failed #2868
- Initializer did not correctly handle second rethrow #2870
- Crash encountering panic in if-else style switch #2871
- Crash in slice expression when it contains a rethrow #2872
- Multiple issues when rethrowing inside of expressions #2873
### Stdlib changes
- Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads.

View File

@@ -811,13 +811,11 @@ static inline void llvm_emit_pointer_offset(GenContext *c, BEValue *value, Expr
Expr *offset_expr = exprptr(expr->pointer_offset_expr.offset);
// Emit the pointer
llvm_emit_expr(c, value, pointer);
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_in_block(c, value, pointer)) RETURN_EMPTY_BLOCK(value);
// Now calculate the offset:
BEValue offset;
llvm_emit_expr(c, &offset, offset_expr);
llvm_value_rvalue(c, &offset);
if (!llvm_emit_rvalue_in_block(c, &offset, offset_expr)) RETURN_EMPTY_BLOCK(value);
Type *element = type_is_vec(value->type) ? value->type->array.base->pointer : value->type->pointer;
value->value = llvm_emit_pointer_gep_raw(c, value->value, offset.value, type_size(element));
@@ -1653,6 +1651,7 @@ static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *r
// Now walk through the elements.
FOREACH_IDX(i, Expr *, element, elements)
{
RETURN_ON_EMPTY_BLOCK(ref);
BEValue pointer;
if (is_struct)
{
@@ -1680,6 +1679,7 @@ static inline void llvm_emit_initialize_reference_list(GenContext *c, BEValue *r
}
BEValue init_value;
llvm_emit_expr(c, &init_value, element);
RETURN_ON_EMPTY_BLOCK(ref);
llvm_store(c, &pointer, &init_value);
}
}
@@ -2381,14 +2381,7 @@ static inline void llvm_emit_deref(GenContext *c, BEValue *value, Expr *inner, T
default:
break;
}
llvm_emit_expr(c, value, inner);
if (!c->current_block)
{
value->type = type_void;
*value = (BEValue) { .type = type_void, .kind = BE_VALUE, .value = NULL };
return;
}
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_in_block(c, value, inner)) RETURN_EMPTY_BLOCK(value);
AlignSize alignment = type_abi_alignment(type);
bool is_const = expr_is_const(inner);
if (is_const)
@@ -2446,7 +2439,7 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e
// Retrieve the address, creating a temp in case this is
// a temporary value (this gives us a lot of flexibility for temporaries)
BEValue addr;
llvm_emit_expr(c, &addr, expr);
if (!llvm_emit_folded_in_block(c, &addr, expr)) RETURN_EMPTY_BLOCK(value);
llvm_value_addr(c, &addr);
// Perform the actual dec/inc to generate the new value.
@@ -2455,8 +2448,7 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e
static void llvm_emit_dynamic_method_addr(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_expr(c, value, expr->access_resolved_expr.parent);
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_in_block(c, value, expr->access_resolved_expr.parent)) RETURN_EMPTY_BLOCK(value);
llvm_emit_type_from_any(c, value);
LLVMValueRef introspect = LLVMBuildIntToPtr(c->builder, value->value, c->ptr_type, "");
@@ -2479,10 +2471,9 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
// Folded
UNREACHABLE_VOID
case UNARYOP_NOT:
llvm_emit_expr(c, value, inner);
if (!llvm_emit_rvalue_in_block(c, value, inner)) RETURN_EMPTY_BLOCK(value);
if (type_flat_is_vector(type))
{
llvm_value_rvalue(c, value);
Type *vec_type = type_vector_type(type);
LLVMValueRef llvm_value;
if (type_is_float(vec_type))
@@ -2498,11 +2489,10 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_value_set(value, llvm_value, res_type);
return;
}
llvm_value_rvalue(c, value);
value->value = LLVMBuildNot(c->builder, value->value, "not");
return;
case UNARYOP_BITNEG:
llvm_emit_expr(c, value, inner);
if (!llvm_emit_folded_in_block(c, value, inner)) RETURN_EMPTY_BLOCK(value);
if (value->type->type_kind == TYPE_ARRAY)
{
llvm_value_addr(c, value);
@@ -2518,8 +2508,7 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
value->value = LLVMBuildNot(c->builder, value->value, "bnot");
return;
case UNARYOP_NEG:
llvm_emit_expr(c, value, inner);
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_in_block(c, value, inner)) RETURN_EMPTY_BLOCK(value);
if (type_is_floatlike(type))
{
value->value = LLVMBuildFNeg(c->builder, value->value, "fneg");
@@ -2548,7 +2537,7 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
}
FALLTHROUGH;
case UNARYOP_TADDR:
llvm_emit_expr(c, value, inner);
if (!llvm_emit_folded_in_block(c, value, inner)) RETURN_EMPTY_BLOCK(value);
// Create an addr
llvm_value_addr(c, value);
// Transform to value
@@ -2661,12 +2650,14 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
parent_type = type_no_optional(parent_type);
BEValue parent_addr_x;
llvm_emit_expr(c, &parent_addr_x, parent_expr);
RETURN_ON_EMPTY_BLOCK_VOID();
LLVMValueRef parent_load_value = NULL;
LLVMValueRef parent_base = NULL;
LLVMValueRef parent_addr = NULL;
if (parent_type->type_kind == TYPE_POINTER)
{
llvm_value_rvalue(c, &parent_addr_x);
RETURN_ON_EMPTY_BLOCK_VOID();
parent_load_value = parent_base = parent_addr_x.value;
}
else
@@ -2703,8 +2694,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
case RANGE_DYNAMIC:
case RANGE_CONST_LEN:
case RANGE_CONST_END:
llvm_emit_exprid(c, &start_index, range.start);
llvm_value_rvalue(c, &start_index);
if (!llvm_emit_rvalue_id_in_block(c, &start_index, range.start)) return;
start_type = start_index.type;
break;
case RANGE_CONST_RANGE:
@@ -2752,6 +2742,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
ASSERT(len.value);
BEValue exceeds_size;
llvm_emit_int_comp(c, &exceeds_size, &start_index, &len, BINARYOP_GT);
RETURN_ON_EMPTY_BLOCK_VOID();
llvm_emit_panic_if_true(c, &exceeds_size, "Index exceeds array len", slice->span, "Index exceeds array length (array had size %d, index was %d).", &len, &start_index);
}
@@ -2808,6 +2799,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
if (is_len_range)
{
llvm_emit_int_comp(c, &excess, &start_index, &end_index, BINARYOP_GT);
RETURN_ON_EMPTY_BLOCK_VOID();
BEValue actual_end_len = end_index;
actual_end_len.value = llvm_emit_sub_int(c, end_index.type, end_index.value, start_index.value, slice->span);
actual_end_len.type = type_isz;
@@ -2815,6 +2807,7 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
if (len.value)
{
llvm_emit_int_comp(c, &excess, &len, &end_index, BINARYOP_LT);
RETURN_ON_EMPTY_BLOCK_VOID();
BEValue actual_end_index = end_index;
actual_end_index.value = llvm_emit_sub_int(c, end_index.type, end_index.value, llvm_const_int(c, type_isz, 1), slice->span);
llvm_emit_panic_if_true(c, &excess, "End index out of bounds", slice->span, "End index out of bounds (end index of %d exceeds size of %d)", &actual_end_index, &len);
@@ -2824,15 +2817,18 @@ static void llvm_emit_slice_values(GenContext *c, Expr *slice, BEValue *parent_r
{
llvm_value_rvalue(c, &start_index);
llvm_value_rvalue(c, &end_index);
RETURN_ON_EMPTY_BLOCK_VOID();
LLVMValueRef val = llvm_emit_add_int(c, end_index.type, end_index.value, llvm_const_int(c, end_index.type, 1), slice->span);
BEValue plus_one_end_index;
llvm_value_set(&plus_one_end_index, val, end_index.type);
llvm_emit_int_comp(c, &excess, &start_index, &plus_one_end_index, BINARYOP_GT);
RETURN_ON_EMPTY_BLOCK_VOID();
llvm_emit_panic_if_true(c, &excess, "Negative size", slice->span, "Negative size (slice was: [%d..%d])", &start_index, &end_index);
if (len.value)
{
llvm_emit_int_comp(c, &excess, &len, &end_index, BINARYOP_LE);
RETURN_ON_EMPTY_BLOCK_VOID();
llvm_emit_panic_if_true(c, &excess, "End index out of bounds", slice->span, "End index out of bounds (end index of %d exceeds size of %d)", &end_index, &len);
}
}
@@ -2860,8 +2856,10 @@ static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr)
BEValue end;
bool is_exclusive;
llvm_emit_slice_values(c, expr, &parent, &start, &end, &is_exclusive);
RETURN_ON_EMPTY_BLOCK(be_value);
llvm_value_rvalue(c, &start);
llvm_value_rvalue(c, &end);
RETURN_ON_EMPTY_BLOCK(be_value);
// Calculate the size
LLVMValueRef size;
@@ -2900,24 +2898,23 @@ static void gencontext_emit_slice(GenContext *c, BEValue *be_value, Expr *expr)
llvm_value_aggregate_two(c, be_value, type_lowering(expr->type), start_pointer, size);
}
static void llvm_emit_slice_copy(GenContext *c, BEValue *be_value, Expr *expr)
static void llvm_emit_slice_copy(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_exprid(c, be_value, expr->slice_assign_expr.right);
llvm_value_rvalue(c, be_value);
if (!llvm_emit_rvalue_id_in_block(c, value, expr->slice_assign_expr.right)) RETURN_EMPTY_BLOCK(value);
BEValue assigned_to;
llvm_emit_exprid(c, &assigned_to, expr->slice_assign_expr.left);
llvm_value_rvalue(c, &assigned_to);
if (!llvm_emit_rvalue_id_in_block(c, &assigned_to, expr->slice_assign_expr.left)) RETURN_EMPTY_BLOCK(value);
BEValue to_pointer;
llvm_emit_slice_pointer(c, &assigned_to, &to_pointer);
llvm_value_rvalue(c, &to_pointer);
RETURN_ON_EMPTY_BLOCK(value);
BEValue from_pointer;
BEValue from_len;
llvm_emit_slice_pointer(c, be_value, &from_pointer);
llvm_emit_slice_pointer(c, value, &from_pointer);
llvm_value_rvalue(c, &from_pointer);
llvm_emit_slice_len(c, be_value, &from_len);
llvm_emit_slice_len(c, value, &from_len);
llvm_value_rvalue(c, &from_len);
if (safe_mode_enabled())
@@ -2926,6 +2923,7 @@ static void llvm_emit_slice_copy(GenContext *c, BEValue *be_value, Expr *expr)
llvm_emit_slice_len(c, &assigned_to, &to_len);
BEValue comp;
llvm_emit_int_comp(c, &comp, &to_len, &from_len, BINARYOP_NE);
RETURN_ON_EMPTY_BLOCK_VOID();
llvm_emit_panic_if_true(c, &comp, "Length mismatch", expr->span, "Slice copy length mismatch (%d != %d).", &to_len, &from_len);
}
@@ -3118,12 +3116,14 @@ void llvm_emit_int_comp_zero(GenContext *c, BEValue *result, BEValue *lhs, Binar
BEValue zero;
llvm_value_set_int(c, &zero, lhs->type, 0);
llvm_emit_int_comp(c, result, lhs, &zero, binary_op);
RETURN_ON_EMPTY_BLOCK_VOID();
}
void llvm_emit_int_comp(GenContext *c, BEValue *result, BEValue *lhs, BEValue *rhs, BinaryOp binary_op)
{
llvm_value_rvalue(c, lhs);
llvm_value_rvalue(c, rhs);
RETURN_ON_EMPTY_BLOCK(result);
llvm_emit_int_comp_raw(c, result, lhs->type, rhs->type, lhs->value, rhs->value, binary_op);
}
void llvm_emit_int_comp_raw(GenContext *c, BEValue *result, Type *lhs_type, Type *rhs_type, LLVMValueRef lhs_value, LLVMValueRef rhs_value, BinaryOp binary_op)
@@ -4402,15 +4402,11 @@ static inline void llvm_emit_rethrow_expr(GenContext *c, BEValue *be_value, Expr
PUSH_CATCH_VAR_BLOCK(error_var_ref.value, guard_block);
llvm_emit_expr(c, be_value, expr->rethrow_expr.inner);
// Fold the optional.
llvm_value_fold_optional(c, be_value);
llvm_emit_folded_in_block(c, be_value, expr->rethrow_expr.inner);
// Restore.
POP_CATCH();
// Emit success and to end.
bool emit_no_err = llvm_emit_br(c, no_err_block);
@@ -4456,8 +4452,7 @@ static inline void llvm_emit_force_unwrap_expr(GenContext *c, BEValue *be_value,
PUSH_CATCH_VAR_BLOCK(error_var_ref.value, panic_block);
llvm_emit_expr(c, be_value, expr->inner_expr);
llvm_value_fold_optional(c, be_value);
llvm_emit_folded_in_block(c, be_value, expr->inner_expr);
// Restore.
POP_CATCH();
@@ -4506,6 +4501,7 @@ static void llvm_emit_vector_assign_expr(GenContext *c, BEValue *be_value, Expr
// Emit the variable
llvm_emit_exprid(c, &addr, left->subscript_expr.expr);
}
RETURN_ON_EMPTY_BLOCK(be_value);
// Emit the variable
llvm_value_addr(c, &addr);
@@ -4526,7 +4522,9 @@ static void llvm_emit_vector_assign_expr(GenContext *c, BEValue *be_value, Expr
{
llvm_emit_expr(c, be_value, exprptr(expr->binary_expr.right));
}
RETURN_ON_EMPTY_BLOCK(be_value);
llvm_value_rvalue(c, be_value);
RETURN_ON_EMPTY_BLOCK(be_value);
const char *sw_ptr = left->swizzle_expr.swizzle;
unsigned vec_len = be_value->type->array.len;
LLVMValueRef result = be_value->value;
@@ -4544,6 +4542,7 @@ static void llvm_emit_vector_assign_expr(GenContext *c, BEValue *be_value, Expr
// Emit the index
BEValue index;
llvm_emit_exprid(c, &index, left->subscript_expr.index.expr);
RETURN_ON_EMPTY_BLOCK(be_value);
LLVMValueRef index_val = llvm_load_value_store(c, &index);
if (binary_op > BINARYOP_ASSIGN)
{
@@ -4552,10 +4551,12 @@ static void llvm_emit_vector_assign_expr(GenContext *c, BEValue *be_value, Expr
BEValue lhs;
llvm_value_set(&lhs, LLVMBuildExtractElement(c->builder, vector_value, index_val, "elem"), expr->type);
llvm_emit_binary(c, be_value, expr, &lhs, base_op);
RETURN_ON_EMPTY_BLOCK(be_value);
}
else
{
llvm_emit_expr(c, be_value, exprptr(expr->binary_expr.right));
RETURN_ON_EMPTY_BLOCK(be_value);
}
LLVMValueRef new_value = LLVMBuildInsertElement(c->builder, vector_value, llvm_load_value_store(c, be_value),
@@ -4583,15 +4584,15 @@ static void llvm_emit_binary_expr(GenContext *c, BEValue *be_value, Expr *expr)
// Get the left hand side, which must be an address.
BEValue addr;
llvm_emit_expr(c, &addr, exprptr(expr->binary_expr.left));
ASSERT(llvm_value_is_addr(&addr));
if (!llvm_emit_folded_in_block(c, &addr, exprptr(expr->binary_expr.left))) RETURN_EMPTY_BLOCK(be_value);
// Fold the optional.
llvm_value_fold_optional(c, &addr);
ASSERT(llvm_value_is_addr(&addr));
// Perform the binary operation, using the already loaded LHS.
llvm_emit_binary(c, be_value, expr, &addr, base_op);
RETURN_ON_EMPTY_BLOCK(be_value);
// Store it.
llvm_store(c, &addr, be_value);
return;
@@ -4657,8 +4658,7 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_emit_cond_br(c, value, lhs_block, rhs_block);
llvm_emit_block(c, lhs_block);
BEValue lhs;
llvm_emit_expr(c, &lhs, then_expr);
llvm_value_rvalue(c, &lhs);
llvm_emit_rvalue_in_block(c, &lhs, then_expr);
LLVMValueRef lhs_value = lhs.value;
LLVMBasicBlockRef lhs_exit = llvm_get_current_block_if_in_use(c);
if (lhs.type == type_bool && LLVMTypeOf(lhs_value) != c->bool_type)
@@ -4669,8 +4669,7 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_emit_block(c, rhs_block);
BEValue rhs;
llvm_emit_expr(c, &rhs, else_expr);
llvm_value_rvalue(c, &rhs);
llvm_emit_rvalue_in_block(c, &rhs, else_expr);
LLVMValueRef rhs_value = rhs.value;
if (rhs.type == type_bool && LLVMTypeOf(rhs_value) != c->bool_type)
{
@@ -4698,7 +4697,7 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr)
if (type_lowering(expr->type) == type_void)
{
llvm_value_set(value, NULL, expr->type);
llvm_value_set_empty(value);
return;
}
@@ -5893,8 +5892,7 @@ INLINE void llvm_emit_varargs_expr(GenContext *c, BEValue *value_ref, Expr **var
INLINE void llvm_emit_vasplat_expr(GenContext *c, BEValue *value_ref, Expr *vasplat, Type *param)
{
llvm_emit_expr(c, value_ref, vasplat);
llvm_value_fold_optional(c, value_ref);
if (!llvm_emit_folded_in_block(c, value_ref, vasplat)) RETURN_EMPTY_BLOCK(value_ref);
Type *type = value_ref->type;
switch (type->type_kind)
{
@@ -5922,7 +5920,6 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
llvm_emit_builtin_call(c, result_value, expr);
return;
}
LLVMTypeRef func_type;
LLVMValueRef func;
@@ -5947,6 +5944,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
// 1c. Evaluate the pointer expression.
BEValue func_value;
llvm_emit_expr(c, &func_value, function);
RETURN_ON_EMPTY_BLOCK(result_value);
// 1d. Load it as a value
func = llvm_load_value_store(c, &func_value);
@@ -6125,6 +6123,7 @@ static inline void llvm_emit_expression_list_expr(GenContext *c, BEValue *be_val
for (unsigned i = 0; i < last; i++)
{
llvm_emit_ignored_expr(c, list[i]);
RETURN_ON_EMPTY_BLOCK(be_value);
}
llvm_emit_expr(c, be_value, list[last]);
}
@@ -6358,6 +6357,7 @@ static inline void llvm_emit_optional(GenContext *c, BEValue *be_value, Expr *ex
{
ASSERT(c->catch.fault);
llvm_emit_expr(c, be_value, fail);
RETURN_ON_EMPTY_BLOCK(be_value);
llvm_store_to_ptr(c, c->catch.fault, be_value);
}
// Branch to the catch
@@ -6401,6 +6401,7 @@ static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *val
FOREACH_IDX(i, Expr *, element, elements)
{
llvm_emit_expr(c, &val, element);
RETURN_ON_EMPTY_BLOCK(value);
vec_value = llvm_update_vector(c, vec_value, llvm_load_value_store(c, &val), (ArrayIndex)i);
}
}
@@ -6411,8 +6412,7 @@ static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *val
if (splat)
{
BEValue splat_val;
llvm_emit_expr(c, &splat_val, splat);
llvm_value_rvalue(c, &splat_val);
if (!llvm_emit_rvalue_in_block(c, &splat_val, splat)) RETURN_ON_EMPTY_BLOCK(value);
vec_value = splat_val.value;
}
else
@@ -6425,18 +6425,19 @@ static inline void llvm_emit_vector_initializer_list(GenContext *c, BEValue *val
ASSERT(vec_size(designator->designator_expr.path) == 1);
DesignatorElement *element = designator->designator_expr.path[0];
llvm_emit_expr(c, &val, designator->designator_expr.value);
LLVMValueRef value = llvm_load_value_store(c, &val);
RETURN_ON_EMPTY_BLOCK(value);
LLVMValueRef value_ref = llvm_load_value_store(c, &val);
switch (element->kind)
{
case DESIGNATOR_ARRAY:
{
vec_value = llvm_update_vector(c, vec_value, value, element->index);
vec_value = llvm_update_vector(c, vec_value, value_ref, element->index);
break;
}
case DESIGNATOR_RANGE:
for (ArrayIndex idx = element->index; idx <= element->index_end; idx++)
{
vec_value = llvm_update_vector(c, vec_value, value, idx);
vec_value = llvm_update_vector(c, vec_value, value_ref, idx);
}
break;
case DESIGNATOR_FIELD:
@@ -6486,6 +6487,7 @@ static void llvm_emit_macro_body_expansion(GenContext *c, BEValue *value, Expr *
{
if (!expr) continue;
llvm_emit_expr(c, value, expr);
RETURN_ON_EMPTY_BLOCK(value);
llvm_store_to_ptr_aligned(c, declarations[j]->backend_ref, value, declarations[j]->alignment);
}
@@ -6515,6 +6517,7 @@ static inline void llvm_emit_try_unwrap(GenContext *c, BEValue *value, Expr *exp
if (lhs)
{
llvm_emit_expr(c, &addr, lhs);
RETURN_ON_EMPTY_BLOCK(value);
}
else
{
@@ -6552,10 +6555,9 @@ void llvm_emit_catch_unwrap(GenContext *c, BEValue *value, Expr *expr)
{
BEValue val;
LLVMBasicBlockRef block = llvm_basic_block_new(c, "testblock");
llvm_emit_br(c, block);
if (c->current_block) llvm_emit_br(c, block);
llvm_emit_block(c, block);
llvm_emit_expr(c, &val, e);
llvm_value_fold_optional(c, &val);
llvm_emit_folded_in_block(c, &val, e);
}
POP_CATCH();
@@ -6575,8 +6577,7 @@ static inline LLVMValueRef llvm_load_introspect(GenContext *c, LLVMValueRef ref,
}
static inline void llvm_emit_typeid_info(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_exprid(c, value, expr->typeid_info_expr.parent);
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_id_in_block(c, value, expr->typeid_info_expr.parent)) RETURN_ON_EMPTY_BLOCK(value);
LLVMValueRef kind = NULL;
LLVMValueRef ref = LLVMBuildIntToPtr(c->builder, value->value, c->ptr_type, "introspect*");
@@ -6733,8 +6734,7 @@ void llvm_emit_try_unwrap_chain(GenContext *c, BEValue *value, Expr *expr)
next_block = llvm_basic_block_new(c, "chain_next");
Expr *link = exprs[i];
BEValue res;
llvm_emit_expr(c, &res, link);
llvm_value_rvalue(c, &res);
if (!llvm_emit_rvalue_in_block(c, &res, link)) break;
ASSERT(llvm_value_is_bool(&res));
llvm_emit_cond_br(c, &res, next_block, fail_block);
}
@@ -6786,6 +6786,7 @@ static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Ex
(void)inner_type;
ASSERT(inner_type->type_kind == TYPE_ANYFAULT);
llvm_value_rvalue(c, be_value);
RETURN_ON_EMPTY_BLOCK(be_value);
BEValue zero = llvm_emit_alloca_b(c, type_chars, "faultname_zero");
LLVMBasicBlockRef exit_block = llvm_basic_block_new(c, "faultname_exit");
@@ -6793,6 +6794,7 @@ static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Ex
LLVMBasicBlockRef ok_block = llvm_basic_block_new(c, "faultname_ok");
BEValue check;
llvm_emit_int_comp_zero(c, &check, be_value, BINARYOP_EQ);
RETURN_ON_EMPTY_BLOCK(be_value);
llvm_emit_cond_br(c, &check, zero_block, ok_block);
llvm_emit_block(c, zero_block);
llvm_store_zero(c, &zero);
@@ -6811,6 +6813,7 @@ static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Ex
Type *inner_type = type_no_optional(inner->type)->canonical;
ASSERT(inner_type->canonical->type_kind == TYPE_ENUM);
llvm_value_rvalue(c, be_value);
RETURN_ON_EMPTY_BLOCK(be_value);
LLVMValueRef to_introspect = LLVMBuildIntToPtr(c->builder, llvm_get_typeid(c, inner_type),
c->ptr_type, "");
LLVMValueRef ptr = LLVMBuildStructGEP2(c->builder, c->introspect_type, to_introspect, INTROSPECT_INDEX_ADDITIONAL, "");
@@ -6913,8 +6916,7 @@ static void llvm_emit_swizzle_from_value(GenContext *c, LLVMValueRef vector_valu
static void llvm_emit_swizzle(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_exprid(c, value, expr->swizzle_expr.parent);
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_id_in_block(c, value, expr->swizzle_expr.parent)) RETURN_EMPTY_BLOCK(value);
llvm_emit_swizzle_from_value(c, value->value, value, expr);
}
@@ -6932,15 +6934,13 @@ static void llvm_emit_default_arg(GenContext *c, BEValue *value, Expr *expr)
DebugScope scope = { .lexical_block = init_def, .inline_loc = c->last_loc };
DebugScope *old = c->debug.block_stack;
c->debug.block_stack = &scope;
llvm_emit_expr(c, value, expr->default_arg_expr.inner);
llvm_value_fold_optional(c, value);
if (!llvm_emit_folded_in_block(c, value, expr->default_arg_expr.inner)) RETURN_EMPTY_BLOCK(value);
c->debug.block_stack = old;
c->last_emitted_loc.a = 0;
}
else
{
llvm_emit_expr(c, value, expr->default_arg_expr.inner);
llvm_value_fold_optional(c, value);
llvm_emit_folded_in_block(c, value, expr->default_arg_expr.inner);
}
}
@@ -7006,15 +7006,13 @@ void llvm_emit_array_to_vector(GenContext *c, BEValue *value, Type *to)
static void llvm_emit_vector_from_array(GenContext *c, BEValue *value, Expr *expr)
{
Expr *inner = expr->inner_expr;
llvm_emit_expr(c, value, inner);
llvm_value_fold_optional(c, value);
if (!llvm_emit_folded_in_block(c, value, inner)) RETURN_EMPTY_BLOCK(value);
llvm_emit_array_to_vector(c, value, expr->type);
}
static void llvm_emit_ptr_access(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_expr(c, value, expr->inner_expr);
llvm_value_fold_optional(c, value);
if (!llvm_emit_folded_in_block(c, value, expr->inner_expr)) RETURN_EMPTY_BLOCK(value);
if (value->kind == BE_ADDRESS)
{
llvm_emit_struct_gep_ref(c, value, value, expr->type, 0);
@@ -7057,10 +7055,11 @@ static void llvm_emit_ext_trunc(GenContext *c, BEValue *value, Expr *expr)
void llvm_emit_enum_from_ord(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_expr(c, value, expr->inner_expr);
RETURN_ON_EMPTY_BLOCK(value);
if (safe_mode_enabled() && c->builder != c->global_builder)
{
llvm_value_rvalue(c, value);
RETURN_ON_EMPTY_BLOCK(value);
BEValue check;
Decl *decl = type_flatten(expr->type)->decl;
unsigned max = vec_size(decl->enums.values);
@@ -7069,6 +7068,7 @@ void llvm_emit_enum_from_ord(GenContext *c, BEValue *value, Expr *expr)
scratch_buffer_clear();
scratch_buffer_printf("Attempt to convert a negative value (%%d) to enum '%s' failed.", decl->name);
llvm_emit_int_comp_zero(c, &check, value, BINARYOP_LT);
RETURN_ON_EMPTY_BLOCK(value);
llvm_emit_panic_on_true(c, check.value, "Attempt to convert negative value to enum failed.", expr->span, scratch_buffer_copy(), value, NULL);
}
scratch_buffer_clear();
@@ -7091,6 +7091,7 @@ void llvm_emit_enum_from_ord(GenContext *c, BEValue *value, Expr *expr)
void llvm_emit_scalar_to_vector(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_expr(c, value, expr->inner_expr);
RETURN_ON_EMPTY_BLOCK(value);
LLVMValueRef val = llvm_load_value_store(c, value);
LLVMTypeRef type = llvm_get_type(c, expr->type);
unsigned elements = LLVMGetVectorSize(type);
@@ -7118,6 +7119,7 @@ void llvm_emit_vec_to_array(GenContext *c, BEValue *value, Type *type)
static inline void llvm_emit_vector_to_array(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_expr(c, value, expr->inner_expr);
RETURN_ON_EMPTY_BLOCK(value);
llvm_emit_vec_to_array(c, value, expr->type);
}
@@ -7142,8 +7144,7 @@ static inline void llvm_emit_make_slice(GenContext *c, BEValue *value, Expr *exp
LLVMValueRef pointer;
if (size)
{
llvm_emit_expr(c, value, expr->make_slice_expr.ptr);
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_in_block(c, value, expr->make_slice_expr.ptr)) RETURN_EMPTY_BLOCK(value);
pointer = value->value;
}
else
@@ -7169,6 +7170,8 @@ bool llvm_emit_folded_in_block(GenContext *c, BEValue *value, Expr *expr)
return true;
}
bool llvm_emit_rvalue_in_block(GenContext *c, BEValue *value, Expr *expr)
{
if (llvm_is_global_eval(c))
@@ -7206,6 +7209,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
UNREACHABLE_VOID
case EXPR_TWO:
llvm_emit_expr(c, value, expr->two_expr.first);
RETURN_ON_EMPTY_BLOCK(value);
llvm_emit_expr(c, value, expr->two_expr.last);
return;
case EXPR_VECTOR_TO_ARRAY:
@@ -7227,8 +7231,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_emit_make_any(c, value, expr);
return;
case EXPR_FLOAT_TO_INT:
llvm_emit_expr(c, value, expr->inner_expr);
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_in_block(c, value, expr->inner_expr)) RETURN_EMPTY_BLOCK(value);
if (type_is_signed_any(type_lowering(expr->type)))
{
llvm_value_set(value, LLVMBuildFPToSI(c->builder, value->value, llvm_get_type(c, expr->type), "fpsi"), expr->type);
@@ -7237,8 +7240,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_value_set(value, LLVMBuildFPToUI(c->builder, value->value, llvm_get_type(c, expr->type), "fpui"), expr->type);
return;
case EXPR_INT_TO_FLOAT:
llvm_emit_expr(c, value, expr->inner_expr);
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_in_block(c, value, expr->inner_expr)) RETURN_EMPTY_BLOCK(value);
if (type_is_signed_any(value->type))
{
llvm_value_set(value, LLVMBuildSIToFP(c->builder, value->value, llvm_get_type(c, expr->type), "sifp"), expr->type);
@@ -7253,17 +7255,16 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
llvm_emit_ignored_expr(c, expr->inner_expr);
return;
case EXPR_PTR_TO_INT:
llvm_emit_expr(c, value, expr->inner_expr);
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_in_block(c, value, expr->inner_expr)) RETURN_EMPTY_BLOCK(value);
llvm_value_set(value, LLVMBuildPtrToInt(c->builder, value->value, llvm_get_type(c, expr->type), "ptrxi"), expr->type);
return;
case EXPR_INT_TO_PTR:
llvm_emit_expr(c, value, expr->inner_expr);
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_in_block(c, value, expr->inner_expr)) RETURN_EMPTY_BLOCK(value);
llvm_value_set(value, LLVMBuildIntToPtr(c->builder, value->value, llvm_get_type(c, expr->type), "intptr"), expr->type);
return;
case EXPR_ADDR_CONVERSION:
llvm_emit_expr(c, value, expr->inner_expr);
RETURN_ON_EMPTY_BLOCK(value);
llvm_value_addr(c, value);
value->type = type_lowering(expr->type);
return;
@@ -7272,8 +7273,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
value->type = type_lowering(expr->type);
return;
case EXPR_RVALUE:
llvm_emit_expr(c, value, expr->inner_expr);
llvm_value_rvalue(c, value);
if (!llvm_emit_rvalue_in_block(c, value, expr->inner_expr)) RETURN_EMPTY_BLOCK(value);
value->type = type_lowering(expr->type);
return;
case EXPR_VECTOR_FROM_ARRAY:
@@ -7281,6 +7281,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
return;
case EXPR_SLICE_LEN:
llvm_emit_expr(c, value, expr->inner_expr);
RETURN_ON_EMPTY_BLOCK(value);
llvm_emit_slice_len(c, value, value);
return;
case EXPR_PTR_ACCESS:

View File

@@ -555,6 +555,7 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *ref_expr, Expr
INLINE void llvm_emit_exprid(GenContext *c, BEValue *value, ExprId expr);
INLINE void llvm_emit_statement_chain(GenContext *c, AstId current);
void llvm_emit_initialize_reference_temporary_const(GenContext *c, BEValue *ref, ConstInitializer *initializer);
INLINE bool llvm_emit_rvalue_id_in_block(GenContext *c, BEValue *value, ExprId expr_id) { return llvm_emit_rvalue_in_block(c, value, exprptr(expr_id)); }
LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl);
LLVMValueRef llvm_emit_call_intrinsic(GenContext *c, unsigned intrinsic, LLVMTypeRef *types, unsigned type_count, LLVMValueRef *values, unsigned arg_count);

View File

@@ -0,0 +1,41 @@
// #target: macos-x64
// #safe: yes
module abc_faults;
module abc <Type>;
import std::io, abc_faults, std::collections::list;
struct TextTemplate
{
TextTag tags;
}
struct TextTag
{
usz start;
}
fn void? TextTemplate.init(&self, String template, String tag_start = "", String tag_end = "", Allocator using )
{
String tmpl = template;
while (true)
{
usz? end = tmpl.index_of(tag_end);
if (catch end) return ;
tmpl = tmpl[end + 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)!!;
}

View File

@@ -0,0 +1,197 @@
// #target: macos-x64
// #safe: yes
module test;
import std;
struct Doc { Head *head; }
struct Head { char[]* title; }
struct Summary
{
char* title;
}
macro dupe(value)
{
$typeof(&value) temp = malloc($sizeof(value));
if (!temp) return OUT_OF_MEMORY~;
return temp;
}
faultdef BAD_READ, OUT_OF_MEMORY;
fn Doc? readDoc(char[] )
{
char* str = malloc( + 1);
return { dupe((Head) { .title = dupe(str[..io::EOF~! - 1])! })! };
}
fn Summary buildSummary(Doc )
{
return {
};
}
fn Summary readAndBuildSummary(char[] url)
{
return buildSummary(readDoc(url)) ?? (Summary) { .title = null, };
}
fn void main()
{
const char[][] URLS = { "", "", "", "", };
foreach ( url : URLS)
{
Summary summary = readAndBuildSummary(url);
}
}
/* #expect: test.ll
define i64 @test.readDoc(ptr %0, ptr %1, i64 %2) #0 {
entry:
%.anon = alloca %"char[]", align 8
%str = alloca ptr, align 8
%reterr = alloca i64, align 8
%literal = alloca %Doc, align 8
%error_var = alloca i64, align 8
%literal1 = alloca %Head, align 8
%error_var2 = alloca i64, align 8
%error_var3 = alloca i64, align 8
store ptr %1, ptr %.anon, align 8
%ptradd = getelementptr inbounds i8, ptr %.anon, i64 8
store i64 %2, ptr %ptradd, align 8
%3 = call ptr @std.core.mem.malloc(i64 1) #3
store ptr %3, ptr %str, align 8
store ptr null, ptr %literal1, align 8
%4 = load ptr, ptr %str, align 8
store i64 ptrtoint (ptr @std.io.EOF to i64), ptr %error_var3, align 8
br label %guard_block
guard_block: ; preds = %entry
%5 = load i64, ptr %error_var3, align 8
ret i64 %5
}
define ptr @test.buildSummary(ptr %0) #0 {
entry:
%.anon = alloca %Doc, align 8
%literal = alloca %Summary, align 8
store ptr %0, ptr %.anon, align 8
store ptr null, ptr %literal, align 8
%1 = load ptr, ptr %literal, align 8
ret ptr %1
}
define ptr @test.readAndBuildSummary(ptr %0, i64 %1) #0 {
entry:
%url = alloca %"char[]", align 8
%retparam = alloca %Doc, align 8
%result = alloca %Summary, align 8
%literal = alloca %Summary, align 8
store ptr %0, ptr %url, align 8
%ptradd = getelementptr inbounds i8, ptr %url, i64 8
store i64 %1, ptr %ptradd, align 8
%lo = load ptr, ptr %url, align 8
%ptradd1 = getelementptr inbounds i8, ptr %url, i64 8
%hi = load i64, ptr %ptradd1, align 8
%2 = call i64 @test.readDoc(ptr %retparam, ptr %lo, i64 %hi)
%not_err = icmp eq i64 %2, 0
%3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
br i1 %3, label %after_check, label %else_block
after_check: ; preds = %entry
%4 = load ptr, ptr %retparam, align 8
%5 = call ptr @test.buildSummary(ptr %4)
store ptr %5, ptr %result, align 8
br label %phi_block
else_block: ; preds = %entry
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal, ptr align 8 @.__const, i32 8, i1 false)
br label %phi_block
phi_block: ; preds = %else_block, %after_check
%val = phi ptr [ %result, %after_check ], [ %literal, %else_block ]
%6 = load ptr, ptr %val, align 8
ret ptr %6
}
define void @test.main() #0 {
entry:
%.anon = alloca i64, align 8
%url = alloca %"char[]", align 8
%taddr = alloca i64, align 8
%taddr1 = alloca i64, align 8
%varargslots = alloca [2 x %any], align 16
%indirectarg = alloca %"any[]", align 8
%taddr3 = alloca i64, align 8
%taddr4 = alloca i64, align 8
%varargslots5 = alloca [2 x %any], align 16
%indirectarg8 = alloca %"any[]", align 8
%summary = alloca %Summary, align 8
%result = alloca %Summary, align 8
%0 = load i64, ptr getelementptr inbounds (i8, ptr @main.URLS, i64 8), align 8
store i64 0, ptr %.anon, align 8
br label %loop.cond
loop.cond: ; preds = %checkok9, %entry
%1 = load i64, ptr %.anon, align 8
%lt = icmp ult i64 %1, %0
br i1 %lt, label %loop.body, label %loop.exit
loop.body: ; preds = %loop.cond
%2 = load i64, ptr getelementptr inbounds (i8, ptr @main.URLS, i64 8), align 8
%3 = load ptr, ptr @main.URLS, align 8
%4 = load i64, ptr %.anon, align 8
%ge = icmp uge i64 %4, %2
%5 = call i1 @llvm.expect.i1(i1 %ge, i1 false)
br i1 %5, label %panic, label %checkok
checkok: ; preds = %loop.body
%ptroffset = getelementptr inbounds [16 x i8], ptr %3, i64 %4
%6 = ptrtoint ptr %ptroffset to i64
%7 = urem i64 %6, 8
%8 = icmp ne i64 %7, 0
%9 = call i1 @llvm.expect.i1(i1 %8, i1 false)
br i1 %9, label %panic2, label %checkok9
checkok9: ; preds = %checkok
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %url, ptr align 8 %ptroffset, i32 16, i1 false)
%lo = load ptr, ptr %url, align 8
%ptradd10 = getelementptr inbounds i8, ptr %url, i64 8
%hi = load i64, ptr %ptradd10, align 8
%10 = call ptr @test.readAndBuildSummary(ptr %lo, i64 %hi)
store ptr %10, ptr %result, align 8
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %summary, ptr align 8 %result, i32 8, i1 false)
%11 = load i64, ptr %.anon, align 8
%addnuw = add nuw i64 %11, 1
store i64 %addnuw, ptr %.anon, align 8
br label %loop.cond
loop.exit: ; preds = %loop.cond
ret void
panic: ; preds = %loop.body
store i64 %2, ptr %taddr, align 8
%12 = insertvalue %any undef, ptr %taddr, 0
%13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1
store i64 %4, ptr %taddr1, align 8
%14 = insertvalue %any undef, ptr %taddr1, 0
%15 = insertvalue %any %14, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1
store %any %13, ptr %varargslots, align 16
%ptradd = getelementptr inbounds i8, ptr %varargslots, i64 16
store %any %15, ptr %ptradd, align 16
%16 = insertvalue %"any[]" undef, ptr %varargslots, 0
%"$$temp" = insertvalue %"any[]" %16, i64 2, 1
store %"any[]" %"$$temp", ptr %indirectarg, align 8
call void @std.core.builtin.panicf(ptr @.panic_msg, i64 59, ptr @.file, i64 25, ptr @.func, i64 4, i32 33, ptr byval(%"any[]") align 8 %indirectarg) #4
unreachable
panic2: ; preds = %checkok
store i64 8, ptr %taddr3, align 8
%17 = insertvalue %any undef, ptr %taddr3, 0
%18 = insertvalue %any %17, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1
store i64 %7, ptr %taddr4, align 8
%19 = insertvalue %any undef, ptr %taddr4, 0
%20 = insertvalue %any %19, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1
store %any %18, ptr %varargslots5, align 16
%ptradd6 = getelementptr inbounds i8, ptr %varargslots5, i64 16
store %any %20, ptr %ptradd6, align 16
%21 = insertvalue %"any[]" undef, ptr %varargslots5, 0
%"$$temp7" = insertvalue %"any[]" %21, i64 2, 1
store %"any[]" %"$$temp7", ptr %indirectarg8, align 8
call void @std.core.builtin.panicf(ptr @.panic_msg.1, i64 94, ptr @.file, i64 25, ptr @.func, i64 4, i32 33, ptr byval(%"any[]") align 8 %indirectarg8) #4
unreachable
}