diff --git a/releasenotes.md b/releasenotes.md index 3933b90ae..eb7ae66c6 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -25,6 +25,7 @@ - Allow even smaller memory limits. - Check unaligned array access. - Add "@structlike" for typedefs. +- "poison" the current function early when a declaration can't be correctly resolved. ### Fixes - mkdir/rmdir would not work properly with substring paths on non-windows platforms. diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 3f028106e..26111e7b0 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -4639,6 +4639,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) VarDeclKind kind = decl->var.kind; + bool success = true; bool is_global = !local; switch (kind) { @@ -4811,25 +4812,26 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) CallEnvKind env_kind = context->call_env.kind; if (is_static) context->call_env.kind = CALL_ENV_FUNCTION_STATIC; decl->in_init = true; - if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false, true, NULL)) - { - context->call_env.kind = env_kind; - return decl_poison(decl); - } + success = sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false, true, NULL); decl->in_init = false; context->call_env.kind = env_kind; - if (infer_len) { + if (!success) return decl_poison(decl); decl->type = type_add_optional(init->type, IS_OPTIONAL(decl)); } // 2. Check const-ness - if (global_level_var && !expr_is_runtime_const(init)) + if (global_level_var) { - SEMA_ERROR(init, "The expression must be a constant value."); - return decl_poison(decl); + if (!success) return decl_poison(decl); + if (!expr_is_runtime_const(init)) + { + SEMA_ERROR(init, "The expression must be a constant value."); + return decl_poison(decl); + } } + if (!success) goto EXIT_OK; if (global_level_var || !type_is_abi_aggregate(init->type)) sema_cast_const(init); if (expr_is_const(init)) { @@ -4850,7 +4852,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) { if (!sema_set_alloca_alignment(context, decl->type, &decl->alignment)) return false; } - return true; + return success; } diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 785bacd24..40a4fabb5 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1232,7 +1232,11 @@ static inline bool sema_analyse_declare_stmt(SemaContext *context, Ast *statemen Decl *decl = statement->declare_stmt; VarDeclKind kind = decl->var.kind; bool erase = kind == VARDECL_LOCAL_CT_TYPE || kind == VARDECL_LOCAL_CT; - if (!sema_analyse_var_decl(context, decl, true)) return false; + if (!sema_analyse_var_decl(context, decl, true)) + { + if (!decl_ok(decl)) context->active_scope.is_poisoned = true; + return false; + } if (erase || decl->decl_kind == DECL_ERASED) statement->ast_kind = AST_NOP_STMT; return true; } @@ -1445,6 +1449,7 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement) if (is_infinite && !statement->for_stmt.flow.has_break) { + if (!success) context->active_scope.is_poisoned = true; SET_JUMP_END(context, statement); } return success; diff --git a/test/src/test_suite_runner.c3 b/test/src/test_suite_runner.c3 index fdff8f522..da4331db4 100644 --- a/test/src/test_suite_runner.c3 +++ b/test/src/test_suite_runner.c3 @@ -442,7 +442,7 @@ fn void test_file(Path file_path) // Start process SubProcess compilation = process::create(cmdline.array_view(), { .search_user_path, .no_window, .inherit_environment })!!; defer compilation.destroy(); - CInt result = compilation.join()!!; + CInt result = compilation.join() ?? 1; DString out; io::copy_to(&&compilation.stderr(), &out)!!; if (result != 0 && result != 1) diff --git a/test/test_suite/cast/cast_struct.c3 b/test/test_suite/cast/cast_struct.c3 index 210ae5045..e60707a5a 100644 --- a/test/test_suite/cast/cast_struct.c3 +++ b/test/test_suite/cast/cast_struct.c3 @@ -25,13 +25,15 @@ struct BazTwo fn void test() { Foo x; - Bar y = (Bar)(x); // #error: 'Foo' to 'Bar' + { Bar y = (Bar)(x); } // #error: 'Foo' to 'Bar' Baz z; - int[2] w = (int[2])(z); // #error: 'Baz' to 'int[2]' - z = (Baz)(w); - BazTwo v = (BazTwo)(z); // #error: 'Baz' to 'BazTwo' - v = (BazTwo)(w); - z = (Baz)(v); - w = (int[2])(v); + { int[2] w = (int[2])(z); } // #error: 'Baz' to 'int[2]' + int[2] w; + z = (Baz)(w); // #error: to 'Baz' + { BazTwo v = (BazTwo)(z); } // #error: 'Baz' to 'BazTwo' + BazTwo v; + v = (BazTwo)(w); // #error: to 'BazTwo' + z = (Baz)(v); // #error: possible to cast 'BazTwo' to 'Baz' + w = (int[2])(v); // #error: possible to cast 'BazTwo' to 'int[2]' } diff --git a/test/test_suite/compile_time/concat_slice_array.c3 b/test/test_suite/compile_time/concat_slice_array.c3 index 1e4f6621a..acfd71a51 100644 --- a/test/test_suite/compile_time/concat_slice_array.c3 +++ b/test/test_suite/compile_time/concat_slice_array.c3 @@ -10,6 +10,18 @@ $foreach $c : $chars: int $offset = ($c - $from) / BITS; int $rem = ($c - $from) % BITS; uint128 $value = $bitmap[$offset]; // #error: is out of range +$endforeach +} + +fn int main2() +{ + String $chars = "Abcd"; + char $from = 2; + char[10] $bitmap = {}; +$foreach $c : $chars: + int $offset = ($c - $from) / BITS; + int $rem = ($c - $from) % BITS; + uint128 $value = 1; $value |= 1ULL << $rem; $bitmap = $bitmap[:$offset] +++ $value +++ $bitmap[$offset+1..]; // #error: End index out of bounds $endforeach diff --git a/test/test_suite/errors/rethrow_macro.c3 b/test/test_suite/errors/rethrow_macro.c3 index 2e9f12a46..2c3f381ce 100644 --- a/test/test_suite/errors/rethrow_macro.c3 +++ b/test/test_suite/errors/rethrow_macro.c3 @@ -1,14 +1,14 @@ module testing; import std::io; -macro char[] read(src, Allocator allocator, n) +macro void read(src, Allocator allocator, n) { char* data = allocator::malloc_try(allocator, n)!; // #error: Rethrow is only allowed in macros - io::read_all(src, data[:n])!; + (void)io::read_all(src, data[:n]); } fn void main() { ByteReader br; - read(&br, allocator::temp(), 10); + read(&br, allocator::temp(), 10)!!; } \ No newline at end of file diff --git a/test/test_suite/visibility/recurse_private_import.c3 b/test/test_suite/visibility/recurse_private_import.c3 index 17d6bd825..822904e59 100644 --- a/test/test_suite/visibility/recurse_private_import.c3 +++ b/test/test_suite/visibility/recurse_private_import.c3 @@ -27,7 +27,7 @@ import abc @norecurse @public; fn int test() { - Abc x; // #error: is '@private' + { Abc x; } // #error: is '@private' abc::baz::test(); // #error: is '@private' return 0; } \ No newline at end of file