diff --git a/releasenotes.md b/releasenotes.md index f058398fd..c4c6d3b0a 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -14,6 +14,7 @@ - Hex escapes like `"\x80"` would be incorrectly lowered. #2623 - Ignore const null check on deref in `$defined` and `$sizeof` #2633. - Subscripting of constant slices would sometimes be considered non-constant #2635. +- Compiler crash when concatenating structs and arrays to an untyped list. ### Stdlib changes - Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads. diff --git a/src/compiler/sema_const.c b/src/compiler/sema_const.c index 89b58c8bd..0adea99f9 100644 --- a/src/compiler/sema_const.c +++ b/src/compiler/sema_const.c @@ -425,9 +425,20 @@ bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr * UNREACHABLE case CONST_INIT_ARRAY_FULL: { + Expr *el; FOREACH(ConstInitializer *, val, init->init_array_full) { - vec_add(untyped_exprs, val->init_value); + switch (val->kind) + { + case CONST_INIT_VALUE: + vec_add(untyped_exprs, val->init_value); + break; + default: + el = expr_new_expr(EXPR_CONST, single_expr); + expr_rewrite_const_initializer(el, val->type, val); + vec_add(untyped_exprs, el); + break; + } } continue; } diff --git a/test/test_suite/compile_time/concat_untyped_with_struct_array.c3t b/test/test_suite/compile_time/concat_untyped_with_struct_array.c3t new file mode 100644 index 000000000..2a404e633 --- /dev/null +++ b/test/test_suite/compile_time/concat_untyped_with_struct_array.c3t @@ -0,0 +1,69 @@ +module assert_repro; +import assert_repro::macros; + +struct ArrayEntry +{ + int x; +} + +macro cause_assert() +{ + ArrayEntry[] $slice = {{1}, {2}, {3}}; + $slice = macros::replace {ArrayEntry} ($slice, 0, {4}); +} + +fn int main() +{ + cause_assert(); + return 0; +} +<* + This contains macros for working with arrays at compile time +*> +module assert_repro::macros { ValueT }; +alias SliceT = ValueT[]; + +macro SliceT slice(SliceT $from, usz $start, usz $end = usz.max) +{ + $if $start >= $from.len: + return (SliceT){}; + $else + $if $end >= $from.len: + return $from[$start..]; + $else + return $from[$start..$end-1]; + $endif + $endif +} + + +macro SliceT insert(SliceT $array, usz $position, ValueT $value) +{ + $if $position == $array.len: + return $array +++ {$value}; + $else + $if $position == 0: + return {$value} +++ $array; + $else + return slice($array, 0, $position) +++ {$value} +++ slice($array, $position); + $endif + $endif +} + +macro SliceT remove(SliceT $array, usz $position) +{ + $if $position == $array.len - 1: + return slice($array, 0, $array.len - 1); + $else + $if $position == 0: + return slice($array, 1); + $else + return slice($array, 0, $position) +++ slice($array, $position + 1); + $endif + $endif +} + +macro SliceT replace(SliceT $array, usz $position, ValueT $value) +{ + return insert(remove($array,$position),$position,$value); +} \ No newline at end of file