Add tentative ".ordinal" on faults. Allow anyerr and fault to be initialized with null.

This commit is contained in:
Christoffer Lerno
2023-03-15 14:32:00 +01:00
parent 3cb94a2857
commit e2b9a35dfe
11 changed files with 89 additions and 11 deletions

View File

@@ -847,6 +847,7 @@ typedef enum
ACCESS_TYPEOFANY,
ACCESS_ENUMNAME,
ACCESS_FAULTNAME,
ACCESS_FAULTORDINAL,
} BuiltinAccessKind;
typedef struct

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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, "");
}

View File

@@ -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

View File

@@ -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;

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.109"
#define COMPILER_VERSION "0.4.110"

View File

@@ -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

View File

@@ -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

View 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);
}