mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Bug with casting anyfault to error.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
123
test/test_suite/errors/fault_conv.c3t
Normal file
123
test/test_suite/errors/fault_conv.c3t
Normal 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
|
||||
}
|
||||
|
||||
16
test/test_suite/errors/invalid_cast_ct.c3
Normal file
16
test/test_suite/errors/invalid_cast_ct.c3
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user