diff --git a/releasenotes.md b/releasenotes.md index 7b8af8c74..8d8a51aba 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -52,6 +52,7 @@ - `$$sat_mul` was missing. - `for` with incorrect `var` declaration caused crash #2154. - Check pointer/slice/etc on `[out]` and `&` params. #2156. +- Compiler didn't check foreach over flexible array member, and folding a flexible array member was allowed #2164. ### Stdlib changes - Added `String.quick_ztr` and `String.is_zstr` diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 28e86c0ca..bc104e12a 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -2374,7 +2374,7 @@ static inline bool unit_add_method(SemaContext *context, Type *parent_type, Decl other = sema_resolve_method(unit, parent, name, &ambiguous, &private); if (other) { - if (unit->module->generic_module && other->unit->module->generic_module == unit->module->generic_module) + if (unit->module->generic_module && other->unit->module->generic_module == unit->module->generic_module && other->unit->module != unit->module) { const char *module_name = unit->module->generic_module->name->module; RETURN_SEMA_ERROR(method, "The same method is generated by multiple instances of '%s': '%s%s' and '%s%s'. " diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index cc229c63b..8fd37df24 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -4981,6 +4981,7 @@ EVAL: switch (result->kind) { case CONST_INIT_ZERO: + if (member->type->type_kind == TYPE_FLEXIBLE_ARRAY) return false; expr_rewrite_to_const_zero(expr, member->type); break; case CONST_INIT_STRUCT: @@ -5688,6 +5689,10 @@ CHECK_DEEPER: { if (!sema_expr_fold_to_member(expr, current_parent, member)) { + if (member->type->type_kind == TYPE_FLEXIBLE_ARRAY) + { + RETURN_SEMA_ERROR(expr, "Could not fold to member '%s', it's a flexible array member which is always empty.", member->name); + } RETURN_SEMA_ERROR(expr, "Could not fold to member '%s' – it wasn't the last assigned member.", member->name); } return true; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 23017fc81..5a0f32549 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1497,6 +1497,10 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen // At this point we should have dereferenced any pointer or bailed. ASSERT_SPAN(enumerator, !type_is_pointer(enumerator->type)); + if (enumerator->type->type_kind == TYPE_FLEXIBLE_ARRAY) + { + RETURN_SEMA_ERROR(enumerator, "It is not possible to enumerate over a flexible array member.", type_quoted_error_string(enumerator->type)); + } // Check that we can even index this expression, this will dig into the flattened type. Type *value_type = type_get_indexed_type(enumerator->type); diff --git a/test/test_suite/generic/generic_self_ref.c3 b/test/test_suite/generic/generic_self_ref.c3 index 7a8f1ea84..a518375a1 100644 --- a/test/test_suite/generic/generic_self_ref.c3 +++ b/test/test_suite/generic/generic_self_ref.c3 @@ -10,7 +10,7 @@ struct Widget List {any} children; } -fn void Widget{Label}.draw(Widget* self) // #error: This identifier is recursively using gui::widget +fn void Widget{Label}.draw(Widget* self) // #error: The same method is generated by multiple instances { io::printfn("Hello Label"); } diff --git a/test/test_suite/statements/foreach_fails.c3 b/test/test_suite/statements/foreach_fails.c3 new file mode 100644 index 000000000..c72e13ad9 --- /dev/null +++ b/test/test_suite/statements/foreach_fails.c3 @@ -0,0 +1,15 @@ +struct Abc +{ + int a; + int[*] b; +} +fn void test() +{ + Abc y = {}; + foreach (x : y.b) {} // #error: It is not possible to enumerate over a flexible +} +fn int main() +{ + foreach (x : (Abc){}.b) {} // #error: it's a flexible array member + return 0; +} \ No newline at end of file