feat(ffi-linkage): consume extern LIB "csym" rename for fns (Phase 1.2b)

parseFnDecl parses the optional [LIB] ["csym"] tail after the
extern/export keyword into FnDecl.extern_lib/extern_name (mirrors
'#foreign LIB "csym"'). declareFunction unifies the symbol-name
override: rename_c_name = foreign_expr.c_name (for #foreign) OR
fd.extern_name (for extern) -> declare under the C name and map sx->C
in foreign_name_map; the dedupe guard now covers extern too.

examples/1224 green: 'c_abs :: (n) -> i32 extern "abs";' resolves
c_abs to libc abs -> c_abs(-42) = 42. 1223 (bare extern) unregressed.
Suite green (635 corpus / 443 unit).

extern_lib is parsed + stored but not a linking driver — like
'#foreign libc', it references a lib; the #library decl + build flags
remain the separate linking axis (decision 4). green commit.
This commit is contained in:
agra
2026-06-14 13:30:59 +03:00
parent 5f946a3d44
commit 5777ff62ad
3 changed files with 47 additions and 17 deletions

View File

@@ -2118,29 +2118,34 @@ pub fn declareFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8)
// call-convention mismatch.
const cc: Function.CallingConvention = if (fd.call_conv == .c or is_foreign or is_extern_decl) .c else .default;
// For #foreign with C name override, declare under C name and map sx name → C name
if (is_foreign) {
const fe = fd.body.data.foreign_expr;
if (fe.c_name) |c_name| {
const c_name_id = self.module.types.internString(c_name);
if (self.dedupeForeignSymbol(fd, c_name_id, params.items, ret_ty)) {
self.foreign_name_map.put(name, c_name) catch {};
return;
}
const fid = self.builder.declareExtern(c_name_id, params.items, ret_ty);
const func = self.module.getFunctionMut(fid);
func.call_conv = cc;
func.source_file = self.current_source_file;
func.is_variadic = is_variadic;
func.has_implicit_ctx = wants_ctx;
// Symbol-name override: `#foreign … "csym"` (foreign_expr.c_name) or the new
// `extern … "csym"` (fd.extern_name). Declare under the C name and map the sx
// name → C name so call sites resolve to the real symbol.
const rename_c_name: ?[]const u8 = if (is_foreign)
fd.body.data.foreign_expr.c_name
else if (is_extern_decl)
fd.extern_name
else
null;
if (rename_c_name) |c_name| {
const c_name_id = self.module.types.internString(c_name);
if (self.dedupeForeignSymbol(fd, c_name_id, params.items, ret_ty)) {
self.foreign_name_map.put(name, c_name) catch {};
self.fn_decl_fids.put(fd, fid) catch {};
return;
}
const fid = self.builder.declareExtern(c_name_id, params.items, ret_ty);
const func = self.module.getFunctionMut(fid);
func.call_conv = cc;
func.source_file = self.current_source_file;
func.is_variadic = is_variadic;
func.has_implicit_ctx = wants_ctx;
self.foreign_name_map.put(name, c_name) catch {};
self.fn_decl_fids.put(fd, fid) catch {};
return;
}
const name_id = self.module.types.internString(name);
if (is_foreign and self.dedupeForeignSymbol(fd, name_id, params.items, ret_ty)) return;
if ((is_foreign or is_extern_decl) and self.dedupeForeignSymbol(fd, name_id, params.items, ret_ty)) return;
const fid = self.builder.declareExtern(name_id, params.items, ret_ty);
const func = self.module.getFunctionMut(fid);
func.call_conv = cc;