- Crash when creating $Type* where $Type is an optional type #2848

- Crashes when using `io::EOF~!` in various unhandled places. #2848
This commit is contained in:
Christoffer Lerno
2026-01-27 13:32:08 +01:00
parent 3e76b7ff1c
commit 4fbb42833e
13 changed files with 365 additions and 26 deletions

View File

@@ -4452,7 +4452,7 @@ static inline void llvm_emit_force_unwrap_expr(GenContext *c, BEValue *be_value,
POP_CATCH();
// Emit success and to end.
llvm_emit_br(c, no_err_block);
bool emit_no_err = llvm_emit_br(c, no_err_block);
POP_CATCH();
@@ -4469,8 +4469,11 @@ static inline void llvm_emit_force_unwrap_expr(GenContext *c, BEValue *be_value,
vec_add(varargs, error_var_ref);
llvm_emit_panic(c, "Force unwrap failed!", loc, "Unexpected fault '%s' was unwrapped!", varargs);
}
llvm_emit_block(c, no_err_block);
EMIT_EXPR_LOC(c, expr);
if (emit_no_err)
{
llvm_emit_block(c, no_err_block);
EMIT_EXPR_LOC(c, expr);
}
}
@@ -4614,6 +4617,7 @@ void gencontext_emit_ternary_expr(GenContext *c, BEValue *value, Expr *expr)
Expr *cond = exprptr(expr->ternary_expr.cond);
llvm_emit_expr(c, value, cond);
llvm_value_rvalue(c, value);
RETURN_ON_EMPTY_BLOCK(value);
Expr *else_expr = exprptr(expr->ternary_expr.else_expr);
Expr *then_expr = exprptr(expr->ternary_expr.then_expr);
@@ -5992,6 +5996,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
{
llvm_emit_expr(c, value_ref, arg);
llvm_value_fold_optional(c, value_ref);
RETURN_ON_EMPTY_BLOCK(result_value);
continue;
}
Decl *decl = sig->params[i];
@@ -5999,11 +6004,13 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
if (vararg_splat)
{
llvm_emit_vasplat_expr(c, value_ref, vararg_splat, param);
RETURN_ON_EMPTY_BLOCK(result_value);
continue;
}
if (varargs)
{
llvm_emit_varargs_expr(c, value_ref, varargs, param);
RETURN_ON_EMPTY_BLOCK(result_value);
continue;
}
// Just set the size to zero.
@@ -6017,6 +6024,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
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);
}
}
@@ -7016,10 +7024,12 @@ 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);
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);
llvm_value_aggregate_two(c, value, expr->type, value->value, typeid_val.value);
}

View File

@@ -594,8 +594,8 @@ void llvm_emit_debug_local_var(GenContext *c, Decl *var);
#define EMIT_SPAN(c, x) do { if (c->debug.builder) llvm_emit_debug_location(c, x); } while (0)
#define PUSH_DEFER_ERROR(val__) LLVMValueRef def_err__ = c->defer_error_var; c->defer_error_var = val__
#define POP_DEFER_ERROR() c->defer_error_var = def_err__
#define RETURN_ON_EMPTY_BLOCK(value__) do { if (!c->current_block) { llvm_value_set_empty(value__); return; }} while(0)
#define RETURN_ON_EMPTY_BLOCK_VOID() do { if (!c->current_block) { 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)
LLVMAtomicOrdering llvm_atomic_ordering(Atomicity atomicity);

View File

@@ -3731,7 +3731,7 @@ static inline bool sema_call_analyse_member_set(SemaContext *context, Expr *expr
}
Expr *access = expr_new_expr(target_kind == TYPE_BITSTRUCT ? EXPR_BITACCESS : EXPR_ACCESS_RESOLVED, expr);
access->access_resolved_expr = (ExprResolvedAccess) { .parent = inner, .ref = decl };
access->type = decl->type;
access->type = type_add_optional(decl->type, IS_OPTIONAL(inner));
access->resolve_status = RESOLVE_DONE;
expr->expr_kind = EXPR_BINARY;
expr->binary_expr = (ExprBinary) { .left = exprid(access), .right = exprid(arg), .operator = BINARYOP_ASSIGN };
@@ -3759,7 +3759,7 @@ static inline bool sema_call_analyse_member_get(SemaContext *context, Expr *expr
}
expr->expr_kind = target_kind == TYPE_BITSTRUCT ? EXPR_BITACCESS : EXPR_ACCESS_RESOLVED;
expr->access_resolved_expr = (ExprResolvedAccess) { .parent = inner, .ref = decl };
expr->type = decl->type;
expr->type = type_add_optional(decl->type, IS_OPTIONAL(inner));
return true;
}

