Files
sx/examples/1172-diagnostics-foreign-symbol-conflict.sx
agra d88bdd7242 fix(0128): foreign cstring returns + conflicting same-symbol bindings
Two genuine defects behind the 0128 filing (whose original repros were
both poisoned by binding getenv, which std already declares -> *u8):

1. Re-declaring a C symbol was silent first-wins: every call through
   the later declaration was typed by the older signature. Foreign
   registration now dedupes — equal signatures share one FuncId,
   conflicting ones are diagnosed.

2. Foreign -> string / -> ?string returns read garbage: C returns one
   char*, but the LLVM signature declared the fat {ptr,i64} (len =
   register garbage), and ?string was mis-declared SRET (the hidden
   out-pointer landed in the callee's first arg register). cstrRetKind
   now classifies such returns, declares them as plain ptr (never
   sret), and the call site synthesizes {ptr, strlen} via a
   branch-guarded strlen (NULL -> {null,0} / optional null), wrapping
   {string, i1} for ?string.

?[:0]u8 itself resolves fine (it is ?string); the spelling works in
return, param, local, and alias positions.

Regression: examples/1221 (plain + optional non-null + NULL paths) and
examples/1172 (conflict diagnostic); both FAIL pre-fix. The extern
dedupe collapses duplicate libc decls, so affected .ir snapshots were
regenerated. zig build test 426/426; run_examples 602/602;
distribution suite 21/21.
2026-06-12 14:13:01 +03:00

16 lines
573 B
Plaintext

// One C symbol bound twice with DIFFERENT sx signatures is diagnosed
// (issue 0128): the first registration used to silently win, mis-typing
// every call through the second declaration. Equal signatures share one
// registration silently (see std's read/write bound by several modules).
#import "modules/std.sx";
libc :: #library "c";
// std/process.sx already binds getenv as `-> *u8`; this view disagrees.
getenv_opt :: (name: [:0]u8) -> ?[:0]u8 #foreign libc "getenv";
main :: () -> i32 {
p := getenv_opt("PATH");
if p == null { return 1; }
return 0;
}