Improved checks of aliased "void".

This commit is contained in:
Christoffer Lerno
2024-02-26 18:45:55 +01:00
parent 4ba033fc84
commit bae5d9c7f8
10 changed files with 30 additions and 20 deletions

View File

@@ -163,7 +163,7 @@ ABIArgInfo *x86_classify_return(CallABI call, Regs *regs, Type *type)
type = type_lowering(type);
// 2. Void is ignored
if (type == type_void) return abi_arg_ignore();
if (type_is_void(type)) return abi_arg_ignore();
// 3. In the case of a vector or regcall, a homogenous aggregate
// should be passed directly in a register.

View File

@@ -2834,6 +2834,7 @@ INLINE const char *type_invalid_storage_type_name(Type *type)
INLINE bool type_is_invalid_storage_type(Type *type)
{
if (!type) return false;
RETRY:
if (type == type_wildcard_optional) return true;
switch (type->type_kind)
{
@@ -2843,6 +2844,9 @@ INLINE bool type_is_invalid_storage_type(Type *type)
case TYPE_TYPEINFO:
case TYPE_WILDCARD:
return true;
case TYPE_TYPEDEF:
type = type->canonical;
goto RETRY;
default:
return false;
}

View File

@@ -51,6 +51,7 @@ LLVMValueRef llvm_store_to_ptr_aligned(GenContext *c, LLVMValueRef destination,
LLVMValueRef llvm_store(GenContext *c, BEValue *destination, BEValue *value)
{
if (value->type == type_void) return NULL;
assert(!type_is_void(value->type));
assert(llvm_value_is_addr(destination));
return llvm_store_to_ptr_aligned(c, destination->value, value, destination->alignment);
}

View File

@@ -227,8 +227,8 @@ static bool sema_expr_analyse_compare_exchange(SemaContext *context, Expr *expr)
for (int i = 1; i < 3; i++)
{
Expr *arg = args[i];
if (!sema_analyse_expr_rhs(context, pointee == type_void ? NULL : pointee, arg, true, NULL)) return false;
if (pointee == type_void) pointee = arg->type->canonical;
if (!sema_analyse_expr_rhs(context, type_is_void(pointee) ? NULL : pointee, arg, true, NULL)) return false;
if (type_is_void(pointee)) pointee = arg->type->canonical;
if (!type_is_atomic(type_flatten(arg->type)))
{
RETURN_SEMA_ERROR(arg, "%s may not be used with atomics.", type_quoted_error_string(arg->type));

View File

@@ -286,7 +286,7 @@ static bool cast_if_valid(SemaContext *context, Expr *expr, Type *to_type, bool
if (from_type == to_type) return true;
bool is_void_silence = to_type == type_void && is_explicit;
bool is_void_silence = type_is_void(to_type) && is_explicit;
bool add_optional = type_is_optional(to_type) || type_is_optional(from_type);
from_type = type_no_optional(from_type);
to_type = type_no_optional(to_type);

View File

@@ -900,7 +900,7 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,
rtype = rtype_info->type;
if (sig->attrs.nodiscard)
{
if (rtype == type_void)
if (type_is_void(rtype))
{
SEMA_ERROR(rtype_info, "@nodiscard cannot be used on %s returning 'void'.", is_macro ? "macros" : "functions");
return false;
@@ -1565,7 +1565,7 @@ static inline bool sema_analyse_operator_element_at(Decl *method)
TypeInfo *rtype;
Decl **params;
if (!sema_analyse_operator_common(method, &rtype, &params, 2)) return false;
if (rtype->type->canonical == type_void)
if (type_is_void(rtype->type))
{
SEMA_ERROR(rtype, "The return type cannot be 'void'.");
return false;
@@ -2842,7 +2842,7 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *era
SEMA_ERROR(rtype_info, "'@test' and '@benchmark' functions may only return 'void' or 'void!'.");
return decl_poison(decl);
}
if (rtype->canonical == type_void)
if (type_is_void(rtype))
{
rtype_info->type = type_get_optional(rtype);
}
@@ -2856,7 +2856,7 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *era
Type *rtype = rtype_info->type->canonical;
if (sig->attrs.nodiscard)
{
if (rtype == type_void)
if (type_is_void(rtype))
{
SEMA_ERROR(rtype_info, "@nodiscard cannot be used on functions returning 'void'.");
return decl_poison(decl);
@@ -3079,7 +3079,7 @@ bool sema_analyse_decl_type(SemaContext *context, Type *type, SourceSpan span)
break;
}
if (!type_is_optional(type)) return true;
if (type == type_wildcard_optional || type->optional == type_void)
if (type == type_wildcard_optional || type_is_void(type->optional))
{
sema_error_at(span, "The use of 'void!' as a variable type is not permitted, use %s instead.",
type_quoted_error_string(type_anyfault));
@@ -3262,7 +3262,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
{
SEMA_ERROR(init_expr, "No type can be inferred from the optional result.");
}
else if (init_expr->type == type_void)
else if (type_is_void(init_expr->type))
{
SEMA_ERROR(init_expr, "You cannot initialize a value to 'void'.");
}
@@ -3470,7 +3470,7 @@ static bool sema_append_generate_parameterized_name(SemaContext *c, Module *modu
if (!sema_resolve_type_info(c, type_info, RESOLVE_TYPE_DEFAULT)) return false;
Type *type = type_info->type->canonical;
if (type->type_kind == TYPE_OPTIONAL) RETURN_SEMA_ERROR(type_info, "Expected a non-optional type.");
if (type == type_void) RETURN_SEMA_ERROR(type_info, "A 'void' type cannot be used as a parameter type.");
if (type_is_void(type)) RETURN_SEMA_ERROR(type_info, "A 'void' type cannot be used as a parameter type.");
if (type_is_invalid_storage_type(type)) RETURN_SEMA_ERROR(type_info, "Expected a runtime type.");
if (type_is_func_ptr(type))
{

View File

@@ -1596,7 +1596,7 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call
case VARDECL_PARAM:
// foo
if (!sema_analyse_expr_rhs(context, type, arg, true, no_match_ref)) return false;
if (type_no_optional(arg->type) == type_void) RETURN_SEMA_ERROR(arg, "A 'void' value cannot be passed as a parameter.");
if (type_is_void(type_no_optional(arg->type))) RETURN_SEMA_ERROR(arg, "A 'void' value cannot be passed as a parameter.");
if (IS_OPTIONAL(arg)) *optional = true;
if (type_is_invalid_storage_type(arg->type))
{
@@ -1748,7 +1748,7 @@ static inline Type *context_unify_returns(SemaContext *context)
}
// 3. Same type -> we're done.
if (common_type == rtype || (common_type == type_void && rtype == type_wildcard)) continue;
if (common_type == rtype || (type_is_void(common_type) && rtype == type_wildcard)) continue;
// 4. Find the max of the old and new.
Type *max = type_find_max_type(common_type, rtype);
@@ -1783,7 +1783,7 @@ static inline Type *context_unify_returns(SemaContext *context)
Expr *ret_expr = return_stmt->return_stmt.expr;
if (!ret_expr)
{
if (common_type == type_void) continue;
if (type_is_void(common_type)) continue;
context_unify_returns(context);
}
// 8. All casts should work.
@@ -2023,7 +2023,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
Expr *ret_expr = return_stmt->return_stmt.expr;
if (!ret_expr)
{
if (rtype == type_void) continue;
if (type_is_void(rtype)) continue;
SEMA_ERROR(return_stmt, "Expected returning a value of type %s.", type_quoted_error_string(rtype));
goto EXIT_FAIL;
}
@@ -5977,7 +5977,7 @@ static inline bool sema_expr_analyse_deref(SemaContext *context, Expr *expr, boo
RETURN_SEMA_ERROR(inner, "Cannot dereference a value of type %s, it must be a pointer.",
type_quoted_error_string(inner_type_nofail));
}
if (canonical->pointer == type_void)
if (type_is_void(canonical->pointer))
{
if (failed_ref) goto ON_FAILED;
RETURN_SEMA_ERROR(inner, "A 'void*' cannot be dereferenced, you need to first cast it to a concrete type.");
@@ -8172,7 +8172,7 @@ static inline bool sema_expr_analyse_retval(SemaContext *c, Expr *expr)
else
{
expr->type = type_no_optional(c->rtype);
if (expr->type == type_void)
if (type_is_void(expr->type))
{
SEMA_ERROR(expr, "'return' cannot be used on void functions.");
return false;

View File

@@ -1069,7 +1069,7 @@ static inline bool sema_analyse_cond(SemaContext *context, Expr *expr, CondType
// 3a. Check for optional in case of an expression.
if (IS_OPTIONAL(last))
{
if (type_no_optional(last->type) == type_void && cast_to_bool)
if (type_is_void(type_no_optional(last->type)) && cast_to_bool)
{
SEMA_ERROR(last, "Use '@ok(<expr>)' or '@catch(<expr>)' to explicitly convert a 'void!' to a boolean.");
return false;

View File

@@ -1391,7 +1391,7 @@ static inline Type *func_create_new_func_proto(Signature *sig, CallABI abi, uint
proto->is_optional = true;
Type *real_return_type = rtype->optional;
proto->ret_by_ref_type = rtype->optional;
proto->ret_by_ref = real_return_type->type_kind != TYPE_VOID;
proto->ret_by_ref = !type_is_void(real_return_type);
proto->abi_ret_type = type_anyfault;
}
else
@@ -1773,7 +1773,7 @@ TypeCmpResult type_array_element_is_equivalent(SemaContext *context, Type *eleme
element2 = element2->canonical;
}
if (element1 == element2) return TYPE_SAME;
if ((element1 == type_void && element2 == type_char) || (element1 == type_char && element2 == type_void))
if ((type_is_void(element1) && element2 == type_char) || (element1 == type_char && type_is_void(element2)))
{
return TYPE_SAME;
}

View File

@@ -2,6 +2,11 @@ struct Foo {
void bar; // #error: Members cannot be of
}
def Void = void;
struct Foo2 {
Void bar; // #error: Members cannot be of
}
fn void main(String[] args) {
Foo foo;
Foo2 foo2;
}