- Passing a non-conststring to module attributes like @cname would trigger an assert rather than printing an error.

- Passing different types to arg 1 and 2 for $$matrix_transpose would trigger an assert.
- Zero init of optional compile time variable would crash the compiler.
- Using multiple declaration for generics in generic module would fail.
- Defining an extern const without a type would crash rather than print an error.
- Typedef followed by brace would trigger an assert.
- Union with too big member would trigger an assert.
This commit is contained in:
Christoffer Lerno
2026-01-18 22:47:17 +01:00
parent c3b2694834
commit dd8449576f
11 changed files with 67 additions and 5 deletions

View File

@@ -66,6 +66,13 @@
- Too little memory reserved when printing backtrace on Darwin #2698.
- In some cases, a type would not get implicitly converted to a typeid #2764.
- Assert on defining a const fault enum with enumerator and fault of the same name. #2732
- Passing a non-conststring to module attributes like @cname would trigger an assert rather than printing an error. #2771
- Passing different types to arg 1 and 2 for $$matrix_transpose would trigger an assert. #2771
- Zero init of optional compile time variable would crash the compiler. #2771
- Using multiple declaration for generics in generic module would fail. #2771
- Defining an extern const without a type would crash rather than print an error. #2771
- Typedef followed by brace would trigger an assert. #2771
- Union with too big member would trigger an assert. #2771
### Stdlib changes
- Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads.

View File

@@ -370,7 +370,7 @@ bool parse_module(ParseContext *c, AstId contracts)
vec_size(attr->exprs));
}
Expr *expr = attr->exprs[0];
if (!expr_is_const_string(expr)) RETURN_PRINT_ERROR_AT(false, expr, "Expected a constant string.");
if (expr->resolve_status != RESOLVE_DONE || !expr_is_const_string(expr)) RETURN_PRINT_ERROR_AT(false, expr, "Expected a constant string.");
if (c->unit->module->extname)
{
RETURN_PRINT_ERROR_AT(false, attr,
@@ -388,7 +388,7 @@ bool parse_module(ParseContext *c, AstId contracts)
vec_size(attr->exprs));
}
Expr *expr = attr->exprs[0];
if (!expr_is_const_string(expr)) RETURN_PRINT_ERROR_AT(false, expr, "Expected a constant string.");
if (expr->resolve_status != RESOLVE_DONE || !expr_is_const_string(expr)) RETURN_PRINT_ERROR_AT(false, expr, "Expected a constant string.");
if (c->unit->module->extname)
{
RETURN_PRINT_ERROR_AT(false, attr,
@@ -1533,6 +1533,7 @@ static inline Decl *parse_global_declaration(ParseContext *c)
CONSUME_EOS_OR_RET(poisoned_decl);
Attr **attributes = decl->attributes;
// Copy the attributes to the other variables.
if (attributes)
{
FOREACH(Decl *, d, decls)
@@ -1541,12 +1542,27 @@ static inline Decl *parse_global_declaration(ParseContext *c)
d->attributes = copy_attributes_single(attributes);
}
}
int generics_id = decl->is_template ? decl->generic_id : -1;
if (generics_id > -1)
{
FOREACH(Decl *, d, decls)
{
if (d == decl) continue;
d->generic_id = generics_id;
d->is_template = true;
}
}
// If we have multiple decls, then we return that as a bundled decl_globals
if (decls)
{
decl = decl_calloc();
decl->decl_kind = DECL_GROUP;
decl->decls = decls;
if (generics_id > -1)
{
decl->generic_id = generics_id;
decl->is_template = true;
}
return decl;
}
return decl;
@@ -2065,8 +2081,6 @@ static inline Decl *parse_typedef_declaration(ParseContext *c)
// 2. Now parse the type which we know is here.
ASSIGN_TYPE_OR_RET(decl->distinct, parse_optional_type(c), poisoned_decl);
ASSERT(!tok_is(c, TOKEN_LBRACE));
while (tok_is(c, TOKEN_AT_IDENT))
{
const char *name = symstr(c);

View File

@@ -835,6 +835,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
if (!sema_check_builtin_args(context, args, (BuiltinArg[]) {BA_VEC, BA_INTEGER, BA_INTEGER}, 3)) return false;
if (!sema_check_builtin_args_const(context, &args[1], 2)) return false;
ArraySize vec_len = type_flatten(args[0]->type)->array.len;
if (!cast_implicit(context, args[2], args[1]->type, false)) return false;
Int sum = int_mul(args[1]->const_expr.ixx, args[2]->const_expr.ixx);
if (!int_icomp(sum, vec_len, BINARYOP_EQ))
{

View File

@@ -362,6 +362,8 @@ static bool sema_analyse_union_members(SemaContext *context, Decl *decl)
if (!sema_check_struct_holes(context, decl, member)) return false;
ByteSize member_size = type_size(member->type);
if (member_size > MAX_STRUCT_SIZE) RETURN_SEMA_ERROR(member, "Union member '%s' would cause the union to become too large (exceeding 2 GB).", member->name);
ASSERT(member_size <= MAX_TYPE_SIZE);
// Update max alignment
if (member->alignment > member_alignment) member_alignment = member->alignment;
@@ -4726,7 +4728,7 @@ bool sema_analyse_var_decl_ct(SemaContext *context, Decl *decl, bool *check_fail
goto FAIL;
}
decl->var.init_expr = init = expr_new(EXPR_POISONED, decl->span);
expr_rewrite_to_const_zero(init, decl->type);
expr_rewrite_to_const_zero(init, type_no_optional(decl->type));
}
// Analyse the expression.
@@ -4813,6 +4815,11 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local, bool *c
TypeInfo *type_info = vartype(decl);
// We expect a constant to actually be parsed correctly so that it has a value, so
// this should always be true.
if (!type_info && decl->is_extern)
{
SEMA_ERROR(decl, "A type is needed for the extern %s '%s'.", decl_to_name(decl), decl->name);
return decl_poison(decl);
}
ASSERT(type_info || decl->var.init_expr);
bool erase_decl = false;

View File

@@ -0,0 +1,5 @@
module linux @cname(NETBSD ??? "" : ""); // #error: Expected a constant string
fn int main()
{
return 0;
}

View File

@@ -0,0 +1,6 @@
fn int main()
{
int[<6>] c = 2;
c = $$matrix_transpose(c, 0x10, 3); // #error: Expected row * col to equal 6
return 0;
}

View File

@@ -0,0 +1,4 @@
fn void main()
{
char? a, $b;
}

View File

@@ -0,0 +1,11 @@
module elastic_array <Type, MAX_SIZE>;
int a, b, c;
module bar;
import elastic_array;
fn int main()
{
int g = elastic_array::a{int, 2};
int g2 = elastic_array::b{int, 2};
elastic_array::b{int, 2} = 3;
return 0;
}

View File

@@ -0,0 +1 @@
extern const FOO; // #error: A type is needed for the extern constant 'FOO'

View File

@@ -0,0 +1,2 @@
typedef Bar = BacktraceList? // #error: Expected ';'
{

View File

@@ -0,0 +1,4 @@
union Xu
{
int[int.max] b; // #error: Union member 'b' would cause the union to become too large
}