Fixes #786, constant initialization with constants sometimes causing an error lowering to LLVM. Fixes bug passing void as a vararg argument to an any vararg.

This commit is contained in:
Christoffer Lerno
2023-06-19 10:38:37 +02:00
parent 3bdeec3bc2
commit 57424d8b6b
7 changed files with 92 additions and 19 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.531"
#define COMPILER_VERSION "0.4.532"

View File

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

View File

@@ -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)
{}