test(ffi-linkage): Phase 5.0 prereq — xfail lib-less extern/#foreign C-import visibility equivalence
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.
This commit is contained in:
19
examples/1228-ffi-extern-c-non-transitive.sx
Normal file
19
examples/1228-ffi-extern-c-non-transitive.sx
Normal file
@@ -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;
|
||||||
|
}
|
||||||
7
examples/1228-ffi-extern-c-non-transitive/b.sx
Normal file
7
examples/1228-ffi-extern-c-non-transitive/b.sx
Normal file
@@ -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);
|
||||||
|
}
|
||||||
7
examples/1228-ffi-extern-c-non-transitive/c.sx
Normal file
7
examples/1228-ffi-extern-c-non-transitive/c.sx
Normal file
@@ -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;
|
||||||
1
examples/expected/1228-ffi-extern-c-non-transitive.exit
Normal file
1
examples/expected/1228-ffi-extern-c-non-transitive.exit
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1
|
||||||
11
examples/expected/1228-ffi-extern-c-non-transitive.stderr
Normal file
11
examples/expected/1228-ffi-extern-c-non-transitive.stderr
Normal file
@@ -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));
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
Reference in New Issue
Block a user