Bug with casting anyfault to error.

This commit is contained in:
Christoffer Lerno
2024-09-15 00:55:22 +02:00
parent e6d1d66c8f
commit bca44d1c14
4 changed files with 160 additions and 8 deletions

View File

@@ -26,6 +26,7 @@
- Asserts are now correctly included and traced in when running tests.
- Use atexit to fix finalizers on Windows #1361.
- Fix bugs in "trap-on-wrap" #1434.
- Bug with casting anyfault to error.
### Stdlib changes
- Additional init functions for hashmap.

View File

@@ -1127,6 +1127,22 @@ static bool rule_explicit_ok(CastContext *cc, bool is_explicit, bool silent)
}
static bool rule_anyfault_to_fault(CastContext *cc, bool is_explicit, bool is_silent)
{
if (!is_explicit)
{
if (is_silent) return false;
return sema_cast_error(cc, rule_anyfault_to_fault(cc, true, true), false);
}
Expr *expr = cc->expr;
if (!expr_is_const_fault(expr)) return true;
if (type_flatten(cc->to) == expr->const_expr.enum_err_val->type) return true;
if (is_silent) return false;
RETURN_CAST_ERROR(expr, "This expression is known at compile time to be a fault of type %s, so it cannot be cast to %s.",
type_quoted_error_string(expr->const_expr.enum_err_val->type),
type_quoted_error_string(cc->to_type));
}
static bool rule_int_to_float(CastContext *cc, bool is_explicit, bool is_silent)
{
if (is_explicit) return true;
@@ -1810,14 +1826,9 @@ static void cast_untyped_list_to_other(SemaContext *context, Expr *expr, Type *t
static void cast_anyfault_to_fault(SemaContext *context, Expr *expr, Type *type)
{
if (insert_runtime_cast_unless_const(expr, CAST_EUER, type) && expr->const_expr.const_kind == CONST_ERR) return;
if (insert_runtime_cast_unless_const(expr, CAST_EUER, type) || !expr_is_const_fault(expr)) return;
Decl *value = expr->const_expr.enum_err_val;
if (value->type != type)
{
expr->const_expr.const_kind = CONST_POINTER;
expr->const_expr.ptr = 0;
}
assert(value->type == type);
assert(value->type != type);
expr->type = type;
}
@@ -2134,6 +2145,7 @@ static void cast_typeid_to_bool(SemaContext *context, Expr *expr, Type *to_type)
#define RWIDE &rule_widen_narrow /* Widen / narrow conversion of int/float */
#define RINFL &rule_int_to_float /* Simple expressions, check sizes */
#define ROKOK &rule_all_ok /* Always works */
#define RAFFA &rule_anyfault_to_fault /* Runtime check that it's valid, otherwise ok if explicit */
#define RINPT &rule_int_to_ptr /* Int -> ptr (explicit + size match) */
#define RPTIN &rule_ptr_to_int /* Ptr -> int (explicit + size match) */
#define RINBS &rule_int_to_bits /* Int -> bits (explicit + int + size match) */
@@ -2185,7 +2197,7 @@ CastRule cast_rules[CONV_LAST + 1][CONV_LAST + 1] = {
{REXPL, _NO__, _NO__, REXPL, _NO__, _NO__, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // ENUM
{REXPL, _NO__, REXPL, RPTIN, _NO__, _NO__, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RPTPT, _NO__, _NO__, ROKOK, _NO__, _NO__, _NO__}, // FUNC
{REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NA__, _NO__, REXPL, REXPL, _NO__, _NO__}, // TYPEID
{REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, REXPL, _NO__, _NO__, _NO__, _NA__, REXPL, REXPL, _NO__, _NO__}, // ANYFAULT
{REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, RAFFA, _NO__, _NO__, _NO__, _NA__, REXPL, REXPL, _NO__, _NO__}, // ANYFAULT
{REXPL, _NO__, REXPL, RPTIN, _NO__, ROKOK, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, ROKOK, _NO__, _NO__, ROKOK, _NO__, _NO__, _NA__, ROKOK, _NO__, _NO__}, // VOIDPTR
{REXPL, _NO__, REXPL, RPTIN, _NO__, RPTPT, RAPSL, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, ROKOK, _NO__, _NO__, _NO__, _NO__, _NO__, ROKOK, RPTPT, RPTFE, _NO__}, // ARRPTR
{_NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // INFERRED

View File

@@ -0,0 +1,123 @@
// #target: macos-x64
module test;
import std::io;
fault HadError
{
BAD_STUFF,
WORSE_STUFF,
THE_WORST_STUFF
}
fn int exitcode(anyfault error)
{
switch ((HadError)error)
{
case BAD_STUFF: return 64;
case WORSE_STUFF: return 65;
case THE_WORST_STUFF: return 66;
default: return 70;
}
}
fn void! canFail()
{
if (34 + 35 == 69)
{
return HadError.BAD_STUFF?;
}
}
fn int main(String[] args)
{
if (catch err = canFail())
{
return exitcode(err);
}
return 0;
}
/* #expect: test.ll
define i32 @test.exitcode(i64 %0) #0 {
entry:
%switch = alloca i64, align 8
store i64 %0, ptr %switch, align 8
br label %switch.entry
switch.entry: ; preds = %entry
%1 = load i64, ptr %switch, align 8
%eq = icmp eq i64 ptrtoint (ptr @"test.HadError$BAD_STUFF" to i64), %1
br i1 %eq, label %switch.case, label %next_if
switch.case: ; preds = %switch.entry
ret i32 64
next_if: ; preds = %switch.entry
%eq1 = icmp eq i64 ptrtoint (ptr @"test.HadError$WORSE_STUFF" to i64), %1
br i1 %eq1, label %switch.case2, label %next_if3
switch.case2: ; preds = %next_if
ret i32 65
next_if3: ; preds = %next_if
%eq4 = icmp eq i64 ptrtoint (ptr @"test.HadError$THE_WORST_STUFF" to i64), %1
br i1 %eq4, label %switch.case5, label %next_if6
switch.case5: ; preds = %next_if3
ret i32 66
next_if6: ; preds = %next_if3
br label %switch.default
switch.default: ; preds = %next_if6
ret i32 70
}
define i64 @test.canFail() #0 {
entry:
br label %if.then
if.then: ; preds = %entry
ret i64 ptrtoint (ptr @"test.HadError$BAD_STUFF" to i64)
}
define i32 @test.main(ptr %0, i64 %1) #0 {
entry:
%args = alloca %"char[][]", align 8
%err = alloca i64, align 8
store ptr %0, ptr %args, align 8
%ptradd = getelementptr inbounds i8, ptr %args, i64 8
store i64 %1, ptr %ptradd, align 8
br label %testblock
testblock: ; preds = %entry
%2 = call i64 @test.canFail()
%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 %assign_optional
assign_optional: ; preds = %testblock
store i64 %2, ptr %err, align 8
br label %end_block
after_check: ; preds = %testblock
store i64 0, ptr %err, align 8
br label %end_block
end_block: ; preds = %after_check, %assign_optional
%4 = load i64, ptr %err, align 8
%neq = icmp ne i64 %4, 0
br i1 %neq, label %if.then, label %if.exit
if.then: ; preds = %end_block
%5 = load i64, ptr %err, align 8
%6 = call i32 @test.exitcode(i64 %5)
ret i32 %6
if.exit: ; preds = %end_block
ret i32 0
}

View File

@@ -0,0 +1,16 @@
module exitcodes;
import std::io;
fault HadError
{
BAD_STUFF,
WORSE_STUFF,
THE_WORST_STUFF
}
fn int main(String[] args)
{
HadError err = HadError.BAD_STUFF;
SearchResult res = (SearchResult)(anyfault)HadError.BAD_STUFF; // #error: This expression is known at compile time
return 0;
}