diff --git a/src/Module.zig b/src/Module.zig index 8575c59f4c..0bdeab68d0 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -22,6 +22,7 @@ const ast = std.zig.ast; const trace = @import("tracy.zig").trace; const astgen = @import("astgen.zig"); const zir_sema = @import("zir_sema.zig"); +const target_util = @import("target.zig"); const default_eval_branch_quota = 1000; @@ -1109,8 +1110,48 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { if (fn_proto.getVarArgsToken()) |var_args_token| { return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{}); } - if (fn_proto.getLibName()) |lib_name| { - return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{}); + if (fn_proto.getLibName()) |lib_name| blk: { + const lib_name_str = mem.trim(u8, tree.tokenSlice(lib_name.firstToken()), "\""); // TODO: call identifierTokenString + log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str}); + const target = self.comp.getTarget(); + if (target_util.is_libc_lib_name(target, lib_name_str)) { + if (!self.comp.bin_file.options.link_libc) { + return self.failNode( + &fn_type_scope.base, + lib_name, + "dependency on libc must be explicitly specified in the build command", + .{}, + ); + } + break :blk; + } + if (target_util.is_libcpp_lib_name(target, lib_name_str)) { + if (!self.comp.bin_file.options.link_libcpp) { + return self.failNode( + &fn_type_scope.base, + lib_name, + "dependency on libc++ must be explicitly specified in the build command", + .{}, + ); + } + break :blk; + } + if (!target.isWasm() and !self.comp.bin_file.options.pic) { + return self.failNode( + &fn_type_scope.base, + lib_name, + "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.", + .{ lib_name, lib_name }, + ); + } + self.comp.stage1AddLinkLib(lib_name_str) catch |err| { + return self.failNode( + &fn_type_scope.base, + lib_name, + "unable to add link lib '{s}': {s}", + .{ lib_name, @errorName(err) }, + ); + }; } if (fn_proto.getAlignExpr()) |align_expr| { return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{}); diff --git a/src/codegen.zig b/src/codegen.zig index eba5cb7913..d83eba2219 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -1602,6 +1602,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { try self.code.ensureCapacity(self.code.items.len + 7); self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 }); mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr); + } else if (func_value.castTag(.extern_fn)) |_| { + return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); } else { return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); } @@ -1628,6 +1630,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr }); mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); + } else if (func_value.castTag(.extern_fn)) |_| { + return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); } else { return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); } @@ -1672,6 +1676,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}), } } + } else if (func_value.castTag(.extern_fn)) |_| { + return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); } else { return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); } @@ -1733,6 +1739,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .lr, Instruction.Operand.reg(.pc, Instruction.Operand.Shift.none)).toU32()); writeInt(u32, try self.code.addManyAsArray(4), Instruction.bx(.al, .lr).toU32()); } + } else if (func_value.castTag(.extern_fn)) |_| { + return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); } else { return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); } @@ -1787,6 +1795,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { try self.genSetReg(inst.base.src, .x30, .{ .memory = got_addr }); writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32()); + } else if (func_value.castTag(.extern_fn)) |_| { + return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); } else { return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); } @@ -1849,6 +1859,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { }, else => unreachable, // unsupported architecture on MachO } + } else if (func_value.castTag(.extern_fn)) |_| { + return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); } else { return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); } diff --git a/src/link/Coff.zig b/src/link/Coff.zig index f7d646356c..f7cd9b69ce 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -662,10 +662,14 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { if (build_options.have_llvm) if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.updateDecl(module, decl); + const typed_value = decl.typed_value.most_recent.typed_value; + if (typed_value.val.tag() == .extern_fn) { + return; // TODO Should we do more when front-end analyzed extern decl? + } + var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); - const typed_value = decl.typed_value.most_recent.typed_value; const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .none); const code = switch (res) { .externally_managed => |x| x, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index f3073824a5..8c76a4e967 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2157,6 +2157,11 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { if (build_options.have_llvm) if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.updateDecl(module, decl); + const typed_value = decl.typed_value.most_recent.typed_value; + if (typed_value.val.tag() == .extern_fn) { + return; // TODO Should we do more when front-end analyzed extern decl? + } + var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -2175,7 +2180,6 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { dbg_info_type_relocs.deinit(self.base.allocator); } - const typed_value = decl.typed_value.most_recent.typed_value; const is_fn: bool = switch (typed_value.ty.zigTypeTag()) { .Fn => true, else => false, diff --git a/src/link/MachO.zig b/src/link/MachO.zig index efb16e4d1c..dbc982f5e2 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -1118,6 +1118,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { const tracy = trace(@src()); defer tracy.end(); + const typed_value = decl.typed_value.most_recent.typed_value; + if (typed_value.val.tag() == .extern_fn) { + return; // TODO Should we do more when front-end analyzed extern decl? + } + var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -1134,7 +1139,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { } } - const typed_value = decl.typed_value.most_recent.typed_value; const res = if (debug_buffers) |*dbg| try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .{ .dwarf = .{ diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index cbb3e83147..576be2d306 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -100,8 +100,11 @@ pub fn deinit(self: *Wasm) void { // Generate code for the Decl, storing it in memory to be later written to // the file on flush(). pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { - if (decl.typed_value.most_recent.typed_value.ty.zigTypeTag() != .Fn) + const typed_value = decl.typed_value.most_recent.typed_value; + if (typed_value.ty.zigTypeTag() != .Fn) return error.TODOImplementNonFnDeclsForWasm; + if (typed_value.val.tag() == .extern_fn) + return error.TODOImplementExternFnDeclsForWasm; if (decl.fn_link.wasm) |*fn_data| { fn_data.functype.items.len = 0;