From 717c35d26d9959081179e9e929b8fe9fedbbaeb2 Mon Sep 17 00:00:00 2001 From: agra Date: Sun, 14 Jun 2026 20:47:48 +0300 Subject: [PATCH] =?UTF-8?q?test(ffi-linkage):=20Phase=205.0=20prereq=20?= =?UTF-8?q?=E2=80=94=20xfail=20lib-less=20extern/#foreign=20C-import=20vis?= =?UTF-8?q?ibility=20equivalence?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cross-module example (main → b → c) referencing c's lib-less C imports transitively. The non-transitive C-import gate (lower/decl.zig c_import_bare) must police the legacy `#foreign` form and the new `extern` keyword IDENTICALLY — same 'C function not visible' diagnostic, not the generic top-level-name wording. Today the extern twin escapes the c_import_bare gate (body is an empty block, not foreign_expr) and is only caught by the general isNameVisible gate, yielding the generic message. Expected snapshot pins the DESIRED equivalent wording; the next commit aligns the gate to green it. Prerequisite for migrating the fn-decl `#foreign` path onto `extern`. 443/444 corpus (1228 xfail), 444 unit. --- examples/1228-ffi-extern-c-non-transitive.sx | 19 +++++++++++++++++++ .../1228-ffi-extern-c-non-transitive/b.sx | 7 +++++++ .../1228-ffi-extern-c-non-transitive/c.sx | 7 +++++++ .../1228-ffi-extern-c-non-transitive.exit | 1 + .../1228-ffi-extern-c-non-transitive.stderr | 11 +++++++++++ .../1228-ffi-extern-c-non-transitive.stdout | 0 6 files changed, 45 insertions(+) create mode 100644 examples/1228-ffi-extern-c-non-transitive.sx create mode 100644 examples/1228-ffi-extern-c-non-transitive/b.sx create mode 100644 examples/1228-ffi-extern-c-non-transitive/c.sx create mode 100644 examples/expected/1228-ffi-extern-c-non-transitive.exit create mode 100644 examples/expected/1228-ffi-extern-c-non-transitive.stderr create mode 100644 examples/expected/1228-ffi-extern-c-non-transitive.stdout diff --git a/examples/1228-ffi-extern-c-non-transitive.sx b/examples/1228-ffi-extern-c-non-transitive.sx new file mode 100644 index 0000000..3b39e12 --- /dev/null +++ b/examples/1228-ffi-extern-c-non-transitive.sx @@ -0,0 +1,19 @@ +// `#import` is non-transitive for C-import functions: main imports b, +// b imports c, so main must NOT see c's lib-less `#foreign` / `extern` +// C functions directly. Referencing either is rejected by the +// C-import visibility gate (lower/decl.zig `c_import_bare`). +// +// Equivalence lock (FFI-linkage Part B): the legacy `#foreign` form and +// the new `extern` keyword are two spellings of the same lib-less +// C-symbol import, so they must produce the SAME "C function not +// visible" diagnostic — not the generic top-level-name wording. This +// pins that equivalence as a prerequisite for migrating the fn-decl +// `#foreign` path onto `extern`. +#import "modules/std.sx"; +#import "1228-ffi-extern-c-non-transitive/b.sx"; + +main :: () -> i32 { + print("{}\n", c_foreign_abs(-3)); + print("{}\n", c_extern_abs(-4)); + return 0; +} diff --git a/examples/1228-ffi-extern-c-non-transitive/b.sx b/examples/1228-ffi-extern-c-non-transitive/b.sx new file mode 100644 index 0000000..ab5a5c4 --- /dev/null +++ b/examples/1228-ffi-extern-c-non-transitive/b.sx @@ -0,0 +1,7 @@ +// Intermediate module: directly imports c.sx, so BOTH of c's lib-less +// C functions are legitimately visible here (the legal usage site). +#import "c.sx"; + +b_use :: () -> i32 { + return c_foreign_abs(-1) + c_extern_abs(-2); +} diff --git a/examples/1228-ffi-extern-c-non-transitive/c.sx b/examples/1228-ffi-extern-c-non-transitive/c.sx new file mode 100644 index 0000000..8fe5235 --- /dev/null +++ b/examples/1228-ffi-extern-c-non-transitive/c.sx @@ -0,0 +1,7 @@ +// Two spellings of the same lib-less C-symbol import: the legacy +// `#foreign` form and the new `extern` keyword. Both declare a C +// function resolved at link time with no library reference. The +// FFI-linkage migration (Part B) requires the two to be policed +// IDENTICALLY by the non-transitive C-import visibility gate. +c_foreign_abs :: (x: i32) -> i32 #foreign; +c_extern_abs :: (x: i32) -> i32 extern; diff --git a/examples/expected/1228-ffi-extern-c-non-transitive.exit b/examples/expected/1228-ffi-extern-c-non-transitive.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/examples/expected/1228-ffi-extern-c-non-transitive.exit @@ -0,0 +1 @@ +1 diff --git a/examples/expected/1228-ffi-extern-c-non-transitive.stderr b/examples/expected/1228-ffi-extern-c-non-transitive.stderr new file mode 100644 index 0000000..0443bdb --- /dev/null +++ b/examples/expected/1228-ffi-extern-c-non-transitive.stderr @@ -0,0 +1,11 @@ +error: C function 'c_foreign_abs' not visible; add #import for the module that declares it + --> examples/1228-ffi-extern-c-non-transitive.sx:16:19 + | +16 | print("{}\n", c_foreign_abs(-3)); + | ^^^^^^^^^^^^^ + +error: C function 'c_extern_abs' not visible; add #import for the module that declares it + --> examples/1228-ffi-extern-c-non-transitive.sx:17:19 + | +17 | print("{}\n", c_extern_abs(-4)); + | ^^^^^^^^^^^^ diff --git a/examples/expected/1228-ffi-extern-c-non-transitive.stdout b/examples/expected/1228-ffi-extern-c-non-transitive.stdout new file mode 100644 index 0000000..e69de29