View File

@@ -122,7 +122,7 @@ static inline bool sema_analyse_assert_stmt(SemaContext *context, Ast *statement
case STORAGE_NORMAL:
break;
case STORAGE_WILDCARD:
UNREACHABLE
RETURN_SEMA_ERROR(e, "This value is always rethrown and doesn't have a definite type. This is not valid.");
case STORAGE_VOID:
RETURN_SEMA_ERROR(e, "This expression is of type 'void', did you make a mistake?");
case STORAGE_COMPILE_TIME:

View File

@@ -99,6 +99,10 @@ bool sema_resolve_array_like_len(SemaContext *context, TypeInfo *type_info, Arra
static inline bool sema_check_array_type(SemaContext *context, TypeInfo *original_info, Type *base, TypeInfoKind kind, ArraySize len, Type **result_ref)
{
if (base->type_kind == TYPE_OPTIONAL)
{
RETURN_SEMA_ERROR(original_info, "You cannot form an array with an optional element type.");
}
Type *distinct_base = type_flatten(base);
if (type_is_infer_type(distinct_base))
@@ -585,40 +589,37 @@ static inline bool sema_resolve_type(SemaContext *context, TypeInfo *type_info,
if (!sema_resolve_ptr_type(context, type_info, resolve_kind)) return type_info_poison(type_info);
break;
}
APPEND_QUALIFIERS:
APPEND_QUALIFIERS:;
Type *type = type_no_optional(type_info->type);
switch (kind)
{
case TYPE_COMPRESSED_NONE:
break;
case TYPE_COMPRESSED_PTR:
if (!sema_check_ptr_type(context, type_info, type_info->type)) return type_info_poison(type_info);
type_info->type = type_get_ptr(type_info->type);
if (!sema_check_ptr_type(context, type_info, type)) return type_info_poison(type_info);
type = type_get_ptr(type);
break;
case TYPE_COMPRESSED_SUB:
if (!sema_check_array_type(context, type_info, type_info->type, TYPE_INFO_SLICE, 0, &type_info->type)) return type_info_poison(type_info);
if (!sema_check_array_type(context, type_info, type, TYPE_INFO_SLICE, 0, &type)) return type_info_poison(type_info);
break;
case TYPE_COMPRESSED_SUBPTR:
if (!sema_check_array_type(context, type_info, type_info->type, TYPE_INFO_SLICE, 0, &type_info->type)) return type_info_poison(type_info);
type_info->type = type_get_ptr(type_info->type);
if (!sema_check_array_type(context, type_info, type, TYPE_INFO_SLICE, 0, &type)) return type_info_poison(type_info);
type = type_get_ptr(type);
break;
case TYPE_COMPRESSED_PTRPTR:
if (!sema_check_ptr_type(context, type_info, type_info->type)) return type_info_poison(type_info);
type_info->type = type_get_ptr(type_get_ptr(type_info->type));
if (!sema_check_ptr_type(context, type_info, type)) return type_info_poison(type_info);
type = type_get_ptr(type_get_ptr(type));
break;
case TYPE_COMPRESSED_PTRSUB:
if (!sema_check_ptr_type(context, type_info, type_info->type)) return type_info_poison(type_info);
type_info->type = type_get_slice(type_get_ptr(type_info->type));
if (!sema_check_ptr_type(context, type_info, type)) return type_info_poison(type_info);
type = type_get_slice(type_get_ptr(type));
break;
case TYPE_COMPRESSED_SUBSUB:
if (!sema_check_array_type(context, type_info, type_info->type, TYPE_INFO_SLICE, 0, &type_info->type)) return type_info_poison(type_info);
type_info->type = type_get_slice(type_info->type);
if (!sema_check_array_type(context, type_info, type, TYPE_INFO_SLICE, 0, &type)) return type_info_poison(type_info);
type = type_get_slice(type);
break;
}
if (type_info->optional)
{
Type *type = type_info->type;
if (!type_is_optional(type)) type_info->type = type_get_optional(type);
}
type_info->type = type_add_optional(type, type_info->optional || type_is_optional(type_info->type));
type_info->resolve_status = RESOLVE_DONE;
return true;
}