mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 16:24:51 +00:00
stage2: implement extern functions
This commit is contained in:
parent
47531b7d93
commit
6ac2047142
@ -1081,6 +1081,7 @@ fn fnProtoExpr(
|
||||
.is_var_args = is_var_args,
|
||||
.is_inferred_error = false,
|
||||
.is_test = false,
|
||||
.is_extern = false,
|
||||
});
|
||||
return rvalue(gz, scope, rl, result, fn_proto.ast.proto_node);
|
||||
}
|
||||
@ -2807,6 +2808,7 @@ fn fnDecl(
|
||||
.is_var_args = is_var_args,
|
||||
.is_inferred_error = false,
|
||||
.is_test = false,
|
||||
.is_extern = true,
|
||||
});
|
||||
} else func: {
|
||||
if (is_var_args) {
|
||||
@ -2883,6 +2885,7 @@ fn fnDecl(
|
||||
.is_var_args = is_var_args,
|
||||
.is_inferred_error = is_inferred_error,
|
||||
.is_test = false,
|
||||
.is_extern = false,
|
||||
});
|
||||
};
|
||||
|
||||
@ -3223,6 +3226,7 @@ fn testDecl(
|
||||
.is_var_args = false,
|
||||
.is_inferred_error = true,
|
||||
.is_test = true,
|
||||
.is_extern = false,
|
||||
});
|
||||
|
||||
_ = try decl_block.addBreak(.break_inline, block_inst, func_inst);
|
||||
@ -7973,6 +7977,7 @@ const GenZir = struct {
|
||||
is_var_args: bool,
|
||||
is_inferred_error: bool,
|
||||
is_test: bool,
|
||||
is_extern: bool,
|
||||
}) !Zir.Inst.Ref {
|
||||
assert(args.src_node != 0);
|
||||
assert(args.ret_ty != .none);
|
||||
@ -8010,7 +8015,8 @@ const GenZir = struct {
|
||||
}
|
||||
|
||||
if (args.cc != .none or args.lib_name != 0 or
|
||||
args.is_var_args or args.is_test or args.align_inst != .none)
|
||||
args.is_var_args or args.is_test or args.align_inst != .none or
|
||||
args.is_extern)
|
||||
{
|
||||
try astgen.extra.ensureUnusedCapacity(
|
||||
gpa,
|
||||
@ -8051,6 +8057,7 @@ const GenZir = struct {
|
||||
.has_cc = args.cc != .none,
|
||||
.has_align = args.align_inst != .none,
|
||||
.is_test = args.is_test,
|
||||
.is_extern = args.is_extern,
|
||||
}),
|
||||
.operand = payload_index,
|
||||
} },
|
||||
|
||||
@ -282,13 +282,10 @@ pub const Decl = struct {
|
||||
|
||||
pub fn destroy(decl: *Decl, module: *Module) void {
|
||||
const gpa = module.gpa;
|
||||
log.debug("destroy Decl {*} ({s})", .{ decl, decl.name });
|
||||
log.debug("destroy {*} ({s})", .{ decl, decl.name });
|
||||
decl.clearName(gpa);
|
||||
if (decl.has_tv) {
|
||||
if (decl.getFunction()) |func| {
|
||||
func.deinit(gpa);
|
||||
gpa.destroy(func);
|
||||
} else if (decl.val.getTypeNamespace()) |namespace| {
|
||||
if (decl.val.getTypeNamespace()) |namespace| {
|
||||
if (namespace.getDecl() == decl) {
|
||||
namespace.clearDecls(module);
|
||||
}
|
||||
@ -470,7 +467,6 @@ pub const Decl = struct {
|
||||
/// otherwise null.
|
||||
pub fn getFunction(decl: *Decl) ?*Fn {
|
||||
if (!decl.has_tv) return null;
|
||||
if (decl.ty.zigTypeTag() != .Fn) return null;
|
||||
const func = (decl.val.castTag(.function) orelse return null).data;
|
||||
if (func.owner_decl != decl) return null;
|
||||
return func;
|
||||
@ -2960,17 +2956,26 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
|
||||
decl.clearValues(gpa);
|
||||
}
|
||||
|
||||
const new_variable = try decl_arena.allocator.create(Var);
|
||||
new_variable.* = .{
|
||||
.owner_decl = decl,
|
||||
.init = try decl_tv.val.copy(&decl_arena.allocator),
|
||||
.is_extern = is_extern,
|
||||
.is_mutable = is_mutable,
|
||||
.is_threadlocal = is_threadlocal,
|
||||
const copied_val = try decl_tv.val.copy(&decl_arena.allocator);
|
||||
const is_extern_fn = copied_val.tag() == .extern_fn;
|
||||
|
||||
// TODO: also avoid allocating this Var structure if `!is_mutable`.
|
||||
// I think this will require adjusting Sema to copy the value or something
|
||||
// like that; otherwise it causes use of undefined value when freeing resources.
|
||||
const decl_val: Value = if (is_extern_fn) copied_val else blk: {
|
||||
const new_variable = try decl_arena.allocator.create(Var);
|
||||
new_variable.* = .{
|
||||
.owner_decl = decl,
|
||||
.init = copied_val,
|
||||
.is_extern = is_extern,
|
||||
.is_mutable = is_mutable,
|
||||
.is_threadlocal = is_threadlocal,
|
||||
};
|
||||
break :blk try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
|
||||
};
|
||||
|
||||
decl.ty = try decl_tv.ty.copy(&decl_arena.allocator);
|
||||
decl.val = try Value.Tag.variable.create(&decl_arena.allocator, new_variable);
|
||||
decl.val = decl_val;
|
||||
decl.align_val = try align_val.copy(&decl_arena.allocator);
|
||||
decl.linksection_val = try linksection_val.copy(&decl_arena.allocator);
|
||||
decl.has_tv = true;
|
||||
@ -2984,6 +2989,16 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
|
||||
// The scope needs to have the decl in it.
|
||||
try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl);
|
||||
}
|
||||
|
||||
if (decl.val.tag() == .extern_fn) {
|
||||
try mod.comp.bin_file.allocateDeclIndexes(decl);
|
||||
try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
|
||||
|
||||
if (type_changed and mod.emit_h != null) {
|
||||
try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
|
||||
}
|
||||
}
|
||||
|
||||
return type_changed;
|
||||
}
|
||||
}
|
||||
|
||||
18
src/Sema.zig
18
src/Sema.zig
@ -2819,6 +2819,7 @@ fn zirFunc(
|
||||
Value.initTag(.null_value),
|
||||
false,
|
||||
inferred_error_set,
|
||||
false,
|
||||
src_locs,
|
||||
null,
|
||||
);
|
||||
@ -2835,6 +2836,7 @@ fn funcCommon(
|
||||
align_val: Value,
|
||||
var_args: bool,
|
||||
inferred_error_set: bool,
|
||||
is_extern: bool,
|
||||
src_locs: Zir.Inst.Func.SrcLocs,
|
||||
opt_lib_name: ?[]const u8,
|
||||
) InnerError!*Inst {
|
||||
@ -2885,10 +2887,6 @@ fn funcCommon(
|
||||
});
|
||||
};
|
||||
|
||||
if (body_inst == 0) {
|
||||
return mod.constType(sema.arena, src, fn_ty);
|
||||
}
|
||||
|
||||
if (opt_lib_name) |lib_name| blk: {
|
||||
const lib_name_src: LazySrcLoc = .{ .node_offset_lib_name = src_node_offset };
|
||||
log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});
|
||||
@ -2930,6 +2928,17 @@ fn funcCommon(
|
||||
}
|
||||
}
|
||||
|
||||
if (is_extern) {
|
||||
return sema.mod.constInst(sema.arena, src, .{
|
||||
.ty = fn_ty,
|
||||
.val = try Value.Tag.extern_fn.create(sema.arena, sema.owner_decl),
|
||||
});
|
||||
}
|
||||
|
||||
if (body_inst == 0) {
|
||||
return mod.constType(sema.arena, src, fn_ty);
|
||||
}
|
||||
|
||||
const is_inline = fn_ty.fnCallingConvention() == .Inline;
|
||||
const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;
|
||||
|
||||
@ -5795,6 +5804,7 @@ fn zirFuncExtended(
|
||||
align_val,
|
||||
small.is_var_args,
|
||||
small.is_inferred_error,
|
||||
small.is_extern,
|
||||
src_locs,
|
||||
lib_name,
|
||||
);
|
||||
|
||||
@ -2217,7 +2217,8 @@ pub const Inst = struct {
|
||||
has_cc: bool,
|
||||
has_align: bool,
|
||||
is_test: bool,
|
||||
_: u10 = undefined,
|
||||
is_extern: bool,
|
||||
_: u9 = undefined,
|
||||
};
|
||||
};
|
||||
|
||||
@ -4103,6 +4104,7 @@ const Writer = struct {
|
||||
extra.data.return_type,
|
||||
inferred_error_set,
|
||||
false,
|
||||
false,
|
||||
.none,
|
||||
.none,
|
||||
body,
|
||||
@ -4150,6 +4152,7 @@ const Writer = struct {
|
||||
extra.data.return_type,
|
||||
small.is_inferred_error,
|
||||
small.is_var_args,
|
||||
small.is_extern,
|
||||
cc,
|
||||
align_inst,
|
||||
body,
|
||||
@ -4232,6 +4235,7 @@ const Writer = struct {
|
||||
ret_ty: Inst.Ref,
|
||||
inferred_error_set: bool,
|
||||
var_args: bool,
|
||||
is_extern: bool,
|
||||
cc: Inst.Ref,
|
||||
align_inst: Inst.Ref,
|
||||
body: []const Inst.Index,
|
||||
@ -4248,6 +4252,7 @@ const Writer = struct {
|
||||
try self.writeOptionalInstRef(stream, ", cc=", cc);
|
||||
try self.writeOptionalInstRef(stream, ", align=", align_inst);
|
||||
try self.writeFlag(stream, ", vargs", var_args);
|
||||
try self.writeFlag(stream, ", extern", is_extern);
|
||||
try self.writeFlag(stream, ", inferror", inferred_error_set);
|
||||
|
||||
if (body.len == 0) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user