From d2cae909e1aea9be19e46101946c9aab763f5b50 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 27 Aug 2025 11:42:53 +0200 Subject: [PATCH] A file with an inferred module may not contain additional other modules. --- releasenotes.md | 1 + src/compiler/compiler_internal.h | 1 + src/compiler/context.c | 2 +- src/compiler/parse_global.c | 9 +++++++++ test/test_suite/attributes/format_macros.c3t | 2 -- test/test_suite/methods/method_lookup_extensions_2208.c3 | 1 + 6 files changed, 13 insertions(+), 3 deletions(-) diff --git a/releasenotes.md b/releasenotes.md index 6090e3768..fd60499c1 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -26,6 +26,7 @@ - `@assignable_to` is deprecated in favour of `$define` - Add `linklib-dir` to c3l-libraries to place their linked libraries in. Defaults to `linked-libs` - If the `os-arch` linked library doesn't exist, try with `os` for c3l libs. +- A file with an inferred module may not contain additional other modules. ### Fixes - List.remove_at would incorrectly trigger ASAN. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index abfbfb801..dd0a4a98f 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1698,6 +1698,7 @@ struct CompilationUnit_ bool is_interface_file; bool benchmark_by_default; bool test_by_default; + bool module_generated; Attr **attr_links; Decl **generic_defines; Decl **ct_asserts; diff --git a/src/compiler/context.c b/src/compiler/context.c index 4942d27b7..09cfcf81f 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -121,7 +121,7 @@ bool context_set_module_from_filename(ParseContext *context) return false; } Path *path = CALLOCS(Path); - path->span = INVALID_SPAN; + path->span = context->span; path->module = module_name; path->len = scratch_buffer.len; return create_module_or_check_name(context->unit, path, NULL); diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 0fe3d8e15..e3557f775 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -3190,6 +3190,7 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out) if (tok != TOKEN_MODULE && !c->unit->module) { if (!context_set_module_from_filename(c)) return poisoned_decl; + c->unit->module_generated = true; // Pass the docs to the next thing. } @@ -3230,6 +3231,14 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **context_out) advance(c); if (c->unit->module) { + if (c->unit->module_generated) + { + print_error_at(c->unit->module->name->span, "This file begins with an auto-generated module '%s', which isn't compatible with having other module sections, please start the file with an explicit 'module'.", + c->unit->module->name->module); + sema_note_prev_at(c->span, "This declaration creates the next module section."); + c->unit->module_generated = false; + return poisoned_decl; + } // We might run into another module declaration. If so, create a new unit. ParseContext *new_context = CALLOCS(ParseContext); *new_context = *c; diff --git a/test/test_suite/attributes/format_macros.c3t b/test/test_suite/attributes/format_macros.c3t index 31b6b7080..9c6cf804d 100644 --- a/test/test_suite/attributes/format_macros.c3t +++ b/test/test_suite/attributes/format_macros.c3t @@ -1,5 +1,3 @@ -import std; - module abort_test; fn int main() diff --git a/test/test_suite/methods/method_lookup_extensions_2208.c3 b/test/test_suite/methods/method_lookup_extensions_2208.c3 index 91801f52e..aab0cb2b8 100644 --- a/test/test_suite/methods/method_lookup_extensions_2208.c3 +++ b/test/test_suite/methods/method_lookup_extensions_2208.c3 @@ -1,3 +1,4 @@ +module okok; fn void main() {} module foo @private;