mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Add tentative ".ordinal" on faults. Allow anyerr and fault to be initialized with null.
This commit is contained in:
@@ -847,6 +847,7 @@ typedef enum
|
||||
ACCESS_TYPEOFANY,
|
||||
ACCESS_ENUMNAME,
|
||||
ACCESS_FAULTNAME,
|
||||
ACCESS_FAULTORDINAL,
|
||||
} BuiltinAccessKind;
|
||||
|
||||
typedef struct
|
||||
|
||||
@@ -185,6 +185,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
||||
case ACCESS_FAULTNAME:
|
||||
case ACCESS_LEN:
|
||||
case ACCESS_PTR:
|
||||
case ACCESS_FAULTORDINAL:
|
||||
break;
|
||||
case ACCESS_TYPEOFANY:
|
||||
if (eval_kind != CONSTANT_EVAL_NO_SIDE_EFFECTS) return false;
|
||||
|
||||
@@ -6047,6 +6047,37 @@ static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Ex
|
||||
assert(be_value->type->type_kind == TYPE_SUBARRAY);
|
||||
llvm_emit_subarray_pointer(c, be_value, be_value);
|
||||
return;
|
||||
case ACCESS_FAULTORDINAL:
|
||||
{
|
||||
LLVMBasicBlockRef current_block = llvm_get_current_block_if_in_use(c);
|
||||
if (!current_block)
|
||||
{
|
||||
llvm_value_set(be_value, llvm_get_zero(c, type_usz), type_usz);
|
||||
return;
|
||||
}
|
||||
Type *inner_type = type_flatten(inner->type);
|
||||
assert(inner_type->type_kind == TYPE_FAULTTYPE);
|
||||
llvm_value_rvalue(c, be_value);
|
||||
BEValue zero;
|
||||
LLVMBasicBlockRef exit_block = llvm_basic_block_new(c, "faultordinal_exit");
|
||||
LLVMBasicBlockRef ok_block = llvm_basic_block_new(c, "faultordinal_found");
|
||||
BEValue check;
|
||||
llvm_emit_int_comp_zero(c, &check, be_value, BINARYOP_EQ);
|
||||
llvm_emit_cond_br(c, &check, exit_block, ok_block);
|
||||
llvm_emit_block(c, ok_block);
|
||||
LLVMValueRef fault_data = LLVMBuildIntToPtr(c->builder, be_value->value,
|
||||
c->ptr_type, "");
|
||||
LLVMValueRef ptr = LLVMBuildStructGEP2(c->builder, c->fault_type, fault_data, 2, "");
|
||||
LLVMValueRef ordinal = llvm_load_abi_alignment(c, type_usz, ptr, "");
|
||||
llvm_emit_br(c, exit_block);
|
||||
llvm_emit_block(c, exit_block);
|
||||
LLVMValueRef phi = LLVMBuildPhi(c->builder, c->size_type, "faultname");
|
||||
LLVMValueRef values[] = { llvm_const_int(c, type_usz, 0), ordinal };
|
||||
LLVMBasicBlockRef blocks[] = { current_block, ok_block };
|
||||
LLVMAddIncoming(phi, values, blocks, 2);
|
||||
llvm_value_set(be_value, phi, type_usz);
|
||||
return;
|
||||
}
|
||||
case ACCESS_FAULTNAME:
|
||||
{
|
||||
Type *inner_type = type_no_optional(inner->type)->canonical;
|
||||
|
||||
@@ -23,8 +23,8 @@ static inline LLVMTypeRef create_introspection_type(GenContext *c)
|
||||
static inline LLVMTypeRef create_fault_type(GenContext *c)
|
||||
{
|
||||
LLVMTypeRef type = LLVMStructCreateNamed(c->context, ".fault");
|
||||
LLVMTypeRef fault_type[] = { c->typeid_type, c->chars_type };
|
||||
LLVMStructSetBody(type, fault_type, 2, false);
|
||||
LLVMTypeRef fault_type[] = { c->typeid_type, c->chars_type, c->size_type };
|
||||
LLVMStructSetBody(type, fault_type, 3, false);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
@@ -602,10 +602,11 @@ static LLVMValueRef llvm_get_introspection_for_fault(GenContext *c, Type *type)
|
||||
LLVMSetAlignment(global_name, LLVMPreferredAlignmentOfGlobal(c->target_data, global_name));
|
||||
LLVMSetGlobalConstant(global_name, 1);
|
||||
|
||||
LLVMValueRef vals[2] = { LLVMBuildPtrToInt(c->builder, ref, c->typeid_type, ""),
|
||||
llvm_emit_string_const(c, val->name, ".fault") };
|
||||
LLVMValueRef vals[3] = { LLVMBuildPtrToInt(c->builder, ref, c->typeid_type, ""),
|
||||
llvm_emit_string_const(c, val->name, ".fault"),
|
||||
llvm_const_int(c, type_usz, val->enum_constant.ordinal + 1 )};
|
||||
|
||||
LLVMSetInitializer(global_name, llvm_get_struct_named(c->fault_type, vals, 2));
|
||||
LLVMSetInitializer(global_name, llvm_get_struct_named(c->fault_type, vals, 3));
|
||||
llvm_set_linkonce(c, global_name);
|
||||
val->backend_ref = LLVMBuildPtrToInt(c->builder, global_name, c->typeid_type, "");
|
||||
}
|
||||
|
||||
@@ -787,6 +787,7 @@ RETRY:
|
||||
case ACCESS_TYPEOFANY:
|
||||
case ACCESS_ENUMNAME:
|
||||
case ACCESS_FAULTNAME:
|
||||
case ACCESS_FAULTORDINAL:
|
||||
// For the rest, just check size.
|
||||
goto CHECK_SIZE;
|
||||
}
|
||||
@@ -1003,6 +1004,13 @@ static bool cast_from_pointer(SemaContext *context, Expr *expr, Type *from, Type
|
||||
return cast_with_optional(expr, to_type, add_optional);
|
||||
}
|
||||
return sema_error_cannot_convert(expr, to_type, true, silent);
|
||||
case TYPE_FAULTTYPE:
|
||||
case TYPE_ANYERR:
|
||||
if (expr_is_const_pointer(expr) && !expr->const_expr.ptr)
|
||||
{
|
||||
expr_rewrite_to_const_zero(expr, to_type);
|
||||
return true;
|
||||
}
|
||||
case TYPE_OPTIONAL_ANY:
|
||||
case TYPE_OPTIONAL:
|
||||
UNREACHABLE
|
||||
|
||||
@@ -3652,12 +3652,28 @@ CHECK_DEEPER:
|
||||
expr_replace(expr, current_parent);
|
||||
return true;
|
||||
}
|
||||
if (flat_type->type_kind == TYPE_FAULTTYPE)
|
||||
{
|
||||
if (expr_is_const(current_parent))
|
||||
{
|
||||
if (current_parent->const_expr.const_kind == CONST_POINTER)
|
||||
{
|
||||
assert(!current_parent->const_expr.ptr);
|
||||
expr_rewrite_const_int(expr, type_usz, 0);
|
||||
return true;
|
||||
}
|
||||
expr_rewrite_const_int(expr, type_usz, current_parent->const_expr.enum_err_val->enum_constant.ordinal + 1);
|
||||
return true;
|
||||
}
|
||||
expr_rewrite_to_builtin_access(expr, current_parent, ACCESS_FAULTORDINAL, type_usz);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (kw == kw_nameof)
|
||||
{
|
||||
if (flat_type->type_kind == TYPE_ENUM)
|
||||
{
|
||||
if (current_parent->expr_kind == EXPR_CONST)
|
||||
if (expr_is_const(current_parent))
|
||||
{
|
||||
expr_rewrite_to_string(expr, current_parent->const_expr.enum_err_val->name);
|
||||
return true;
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.109"
|
||||
#define COMPILER_VERSION "0.4.110"
|
||||
@@ -18,9 +18,9 @@ fn void main()
|
||||
|
||||
/* #expect: foo.ll
|
||||
|
||||
@"foo.Foo$BAR" = linkonce constant %.fault { i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), %"char[]" { ptr @.fault, i64 3 } }, align 8
|
||||
@"foo.Foo$BAR" = linkonce constant %.fault { i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), %"char[]" { ptr @.fault, i64 3 }, i64 1 }, align 8
|
||||
@.fault = internal constant [4 x i8] c"BAR\00", align 1
|
||||
@"foo.Foo$BAZ" = linkonce constant %.fault { i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), %"char[]" { ptr @.fault.1, i64 3 } }, align 8
|
||||
@"foo.Foo$BAZ" = linkonce constant %.fault { i64 ptrtoint (ptr @"$ct.foo.Foo" to i64), %"char[]" { ptr @.fault.1, i64 3 }, i64 2 }, align 8
|
||||
@.fault.1 = internal constant [4 x i8] c"BAZ\00", align 1
|
||||
@"$ct.foo.Foo" = linkonce constant %.introspect { i8 9, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
|
||||
@.str = private unnamed_addr constant [4 x i8] c"BAR\00", align 1
|
||||
@@ -35,7 +35,6 @@ fn void main()
|
||||
@.str.5 = private unnamed_addr constant [17 x i8] c"Foo.elements: %s\00", align 1
|
||||
@"$ct.long" = linkonce constant %.introspect { i8 2, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
|
||||
|
||||
|
||||
entry:
|
||||
%x = alloca %"String[]", align 8
|
||||
%literal = alloca [2 x %"char[]"], align 16
|
||||
|
||||
@@ -28,7 +28,7 @@ fn void main()
|
||||
%Foo = type { i32, i32 }
|
||||
|
||||
@"$ct.test.Foo" = linkonce constant %.introspect { i8 10, i64 8, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8
|
||||
@"test.MyErr$FOO" = linkonce constant %.fault { i64 ptrtoint (ptr @"$ct.test.MyErr" to i64), %"char[]" { ptr @.fault, i64 3 } }, align 8
|
||||
@"test.MyErr$FOO" = linkonce constant %.fault { i64 ptrtoint (ptr @"$ct.test.MyErr" to i64), %"char[]" { ptr @.fault, i64 3 }, i64 1 }, align 8
|
||||
@"$ct.test.MyErr" = linkonce constant %.introspect { i8 9, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8
|
||||
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
|
||||
@.str.1 = private unnamed_addr constant [17 x i8] c"Not visible: %d\0A\00", align 1
|
||||
|
||||
21
test/unit/regression/faults.c3
Normal file
21
test/unit/regression/faults.c3
Normal file
@@ -0,0 +1,21 @@
|
||||
module faults @test;
|
||||
|
||||
fault Foo
|
||||
{
|
||||
ABC,
|
||||
CDE
|
||||
}
|
||||
|
||||
fn void ordinals()
|
||||
{
|
||||
Foo z = null;
|
||||
assert(z.ordinal == 0);
|
||||
$assert(Foo.ABC.ordinal == 1);
|
||||
$assert(Foo.CDE.ordinal == 2);
|
||||
$assert(((Foo)null).ordinal == 0);
|
||||
Foo x = Foo.CDE;
|
||||
assert(x.ordinal == 2);
|
||||
x = Foo.ABC;
|
||||
assert(x.ordinal == 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user