feat(ffi-linkage): lower extern data globals (Phase 1.2d) — Phase 1 complete
Parser: a 'kw_extern' branch in the var-decl-with-type-annotation path (beside #foreign) parses 'name : type extern [LIB] ["csym"];' into VarDecl.is_extern/extern_lib/extern_name; the trailing diagnostic now lists 'extern'. Lowering: registerTopLevelGlobal uses extern_name orelse foreign_name orelse name for the C symbol and sets is_extern = is_foreign or is_extern; globalInitValue returns null (no initializer) for extern globals too. examples/1225 green: '__stdinp : *void extern;' lowers to '@__stdinp = external global ptr'; @__stdinp reads non-null. Suite green (636 corpus / 443 unit). Phase 1 done: extern functions (bare + rename) and data globals (bare + rename) all work, behavior-equivalent to the matching #foreign form. export (Phase 2), aggregates (Phase 3), docs + A->B gate (Phase 4) remain. green commit.
This commit is contained in:
@@ -1112,10 +1112,11 @@ pub fn registerTopLevelGlobal(self: *Lowering, vd: *const ast.VarDecl) void {
|
||||
d.addFmt(.err, null, "top-level var '{s}' has no type annotation and no initializer to infer from", .{vd.name});
|
||||
break :blk .void;
|
||||
};
|
||||
// Foreign globals reference a symbol defined in libSystem etc.
|
||||
// (`_NSConcreteStackBlock : *void #foreign;`). The C symbol
|
||||
// name is the optional override or the sx name itself.
|
||||
const sym_name = vd.foreign_name orelse vd.name;
|
||||
// Foreign / extern globals reference a symbol defined in libSystem etc.
|
||||
// (`_NSConcreteStackBlock : *void #foreign;` or `… : *void extern;`). The C
|
||||
// symbol name is the optional override (`extern_name`/`foreign_name`) or the
|
||||
// sx name itself.
|
||||
const sym_name = vd.extern_name orelse vd.foreign_name orelse vd.name;
|
||||
const name_id = self.module.types.internString(sym_name);
|
||||
const init_val = self.globalInitValue(vd, var_ty);
|
||||
const gid = self.module.addGlobal(.{
|
||||
@@ -1123,7 +1124,7 @@ pub fn registerTopLevelGlobal(self: *Lowering, vd: *const ast.VarDecl) void {
|
||||
.ty = var_ty,
|
||||
.init_val = init_val,
|
||||
.is_const = false,
|
||||
.is_extern = vd.is_foreign,
|
||||
.is_extern = vd.is_foreign or vd.is_extern,
|
||||
});
|
||||
self.putGlobal(self.current_source_file, vd.name, .{ .id = gid, .ty = var_ty });
|
||||
}
|
||||
@@ -1137,7 +1138,7 @@ pub fn registerTopLevelGlobal(self: *Lowering, vd: *const ast.VarDecl) void {
|
||||
/// is rejected with a diagnostic rather than silently zero-initialized — a
|
||||
/// global has no run site for a dynamic initializer.
|
||||
pub fn globalInitValue(self: *Lowering, vd: *const ast.VarDecl, var_ty: TypeId) ?inst_mod.ConstantValue {
|
||||
if (vd.is_foreign) return null;
|
||||
if (vd.is_foreign or vd.is_extern) return null;
|
||||
const v = vd.value orelse return null;
|
||||
return switch (v.data) {
|
||||
.undef_literal => .zeroinit,
|
||||
|
||||
@@ -449,7 +449,35 @@ pub const Parser = struct {
|
||||
} });
|
||||
}
|
||||
|
||||
return self.fail("expected ':', '=', ';' or '#foreign' after type annotation");
|
||||
if (self.current.tag == .kw_extern) {
|
||||
// name : type extern [LIB] ["csym"]; (extern data global — the
|
||||
// extern-named counterpart of `#foreign`; resolved at link time)
|
||||
self.advance();
|
||||
var ext_lib: ?[]const u8 = null;
|
||||
if (self.current.tag == .identifier) {
|
||||
ext_lib = self.tokenSlice(self.current);
|
||||
self.advance();
|
||||
}
|
||||
var ext_name: ?[]const u8 = null;
|
||||
if (self.current.tag == .string_literal) {
|
||||
const raw = self.tokenSlice(self.current);
|
||||
ext_name = raw[1 .. raw.len - 1];
|
||||
self.advance();
|
||||
}
|
||||
try self.expect(.semicolon);
|
||||
return try self.createNode(start_pos, .{ .var_decl = .{
|
||||
.name = name,
|
||||
.name_span = name_span,
|
||||
.type_annotation = type_node,
|
||||
.value = null,
|
||||
.is_extern = true,
|
||||
.extern_lib = ext_lib,
|
||||
.extern_name = ext_name,
|
||||
.is_raw = name_is_raw,
|
||||
} });
|
||||
}
|
||||
|
||||
return self.fail("expected ':', '=', ';', '#foreign', or 'extern' after type annotation");
|
||||
}
|
||||
|
||||
fn parseTypeExpr(self: *Parser) anyerror!*Node {
|
||||
|
||||
Reference in New Issue
Block a user