diff --git a/releasenotes.md b/releasenotes.md index b0e01a884..1386a8681 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -123,6 +123,8 @@ - Added `Clock` and `DateTime`. ### Fixes +- Fixes bug initializing a const struct with a const struct value +- Fixes bug when `void` is passed to an "any"-vararg. - Fixed defer/return value ordering in certain cases. - Fixes to the x64 ABI. - Updates to how variadics are implemented. diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index fc756d309..cde6dccfb 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -2826,9 +2826,12 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) if (init_expr->type == type_wildcard_optional || init_expr->type == type_wildcard) { SEMA_ERROR(init_expr, "No type can be inferred from the optional result."); - return false; } - if (init_expr->type == type_untypedlist) + else if (init_expr->type == type_void) + { + SEMA_ERROR(init_expr, "You cannot initialize a value to 'void'."); + } + else if (init_expr->type == type_untypedlist) { SEMA_ERROR(init_expr, "The type of an untyped list cannot be inferred, you can try adding an explicit type to solve this."); } @@ -3018,25 +3021,31 @@ static bool sema_append_generate_parameterized_name(SemaContext *c, Module *modu } if (param->expr_kind == EXPR_TYPEINFO) { - TypeInfo *type = param->type_expr; - if (!sema_resolve_type_info(c, type)) return decl_poison(decl); - if (type->type->type_kind == TYPE_OPTIONAL) + TypeInfo *type_info = param->type_expr; + if (!sema_resolve_type_info(c, type_info)) return decl_poison(decl); + Type *type = type_info->type->canonical; + if (type->type_kind == TYPE_OPTIONAL) { - SEMA_ERROR(type, "Expected a non-optional type."); + SEMA_ERROR(type_info, "Expected a non-optional type."); return poisoned_decl; } - if (type_is_invalid_storage_type(type->type)) + if (type == type_void) { - SEMA_ERROR(type, "Expected a runtime type."); + SEMA_ERROR(type_info, "A 'void' type cannot be used as a parameter type."); + return poisoned_decl; + } + if (type_is_invalid_storage_type(type)) + { + SEMA_ERROR(type_info, "Expected a runtime type."); return poisoned_decl; } if (mangled) { - type_mangle_introspect_name_to_buffer(type->type->canonical); + type_mangle_introspect_name_to_buffer(type); } else { - scratch_buffer_append(type->type->name); + scratch_buffer_append(type_info->type->name); } } else diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 4486344ec..7cb5c730c 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1257,10 +1257,11 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee, else if (variadic == VARIADIC_ANY) { if (!sema_analyse_expr(context, arg)) return false; - if (type_is_invalid_storage_type(arg->type)) + Type *type = arg->type; + if (type_is_invalid_storage_type(type) || type == type_void) { SEMA_ERROR(arg, "A value of type %s cannot be passed as a variadic argument.", - type_quoted_error_string(arg->type)); + type_quoted_error_string(type)); return false; } expr_insert_addr(arg); @@ -1471,7 +1472,7 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call else { if (!sema_analyse_expr(context, val)) return false; - if (type_is_invalid_storage_type(val->type)) + if (type_is_invalid_storage_type(val->type) || val->type == type_void) { SEMA_ERROR(val, "A value of type %s cannot be passed as a variadic argument.", type_quoted_error_string(val->type)); @@ -1538,7 +1539,7 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call if (!sema_expr_check_assign(context, arg)) return false; *optional |= IS_OPTIONAL(arg); if (!sema_call_check_contract_param_match(context, param, arg)) return false; - if (type_is_invalid_storage_type(type)) + if (type_is_invalid_storage_type(type) || type == type_void) { SEMA_ERROR(arg, "A value of type %s cannot be passed by reference.", type_quoted_error_string(type)); return false; @@ -1563,6 +1564,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)) return false; + if (type_no_optional(arg->type) == type_void) 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)) { @@ -5892,10 +5894,11 @@ static inline bool sema_expr_analyse_taddr(SemaContext *context, Expr *expr) Expr *inner = expr->unary_expr.expr; if (!sema_analyse_expr(context, inner)) return false; - if (type_is_invalid_storage_type(inner->type)) + Type *type = inner->type; + if (type_is_invalid_storage_type(type) || type == type_void) { - SEMA_ERROR(expr, "It is not possible to take the address from a value of the type %s.", - type_quoted_error_string(inner->type)); + SEMA_ERROR(expr, "It is not possible to take the address from a value of type %s.", + type_quoted_error_string(type)); return false; } // 2. The type is the resulting type of the expression. @@ -6584,7 +6587,7 @@ static inline bool sema_expr_analyse_ct_alignof(SemaContext *context, Expr *expr Decl *decl = sema_expr_analyse_var_path(context, main_var); if (!decl) return false; Type *type = decl->type; - if (type_is_invalid_storage_type(type)) + if (type_is_invalid_storage_type(type) || type == type_void) { SEMA_ERROR(main_var, "Cannot use '$alignof' on type %s.", type_quoted_error_string(type)); return false; diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index b8dfb872e..6ee14cf5f 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -637,6 +637,14 @@ static void sema_create_const_initializer_value(ConstInitializer *const_init, Ex value->const_expr.initializer = const_init; return; } + if (value->expr_kind == EXPR_IDENTIFIER) + { + Decl *ident = value->identifier_expr.decl; + assert(ident->decl_kind == DECL_VAR); + assert(ident->var.kind == VARDECL_CONST); + sema_create_const_initializer_value(const_init, expr_copy(ident->var.init_expr)); + return; + } const_init->init_value = value; const_init->type = type_flatten(value->type); const_init->kind = CONST_INIT_VALUE; diff --git a/src/version.h b/src/version.h index 6d998765f..181b6ac06 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.531" \ No newline at end of file +#define COMPILER_VERSION "0.4.532" \ No newline at end of file diff --git a/test/test_suite/constants/constant_struct.c3 b/test/test_suite/constants/constant_struct.c3 new file mode 100644 index 000000000..109b79ae9 --- /dev/null +++ b/test/test_suite/constants/constant_struct.c3 @@ -0,0 +1,18 @@ +import std::io; + +struct Abc +{ + int a; +} + +struct Bcd +{ + Abc x; +} + +const Abc FOO = { 2 }; + +fn void! main() +{ + Bcd a = { FOO }; +} diff --git a/test/test_suite/expressions/void_arg.c3 b/test/test_suite/expressions/void_arg.c3 new file mode 100644 index 000000000..74fa5bc75 --- /dev/null +++ b/test/test_suite/expressions/void_arg.c3 @@ -0,0 +1,33 @@ +import std::io; + +fn void test1() +{ + foo(test1()); // #error: A 'void' value cannot be passed as a parameter +} + +fn void test2() +{ + bar(test2()); // #error: You cannot cast 'void' into 'int' even with an explicit cast +} + +fn void test3() +{ + baz(test3()); // #error: A value of type 'void' cannot be passed as a variadic argumen +} + +fn void test4() +{ + abc(test4()); +} + +macro void abc(...) {} + +extern fn void baz(...); + +macro void foo(x) +{ +} + +fn void bar(int x) +{} +