From bae5d9c7f8fefe3629ed3ec4f27d6b87d0a876a5 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 26 Feb 2024 18:45:55 +0100 Subject: [PATCH] Improved checks of aliased "void". --- src/compiler/abi/c_abi_x86.c | 2 +- src/compiler/compiler_internal.h | 4 ++++ src/compiler/llvm_codegen_storeload.c | 1 + src/compiler/sema_builtins.c | 4 ++-- src/compiler/sema_casts.c | 2 +- src/compiler/sema_decls.c | 14 +++++++------- src/compiler/sema_expr.c | 12 ++++++------ src/compiler/sema_stmts.c | 2 +- src/compiler/types.c | 4 ++-- test/test_suite/struct/struct_bad_member.c3 | 5 +++++ 10 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/compiler/abi/c_abi_x86.c b/src/compiler/abi/c_abi_x86.c index 4c04d87ce..068e152f0 100644 --- a/src/compiler/abi/c_abi_x86.c +++ b/src/compiler/abi/c_abi_x86.c @@ -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. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 1c3871035..28d057ace 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -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; } diff --git a/src/compiler/llvm_codegen_storeload.c b/src/compiler/llvm_codegen_storeload.c index 51cc60cad..117849434 100644 --- a/src/compiler/llvm_codegen_storeload.c +++ b/src/compiler/llvm_codegen_storeload.c @@ -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); } diff --git a/src/compiler/sema_builtins.c b/src/compiler/sema_builtins.c index f27f695a6..90c6bb160 100644 --- a/src/compiler/sema_builtins.c +++ b/src/compiler/sema_builtins.c @@ -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)); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 8bb3844e1..d42dfdff1 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -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); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 51446af2b..8833b9165 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -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, ¶ms, 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)) { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 93c32a414..9712047b9 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -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; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 31b93d17e..a0297e94e 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -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()' or '@catch()' to explicitly convert a 'void!' to a boolean."); return false; diff --git a/src/compiler/types.c b/src/compiler/types.c index cb680f3c3..ffe4306be 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -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; } diff --git a/test/test_suite/struct/struct_bad_member.c3 b/test/test_suite/struct/struct_bad_member.c3 index 1ecb955e5..fffaf25d7 100644 --- a/test/test_suite/struct/struct_bad_member.c3 +++ b/test/test_suite/struct/struct_bad_member.c3 @@ -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; }