From 7fe49fbffbcb30f242de2f8eed6dff48d92aa7c5 Mon Sep 17 00:00:00 2001 From: kalsprite Date: Fri, 21 Aug 2026 16:38:56 -0700 Subject: [PATCH 1/4] Fix compiler panic on a selector into --- src/llvm_backend_expr.cpp | 5 +++++ tests/internal/test_branch_location.odin | 26 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/internal/test_branch_location.odin diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index f12965197..74cb46ceb 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -6546,6 +6546,11 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { return lb_build_addr_from_entity(p, e, expr); case_end; + case_ast_node(bd, BasicDirective, expr); + lbValue ptr = lb_address_from_load_or_generate_local(p, lb_build_expr(p, expr)); + return lb_addr(ptr); + case_end; + case_ast_node(se, SelectorExpr, expr); Ast *sel_node = unparen_expr(se->selector); if (sel_node->kind == Ast_Ident) { diff --git a/tests/internal/test_branch_location.odin b/tests/internal/test_branch_location.odin new file mode 100644 index 000000000..999657943 --- /dev/null +++ b/tests/internal/test_branch_location.odin @@ -0,0 +1,26 @@ +package test_internal + +import "core:testing" + +@(private="file") +returns_at :: proc(early: bool, got: ^i32) -> (expected: i32) { + defer got^ = #branch_location.line + + if early { + return #line + } + + return #line +} + +// A selector on `#branch_location` reached `lb_build_addr`, which had no case for a directive +@(test) +branch_location_field_access :: proc(t: ^testing.T) { + got: i32 + + expected := returns_at(true, &got) + testing.expect_value(t, got, expected) + + expected = returns_at(false, &got) + testing.expect_value(t, got, expected) +} From a1b56d76791accd8f3018cc5c2ca03047541c594 Mon Sep 17 00:00:00 2001 From: kalsprite Date: Fri, 21 Aug 2026 16:59:39 -0700 Subject: [PATCH 2/4] Fix compiler segfault on of a type alias that cycles back --- src/check_decl.cpp | 6 +++++- src/check_type.cpp | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 1751fee3b..56fc0e082 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -473,7 +473,11 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, check_type_path_pop(ctx); Type *base = base_type(bt); - if (is_distinct && bt->kind == Type_Named && base->kind == Type_Enum) { + if (base == nullptr) { + // `bt` is a named type that is still being checked, e.g. a cycle back through a + // pointer or slice, so chain to it and let it resolve when it does. + base = bt; + } else if (is_distinct && bt->kind == Type_Named && base->kind == Type_Enum) { base = clone_enum_type(ctx, base, named); } named->Named.base = base; diff --git a/src/check_type.cpp b/src/check_type.cpp index fcc1378f6..0b912905b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -4139,7 +4139,7 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) } #endif - if (type->kind == Type_Named && type->Named.base == nullptr || is_type_typed(type)) { + if (type->kind == Type_Named && base_type(type) == nullptr || is_type_typed(type)) { add_type_and_value(ctx, e, Addressing_Type, type, empty_exact_value); } else { gbString name = type_to_string(type); From f8bdfa0857eae3c9691d050f4bfba4c1bd42d2f9 Mon Sep 17 00:00:00 2001 From: kalsprite Date: Fri, 21 Aug 2026 17:31:42 -0700 Subject: [PATCH 3/4] Fix segfault comparing two foreign declarations of the same symbol --- src/check_decl.cpp | 8 ++-- tests/issues/run.bat | 2 + tests/issues/run.sh | 7 ++++ .../test_issue_foreign_redeclaration.odin | 39 +++++++++++++++++++ ..._issue_foreign_redeclaration_mismatch.odin | 18 +++++++++ 5 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 tests/issues/test_issue_foreign_redeclaration.odin create mode 100644 tests/issues/test_issue_foreign_redeclaration_mismatch.odin diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 1751fee3b..5b97e6eab 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -881,10 +881,10 @@ gb_internal bool signature_parameter_similar_enough(Type *x, Type *y) { if (x_base->Struct.is_raw_union) { return true; } - if (x->Struct.fields.count == y->Struct.fields.count) { - for (isize i = 0; i < x->Struct.fields.count; i++) { - Entity *a = x->Struct.fields[i]; - Entity *b = y->Struct.fields[i]; + if (x_base->Struct.fields.count == y_base->Struct.fields.count) { + for (isize i = 0; i < x_base->Struct.fields.count; i++) { + Entity *a = x_base->Struct.fields[i]; + Entity *b = y_base->Struct.fields[i]; bool similar = signature_parameter_similar_enough(a->type, b->type); if (!similar) { // NOTE(bill): If the fields are not similar enough, then stop. diff --git a/tests/issues/run.bat b/tests/issues/run.bat index a2224edb6..7db64dc39 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -42,6 +42,8 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused ..\..\..\odin check ..\test_issue_6979.odin -no-entry-point %COMMON% || exit /b ..\..\..\odin check ..\test_issue_7012.odin -no-entry-point %COMMON% || exit /b ..\..\..\odin check ..\test_issue_7260.odin -no-entry-point %COMMON% || exit /b +..\..\..\odin check ..\test_issue_foreign_redeclaration.odin -no-entry-point %COMMON% || exit /b +..\..\..\odin check ..\test_issue_foreign_redeclaration_mismatch.odin -no-entry-point %COMMON% 2>&1 | find /c "Error:" | findstr /x "1" || exit /b ..\..\..\odin build ..\test_issue_7037.odin %COMMON% -o:none || exit /b ..\..\..\odin build ..\test_issue_7188.odin %COMMON% || exit /b clang -c ..\test_issue_sysv_abi.c -o test_issue_sysv_abi_c.o || exit /b diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 138c88589..7ee6270a0 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -94,6 +94,13 @@ $ODIN test ../test_issue_7356.odin $COMMON $ODIN build ../test_issue_7167.odin $COMMON $ODIN build ../test_issue_7188.odin $COMMON $ODIN check ../test_issue_7260.odin -no-entry-point $COMMON_CHECK +$ODIN check ../test_issue_foreign_redeclaration.odin -no-entry-point $COMMON_CHECK +if [[ $($ODIN check ../test_issue_foreign_redeclaration_mismatch.odin -no-entry-point $COMMON_CHECK 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]]; then + echo "SUCCESSFUL 1/1" +else + echo "SUCCESSFUL 0/1" + exit 1 +fi if [[ $($ODIN build ../test_issue_7108.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]]; then echo "SUCCESSFUL 1/1" diff --git a/tests/issues/test_issue_foreign_redeclaration.odin b/tests/issues/test_issue_foreign_redeclaration.odin new file mode 100644 index 000000000..bed542ab6 --- /dev/null +++ b/tests/issues/test_issue_foreign_redeclaration.odin @@ -0,0 +1,39 @@ +// The field comparison that guards this had been reading a type's name as its field list, so +// signatures this different were accepted whenever the two names differed in length +package test_issues + +foreign import lib "this_library_does_not_exist" + +Ints :: struct { a: i32, b: i32 } +Floats :: struct { c: f32, d: f32 } + +@(default_calling_convention="c") +foreign lib { + @(link_name="mismatched") mismatched_1 :: proc(x: []Ints) --- +} + +@(default_calling_convention="c") +foreign lib { + @(link_name="mismatched") mismatched_2 :: proc(x: []Floats) --- +} + +// Two declarations of the same foreign symbol whose parameters reach a named struct through a +// slice or a field read the wrong member of the type union and segfaulted the compiler + +Inner :: struct { a: i32, b: i32 } +Other :: struct { c: i32, d: i32 } + +Wrap1 :: struct { f: Inner } +Wrap2 :: struct { f: Other } + +@(default_calling_convention="c") +foreign lib { + @(link_name="via_slice") slice_1 :: proc(x: []Inner) --- + @(link_name="via_field") field_1 :: proc(x: Wrap1) --- +} + +@(default_calling_convention="c") +foreign lib { + @(link_name="via_slice") slice_2 :: proc(x: []Other) --- + @(link_name="via_field") field_2 :: proc(x: Wrap2) --- +} diff --git a/tests/issues/test_issue_foreign_redeclaration_mismatch.odin b/tests/issues/test_issue_foreign_redeclaration_mismatch.odin new file mode 100644 index 000000000..998c78d57 --- /dev/null +++ b/tests/issues/test_issue_foreign_redeclaration_mismatch.odin @@ -0,0 +1,18 @@ +// The field comparison that guards this had been reading a type's name as its field list, so +// signatures this different were accepted whenever the two names differed in length +package test_issues + +foreign import lib "this_library_does_not_exist" + +Ints :: struct { a: i32, b: i32 } +Floats :: struct { c: f32, d: f32 } + +@(default_calling_convention="c") +foreign lib { + @(link_name="mismatched") mismatched_1 :: proc(x: []Ints) --- +} + +@(default_calling_convention="c") +foreign lib { + @(link_name="mismatched") mismatched_2 :: proc(x: []Floats) --- +} From c29596e88f5c31929fa655f56dec7a1b7012a1bd Mon Sep 17 00:00:00 2001 From: kalsprite Date: Fri, 21 Aug 2026 17:59:02 -0700 Subject: [PATCH 4/4] fix test typo --- .../test_issue_foreign_redeclaration.odin | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/tests/issues/test_issue_foreign_redeclaration.odin b/tests/issues/test_issue_foreign_redeclaration.odin index bed542ab6..2b5255765 100644 --- a/tests/issues/test_issue_foreign_redeclaration.odin +++ b/tests/issues/test_issue_foreign_redeclaration.odin @@ -1,25 +1,9 @@ -// The field comparison that guards this had been reading a type's name as its field list, so -// signatures this different were accepted whenever the two names differed in length +// Two declarations of the same foreign symbol whose parameters reach a named struct through a +// slice or a field read the wrong member of the type union and segfaulted the compiler package test_issues foreign import lib "this_library_does_not_exist" -Ints :: struct { a: i32, b: i32 } -Floats :: struct { c: f32, d: f32 } - -@(default_calling_convention="c") -foreign lib { - @(link_name="mismatched") mismatched_1 :: proc(x: []Ints) --- -} - -@(default_calling_convention="c") -foreign lib { - @(link_name="mismatched") mismatched_2 :: proc(x: []Floats) --- -} - -// Two declarations of the same foreign symbol whose parameters reach a named struct through a -// slice or a field read the wrong member of the type union and segfaulted the compiler - Inner :: struct { a: i32, b: i32 } Other :: struct { c: i32, d: i32 }