commit 39d4cd337cc14b36482c00d837f112a3ef3b2359
parent 62c4357d7aba7223c18cf032cc8005d30414ea44
Author: Ember Sawady <ecs@d2evs.net>
Date: Sun, 27 Nov 2022 01:08:58 +0000
Add dedicated error type
In order to avoid spurious errors
Signed-off-by: Ember Sawady <ecs@d2evs.net>
Diffstat:
11 files changed, 86 insertions(+), 47 deletions(-)
diff --git a/include/types.h b/include/types.h
@@ -42,6 +42,8 @@ enum type_storage {
STORAGE_FCONST,
STORAGE_ICONST,
STORAGE_RCONST,
+ // For internal use only
+ STORAGE_ERROR,
};
struct type;
@@ -201,6 +203,7 @@ extern struct type
// Primitive
builtin_type_bool,
builtin_type_char,
+ builtin_type_error,
builtin_type_f32,
builtin_type_f64,
builtin_type_i8,
diff --git a/src/check.c b/src/check.c
@@ -69,9 +69,7 @@ verror(struct context *ctx, const struct location loc, struct expression *expr,
{
if (expr) {
expr->type = EXPR_CONSTANT;
- // TODO: We should have a separate type for errors, to avoid
- // spurious errors
- expr->result = &builtin_type_void;
+ expr->result = &builtin_type_error;
expr->terminates = false;
expr->loc = loc;
}
@@ -848,6 +846,8 @@ type_promote(struct type_store *store,
return b;
}
return NULL;
+ case STORAGE_ERROR:
+ return b;
// Cannot be promoted
case STORAGE_BOOL:
case STORAGE_FUNCTION:
@@ -1711,6 +1711,7 @@ check_expr_constant(struct context *ctx,
break;
case STORAGE_CHAR:
case STORAGE_ENUM:
+ case STORAGE_ERROR:
case STORAGE_UINTPTR:
case STORAGE_ALIAS:
case STORAGE_FUNCTION:
@@ -2879,7 +2880,7 @@ check_expr_tuple(struct context *ctx,
} else {
expr->result = type_store_lookup_tuple(ctx->store,
aexpr->loc, &result);
- if (expr->result == &builtin_type_void) {
+ if (expr->result == &builtin_type_error) {
// an error occured
return;
}
@@ -3033,7 +3034,7 @@ check_expr_vaend(struct context *ctx,
"Expected vaend operand to be valist");
return;
}
- expr->result = &builtin_type_void;
+ expr->result = &builtin_type_error;
}
void
diff --git a/src/eval.c b/src/eval.c
@@ -134,6 +134,7 @@ itrunc(const struct type *type, uintmax_t val)
return itrunc(type_dealias(type), val);
case STORAGE_ENUM:
return itrunc(type->alias.type, val);
+ case STORAGE_ERROR:
case STORAGE_F32:
case STORAGE_F64:
case STORAGE_FCONST:
@@ -406,6 +407,7 @@ eval_const(struct context *ctx, struct expression *in, struct expression *out)
assert(0); // TODO
case STORAGE_BOOL:
case STORAGE_CHAR:
+ case STORAGE_ERROR:
case STORAGE_F32:
case STORAGE_F64:
case STORAGE_FCONST:
@@ -602,6 +604,7 @@ eval_cast(struct context *ctx, struct expression *in, struct expression *out)
case STORAGE_UNION:
case STORAGE_VALIST:
assert(0); // Invariant
+ case STORAGE_ERROR:
case STORAGE_VOID:
break; // no-op
}
@@ -662,6 +665,7 @@ constant_default(struct context *ctx, struct expression *v)
{
struct expression b = {0};
switch (type_dealias(v->result)->storage) {
+ case STORAGE_ERROR:
case STORAGE_POINTER:
case STORAGE_I16:
case STORAGE_I32:
diff --git a/src/gen.c b/src/gen.c
@@ -1801,6 +1801,7 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr)
break;
case STORAGE_ALIAS:
case STORAGE_BOOL:
+ case STORAGE_ERROR:
case STORAGE_FCONST:
case STORAGE_FUNCTION:
case STORAGE_ICONST:
@@ -3756,6 +3757,7 @@ gen_data_item(struct gen_context *ctx, struct expression *expr,
break;
case STORAGE_UNION:
case STORAGE_ALIAS:
+ case STORAGE_ERROR:
case STORAGE_FCONST:
case STORAGE_FUNCTION:
case STORAGE_ICONST:
diff --git a/src/lex.c b/src/lex.c
@@ -1181,6 +1181,7 @@ token_str(const struct token *tok)
case STORAGE_BOOL:
case STORAGE_CHAR:
case STORAGE_ENUM:
+ case STORAGE_ERROR:
case STORAGE_FUNCTION:
case STORAGE_POINTER:
case STORAGE_NULL:
diff --git a/src/parse.c b/src/parse.c
@@ -852,6 +852,8 @@ parse_constant(struct lexer *lexer)
case STORAGE_UNION:
case STORAGE_VALIST:
assert(0); // Handled in a different nonterminal
+ case STORAGE_ERROR:
+ assert(0); // Invariant
}
return exp;
}
diff --git a/src/qinstr.c b/src/qinstr.c
@@ -69,6 +69,7 @@ store_for_type(struct gen_context *ctx, const struct type *type)
case STORAGE_ALIAS:
return store_for_type(ctx, type->alias.type);
case STORAGE_ARRAY:
+ case STORAGE_ERROR:
case STORAGE_FCONST:
case STORAGE_FUNCTION:
case STORAGE_ICONST:
@@ -136,6 +137,7 @@ load_for_type(struct gen_context *ctx, const struct type *type)
case STORAGE_ALIAS:
return load_for_type(ctx, type->alias.type);
case STORAGE_ARRAY:
+ case STORAGE_ERROR:
case STORAGE_FCONST:
case STORAGE_FUNCTION:
case STORAGE_ICONST:
diff --git a/src/qtype.c b/src/qtype.c
@@ -158,6 +158,7 @@ aggregate_lookup(struct gen_context *ctx, const struct type *type)
}
break;
case STORAGE_ENUM:
+ case STORAGE_ERROR:
case STORAGE_ALIAS:
case STORAGE_CHAR:
case STORAGE_I8:
@@ -238,6 +239,7 @@ qtype_lookup(struct gen_context *ctx,
return ctx->arch.ptr;
case STORAGE_VALIST:
return ctx->arch.ptr;
+ case STORAGE_ERROR:
case STORAGE_VOID:
abort(); // Invariant
case STORAGE_FCONST:
@@ -293,6 +295,8 @@ type_is_aggregate(const struct type *type)
case STORAGE_RCONST:
lower_const(type, NULL);
return false;
+ case STORAGE_ERROR:
+ assert(0); // Invariant
}
assert(0); // Unreachable
}
diff --git a/src/type_store.c b/src/type_store.c
@@ -79,6 +79,8 @@ builtin_type_for_storage(enum type_storage storage, bool is_const)
return is_const ? &builtin_type_const_bool : &builtin_type_bool;
case STORAGE_CHAR:
return is_const ? &builtin_type_const_char : &builtin_type_char;
+ case STORAGE_ERROR:
+ return &builtin_type_error;
case STORAGE_F32:
return is_const ? &builtin_type_const_f32 : &builtin_type_f32;
case STORAGE_F64:
@@ -367,7 +369,7 @@ tagged_or_atagged_member(struct type_store *store,
error(store->check_context, _atype->loc,
"Unknown object '%s'",
identifier_unparse(&_atype->alias));
- *type = &builtin_type_void;
+ *type = &builtin_type_error;
return;
}
if (obj->otype != O_SCAN) {
@@ -378,7 +380,7 @@ tagged_or_atagged_member(struct type_store *store,
error(store->check_context, _atype->loc,
"Object '%s' is not a type",
identifier_unparse(&obj->ident));
- *type = &builtin_type_void;
+ *type = &builtin_type_error;
return;
}
}
@@ -389,7 +391,7 @@ tagged_or_atagged_member(struct type_store *store,
error(store->check_context, _atype->loc,
"Object '%s' is not a type",
identifier_unparse(&obj->ident));
- *type = &builtin_type_void;
+ *type = &builtin_type_error;
return;
}
_atype = idecl->decl.type.type;
@@ -520,7 +522,7 @@ tagged_init_from_atype(struct type_store *store,
collect_atagged_memb(store, tu, &atype->tagged_union, &i);
tagged_init(store, type, tu, nmemb);
if (!enforce_tagged_invariants(store, atype->loc, type)) {
- *type = builtin_type_void;
+ *type = builtin_type_error;
};
}
@@ -646,10 +648,10 @@ type_init_from_atype(struct type_store *store,
type->storage = atype->storage;
type->flags = atype->flags;
- // TODO: Use a dedicated error type instead of void for errors
const struct scope_object *obj = NULL;
const struct type *builtin;
switch (type->storage) {
+ case STORAGE_ERROR:
case STORAGE_FCONST:
case STORAGE_ICONST:
case STORAGE_RCONST:
@@ -686,7 +688,7 @@ type_init_from_atype(struct type_store *store,
error(store->check_context, atype->loc,
"Unresolvable identifier '%s'",
identifier_unparse(&atype->alias));
- *type = builtin_type_void;
+ *type = builtin_type_error;
return (struct dimensions){0};
}
@@ -709,7 +711,7 @@ type_init_from_atype(struct type_store *store,
error(store->check_context, atype->loc,
"Object '%s' is not a type",
identifier_unparse(&obj->ident));
- *type = builtin_type_void;
+ *type = builtin_type_error;
return (struct dimensions){0};
}
@@ -742,13 +744,13 @@ type_init_from_atype(struct type_store *store,
if (type->array.length != SIZE_UNDEFINED && memb.size == 0) {
error(store->check_context, atype->loc,
"Type of size 0 is not a valid array member");
- *type = builtin_type_void;
+ *type = builtin_type_error;
return (struct dimensions){0};
}
if (memb.size == SIZE_UNDEFINED) {
error(store->check_context, atype->loc,
"Type of undefined size is not a valid array member");
- *type = builtin_type_void;
+ *type = builtin_type_error;
return (struct dimensions){0};
}
@@ -777,13 +779,13 @@ type_init_from_atype(struct type_store *store,
if (param->type->size == 0) {
error(store->check_context, atype->loc,
"Function parameter types must have nonzero size");
- *type = builtin_type_void;
+ *type = builtin_type_error;
return (struct dimensions){0};
}
if (param->type->size == SIZE_UNDEFINED) {
error(store->check_context, atype->loc,
"Function parameter types must have defined size");
- *type = builtin_type_void;
+ *type = builtin_type_error;
return (struct dimensions){0};
}
if (atype->func.variadism == VARIADISM_HARE
@@ -970,7 +972,7 @@ type_store_lookup_pointer(struct type_store *store, struct location loc,
if (referent->storage == STORAGE_NULL) {
error(store->check_context, loc,
"Null type not allowed in this context");
- return &builtin_type_void;
+ return &builtin_type_error;
}
referent = lower_const(referent, NULL);
@@ -993,7 +995,7 @@ type_store_lookup_array(struct type_store *store, struct location loc,
if (members->storage == STORAGE_NULL) {
error(store->check_context, loc,
"Null type not allowed in this context");
- return &builtin_type_void;
+ return &builtin_type_error;
}
members = lower_const(members, NULL);
// XXX: I'm not sure these checks are *exactly* right, we might still
@@ -1001,12 +1003,12 @@ type_store_lookup_array(struct type_store *store, struct location loc,
if (len != SIZE_UNDEFINED && members->size == 0) {
error(store->check_context, loc,
"Type of size 0 is not a valid array member");
- return &builtin_type_void;
+ return &builtin_type_error;
}
if (members->size == SIZE_UNDEFINED) {
error(store->check_context, loc,
"Type of undefined size is not a valid member of a bounded array");
- return &builtin_type_void;
+ return &builtin_type_error;
}
assert(members->align != 0);
assert(members->align != ALIGN_UNDEFINED);
@@ -1033,18 +1035,18 @@ type_store_lookup_slice(struct type_store *store, struct location loc,
if (members->storage == STORAGE_NULL) {
error(store->check_context, loc,
"Null type not allowed in this context");
- return &builtin_type_void;
+ return &builtin_type_error;
}
members = lower_const(members, NULL);
if (members->size == 0) {
error(store->check_context, loc,
"Type of size 0 is not a valid slice member");
- return &builtin_type_void;
+ return &builtin_type_error;
}
if (members->size == SIZE_UNDEFINED) {
error(store->check_context, loc,
"Type of undefined size is not a valid slice member");
- return &builtin_type_void;
+ return &builtin_type_error;
}
assert(members->align != 0);
assert(members->align != ALIGN_UNDEFINED);
@@ -1109,7 +1111,7 @@ type_store_lookup_tagged(struct type_store *store, struct location loc,
{
const struct type *type = lookup_tagged(store, tags);
if (!enforce_tagged_invariants(store, loc, type)) {
- return &builtin_type_void;
+ return &builtin_type_error;
}
return type_store_lookup_type(store, type);
}
@@ -1158,18 +1160,18 @@ type_store_lookup_tuple(struct type_store *store, struct location loc,
if (t->type->storage == STORAGE_NULL) {
error(store->check_context, loc,
"Null type not allowed in this context");
- return &builtin_type_void;
+ return &builtin_type_error;
}
t->type = lower_const(t->type, NULL);
if (t->type->size == 0) {
error(store->check_context, loc,
"Type of size 0 is not a valid tuple member");
- return &builtin_type_void;
+ return &builtin_type_error;
}
if (t->type->size == SIZE_UNDEFINED) {
error(store->check_context, loc,
"Type of undefined size is not a valid tuple member");
- return &builtin_type_void;
+ return &builtin_type_error;
}
assert(t->type->align != 0);
assert(t->type->align != ALIGN_UNDEFINED);
@@ -1200,7 +1202,7 @@ type_store_lookup_enum(struct type_store *store, const struct ast_type *atype,
&& type.alias.type->storage != STORAGE_RUNE) {
error(store->check_context, atype->loc,
"Enum storage must be an integer or rune");
- return &builtin_type_void;
+ return &builtin_type_error;
}
type.size = type.alias.type->size;
type.align = type.alias.type->size;
diff --git a/src/typedef.c b/src/typedef.c
@@ -169,6 +169,7 @@ emit_const(const struct expression *expr, FILE *out)
assert(0); // TODO
case STORAGE_ALIAS:
case STORAGE_CHAR:
+ case STORAGE_ERROR:
case STORAGE_FUNCTION:
case STORAGE_POINTER:
case STORAGE_VALIST:
@@ -235,6 +236,7 @@ emit_type(const struct type *type, FILE *out)
switch (type->storage) {
case STORAGE_BOOL:
case STORAGE_CHAR:
+ case STORAGE_ERROR:
case STORAGE_F32:
case STORAGE_F64:
case STORAGE_FCONST:
diff --git a/src/types.c b/src/types.c
@@ -119,6 +119,8 @@ type_storage_unparse(enum type_storage storage)
return "f32";
case STORAGE_F64:
return "f64";
+ case STORAGE_ERROR:
+ return "invalid";
case STORAGE_FCONST:
return "fconst";
case STORAGE_FUNCTION:
@@ -202,6 +204,7 @@ type_is_integer(const struct type *type)
return false;
case STORAGE_CHAR:
case STORAGE_ENUM:
+ case STORAGE_ERROR:
case STORAGE_I8:
case STORAGE_I16:
case STORAGE_I32:
@@ -243,6 +246,7 @@ type_is_numeric(const struct type *type)
case STORAGE_NULL:
case STORAGE_VALIST:
return false;
+ case STORAGE_ERROR:
case STORAGE_ENUM:
case STORAGE_I8:
case STORAGE_I16:
@@ -272,7 +276,8 @@ type_is_float(const struct type *type)
{
type = type_dealias(type);
return type->storage == STORAGE_F32 || type->storage == STORAGE_F64
- || type->storage == STORAGE_FCONST;
+ || type->storage == STORAGE_FCONST
+ || type->storage == STORAGE_ERROR;
}
bool
@@ -286,6 +291,7 @@ type_is_signed(const struct type *type)
case STORAGE_VOID:
case STORAGE_ARRAY:
case STORAGE_ENUM:
+ case STORAGE_ERROR: // XXX?
case STORAGE_FUNCTION:
case STORAGE_POINTER:
case STORAGE_SLICE:
@@ -343,6 +349,7 @@ type_hash(const struct type *type)
switch (type->storage) {
case STORAGE_BOOL:
case STORAGE_CHAR:
+ case STORAGE_ERROR:
case STORAGE_F32:
case STORAGE_F64:
case STORAGE_I8:
@@ -855,6 +862,8 @@ type_is_assignable(const struct type *to, const struct type *from)
case STORAGE_UNION:
case STORAGE_VALIST:
return false;
+ case STORAGE_ERROR:
+ return true;
}
assert(0); // Unreachable
@@ -970,6 +979,8 @@ type_is_castable(const struct type *to, const struct type *from)
case STORAGE_UNION:
case STORAGE_VALIST:
return false;
+ case STORAGE_ERROR:
+ return true;
case STORAGE_TAGGED:
case STORAGE_ALIAS:
assert(0); // Handled above
@@ -1067,24 +1078,24 @@ builtin_types_init(const char *target)
exit(EXIT_FAILURE);
}
struct type *builtins[] = {
- &builtin_type_bool, &builtin_type_char, &builtin_type_f32,
- &builtin_type_f64, &builtin_type_i8, &builtin_type_i16,
- &builtin_type_i32, &builtin_type_i64, &builtin_type_int,
- &builtin_type_u8, &builtin_type_u16, &builtin_type_u32,
- &builtin_type_u64, &builtin_type_uint, &builtin_type_uintptr,
- &builtin_type_null, &builtin_type_rune, &builtin_type_size,
- &builtin_type_void, &builtin_type_const_bool,
- &builtin_type_const_char, &builtin_type_const_f32,
- &builtin_type_const_f64, &builtin_type_const_i8,
- &builtin_type_const_i16, &builtin_type_const_i32,
- &builtin_type_const_i64, &builtin_type_const_int,
- &builtin_type_const_u8, &builtin_type_const_u16,
- &builtin_type_const_u32, &builtin_type_const_u64,
- &builtin_type_const_uint, &builtin_type_const_uintptr,
- &builtin_type_const_rune, &builtin_type_const_size,
- &builtin_type_const_void, &builtin_type_ptr_const_char,
- &builtin_type_str, &builtin_type_const_str,
- &builtin_type_valist,
+ &builtin_type_bool, &builtin_type_char, &builtin_type_error,
+ &builtin_type_f32, &builtin_type_f64, &builtin_type_i8,
+ &builtin_type_i16, &builtin_type_i32, &builtin_type_i64,
+ &builtin_type_int, &builtin_type_u8, &builtin_type_u16,
+ &builtin_type_u32, &builtin_type_u64, &builtin_type_uint,
+ &builtin_type_uintptr, &builtin_type_null, &builtin_type_rune,
+ &builtin_type_size, &builtin_type_void,
+ &builtin_type_const_bool, &builtin_type_const_char,
+ &builtin_type_const_f32, &builtin_type_const_f64,
+ &builtin_type_const_i8, &builtin_type_const_i16,
+ &builtin_type_const_i32, &builtin_type_const_i64,
+ &builtin_type_const_int, &builtin_type_const_u8,
+ &builtin_type_const_u16, &builtin_type_const_u32,
+ &builtin_type_const_u64, &builtin_type_const_uint,
+ &builtin_type_const_uintptr, &builtin_type_const_rune,
+ &builtin_type_const_size, &builtin_type_const_void,
+ &builtin_type_ptr_const_char, &builtin_type_str,
+ &builtin_type_const_str, &builtin_type_valist,
};
for (size_t i = 0; i < sizeof(builtins) / sizeof(builtins[0]); ++i) {
builtins[i]->id = type_hash(builtins[i]);
@@ -1102,6 +1113,11 @@ builtin_type_char = {
.size = 1,
.align = 1,
},
+builtin_type_error = {
+ .storage = STORAGE_ERROR,
+ .size = 1,
+ .align = 1,
+},
builtin_type_f32 = {
.storage = STORAGE_F32,
.size = 4,