mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
Sema: restore the extern lib name functionality
This commit is contained in:
parent
1f0fd64302
commit
7a27f0d80c
128
BRANCH_TODO
128
BRANCH_TODO
@ -55,132 +55,4 @@
|
||||
natural alignment for fields and do not have any comptime fields. this
|
||||
will save 16 bytes per struct field in the compilation.
|
||||
|
||||
pub fn analyzeNamespace(
|
||||
mod: *Module,
|
||||
namespace: *Scope.Namespace,
|
||||
decls: []const ast.Node.Index,
|
||||
) InnerError!void {
|
||||
for (decls) |decl_node| switch (node_tags[decl_node]) {
|
||||
.@"comptime" => {
|
||||
const name_index = mod.getNextAnonNameIndex();
|
||||
const name = try std.fmt.allocPrint(mod.gpa, "__comptime_{d}", .{name_index});
|
||||
defer mod.gpa.free(name);
|
||||
|
||||
const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
|
||||
|
||||
const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
|
||||
namespace.decls.putAssumeCapacity(new_decl, {});
|
||||
mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
|
||||
},
|
||||
|
||||
// Container fields are handled in AstGen.
|
||||
.container_field_init,
|
||||
.container_field_align,
|
||||
.container_field,
|
||||
=> continue,
|
||||
|
||||
.test_decl => {
|
||||
if (mod.comp.bin_file.options.is_test) {
|
||||
log.err("TODO: analyze test decl", .{});
|
||||
}
|
||||
},
|
||||
.@"usingnamespace" => {
|
||||
const name_index = mod.getNextAnonNameIndex();
|
||||
const name = try std.fmt.allocPrint(mod.gpa, "__usingnamespace_{d}", .{name_index});
|
||||
defer mod.gpa.free(name);
|
||||
|
||||
const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
|
||||
|
||||
const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
|
||||
namespace.decls.putAssumeCapacity(new_decl, {});
|
||||
|
||||
mod.ensureDeclAnalyzed(new_decl) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.AnalysisFail => continue,
|
||||
};
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Trailing:
|
||||
/// 0. `EmitH` if `module.emit_h != null`.
|
||||
/// 1. A per-Decl link object. Represents the position of the code in the output file.
|
||||
/// This is populated regardless of semantic analysis and code generation.
|
||||
/// Depending on the target, will be one of:
|
||||
/// * Elf.TextBlock
|
||||
/// * Coff.TextBlock
|
||||
/// * MachO.TextBlock
|
||||
/// * C.DeclBlock
|
||||
/// * Wasm.DeclBlock
|
||||
/// * void
|
||||
/// 2. If it is a function, a per-Decl link function object. Represents the
|
||||
/// function in the linked output file, if the `Decl` is a function.
|
||||
/// This is stored here and not in `Fn` because `Decl` survives across updates but
|
||||
/// `Fn` does not. Depending on the target, will be one of:
|
||||
/// * Elf.SrcFn
|
||||
/// * Coff.SrcFn
|
||||
/// * MachO.SrcFn
|
||||
/// * C.FnBlock
|
||||
/// * Wasm.FnData
|
||||
/// * SpirV.FnData
|
||||
|
||||
|
||||
extra_index += @boolToInt(has_align);
|
||||
extra_index += @boolToInt(has_section);
|
||||
|
||||
/// Contains un-analyzed ZIR instructions generated from Zig source AST.
|
||||
/// Even after we finish analysis, the ZIR is kept in memory, so that
|
||||
/// comptime and inline function calls can happen.
|
||||
/// Parameter names are stored here so that they may be referenced for debug info,
|
||||
/// without having source code bytes loaded into memory.
|
||||
/// The number of parameters is determined by referring to the type.
|
||||
/// The first N elements of `extra` are indexes into `string_bytes` to
|
||||
/// a null-terminated string.
|
||||
/// This memory is managed with gpa, must be freed when the function is freed.
|
||||
zir: Zir,
|
||||
|
||||
|
||||
if (fn_proto.lib_name) |lib_name_token| blk: {
|
||||
log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});
|
||||
mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {
|
||||
return mod.failTok(
|
||||
&fn_type_scope.base,
|
||||
lib_name_token,
|
||||
"unable to add link lib '{s}': {s}",
|
||||
.{ lib_name_str, @errorName(err) },
|
||||
);
|
||||
};
|
||||
const target = mod.comp.getTarget();
|
||||
if (target_util.is_libc_lib_name(target, lib_name_str)) {
|
||||
if (!mod.comp.bin_file.options.link_libc) {
|
||||
return mod.failTok(
|
||||
&fn_type_scope.base,
|
||||
lib_name_token,
|
||||
"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 (!mod.comp.bin_file.options.link_libcpp) {
|
||||
return mod.failTok(
|
||||
&fn_type_scope.base,
|
||||
lib_name_token,
|
||||
"dependency on libc++ must be explicitly specified in the build command",
|
||||
.{},
|
||||
);
|
||||
}
|
||||
break :blk;
|
||||
}
|
||||
if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
|
||||
return mod.failTok(
|
||||
&fn_type_scope.base,
|
||||
lib_name_token,
|
||||
"dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
|
||||
.{ lib_name_str, lib_name_str },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1603,6 +1603,34 @@ pub const SrcLoc = struct {
|
||||
const token_starts = tree.tokens.items(.start);
|
||||
return token_starts[tok_index];
|
||||
},
|
||||
|
||||
.node_offset_lib_name => |node_off| {
|
||||
const tree = try src_loc.file_scope.getTree(gpa);
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
const node_tags = tree.nodes.items(.tag);
|
||||
const parent_node = src_loc.declRelativeToNodeIndex(node_off);
|
||||
var params: [1]ast.Node.Index = undefined;
|
||||
const full = switch (node_tags[parent_node]) {
|
||||
.fn_proto_simple => tree.fnProtoSimple(¶ms, parent_node),
|
||||
.fn_proto_multi => tree.fnProtoMulti(parent_node),
|
||||
.fn_proto_one => tree.fnProtoOne(¶ms, parent_node),
|
||||
.fn_proto => tree.fnProto(parent_node),
|
||||
.fn_decl => blk: {
|
||||
const fn_proto = node_datas[parent_node].lhs;
|
||||
break :blk switch (node_tags[fn_proto]) {
|
||||
.fn_proto_simple => tree.fnProtoSimple(¶ms, fn_proto),
|
||||
.fn_proto_multi => tree.fnProtoMulti(fn_proto),
|
||||
.fn_proto_one => tree.fnProtoOne(¶ms, fn_proto),
|
||||
.fn_proto => tree.fnProto(fn_proto),
|
||||
else => unreachable,
|
||||
};
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
const tok_index = full.lib_name.?;
|
||||
const token_starts = tree.tokens.items(.start);
|
||||
return token_starts[tok_index];
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1768,6 +1796,12 @@ pub const LazySrcLoc = union(enum) {
|
||||
/// to the type expression.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_anyframe_type: i32,
|
||||
/// The source location points to the string literal of `extern "foo"`, found
|
||||
/// by taking this AST node index offset from the containing
|
||||
/// Decl AST node, which points to a function prototype or variable declaration
|
||||
/// expression AST node. Next, navigate to the string literal of the `extern "foo"`.
|
||||
/// The Decl is determined contextually.
|
||||
node_offset_lib_name: i32,
|
||||
|
||||
/// Upgrade to a `SrcLoc` based on the `Decl` or file in the provided scope.
|
||||
pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc {
|
||||
@ -1808,6 +1842,7 @@ pub const LazySrcLoc = union(enum) {
|
||||
.node_offset_fn_type_cc,
|
||||
.node_offset_fn_type_ret_ty,
|
||||
.node_offset_anyframe_type,
|
||||
.node_offset_lib_name,
|
||||
=> .{
|
||||
.file_scope = scope.getFileScope(),
|
||||
.parent_decl_node = scope.srcDecl().?.src_node,
|
||||
@ -1855,6 +1890,7 @@ pub const LazySrcLoc = union(enum) {
|
||||
.node_offset_fn_type_cc,
|
||||
.node_offset_fn_type_ret_ty,
|
||||
.node_offset_anyframe_type,
|
||||
.node_offset_lib_name,
|
||||
=> .{
|
||||
.file_scope = decl.getFileScope(),
|
||||
.parent_decl_node = decl.src_node,
|
||||
|
||||
59
src/Sema.zig
59
src/Sema.zig
@ -63,6 +63,7 @@ const InnerError = Module.InnerError;
|
||||
const Decl = Module.Decl;
|
||||
const LazySrcLoc = Module.LazySrcLoc;
|
||||
const RangeSet = @import("RangeSet.zig");
|
||||
const target_util = @import("target.zig");
|
||||
|
||||
pub fn analyzeFnBody(
|
||||
sema: *Sema,
|
||||
@ -2739,6 +2740,7 @@ fn zirFunc(
|
||||
false,
|
||||
inferred_error_set,
|
||||
src_locs,
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
@ -2754,11 +2756,14 @@ fn funcCommon(
|
||||
var_args: bool,
|
||||
inferred_error_set: bool,
|
||||
src_locs: Zir.Inst.Func.SrcLocs,
|
||||
opt_lib_name: ?[]const u8,
|
||||
) InnerError!*Inst {
|
||||
const src: LazySrcLoc = .{ .node_offset = src_node_offset };
|
||||
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
|
||||
const return_type = try sema.resolveType(block, ret_ty_src, zir_return_type);
|
||||
|
||||
const mod = sema.mod;
|
||||
|
||||
const fn_ty: Type = fn_ty: {
|
||||
// Hot path for some common function types.
|
||||
if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value) {
|
||||
@ -2789,7 +2794,7 @@ fn funcCommon(
|
||||
}
|
||||
|
||||
if (align_val.tag() != .null_value) {
|
||||
return sema.mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
|
||||
return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
|
||||
}
|
||||
|
||||
break :fn_ty try Type.Tag.function.create(sema.arena, .{
|
||||
@ -2801,7 +2806,48 @@ fn funcCommon(
|
||||
};
|
||||
|
||||
if (body_inst == 0) {
|
||||
return sema.mod.constType(sema.arena, src, fn_ty);
|
||||
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});
|
||||
mod.comp.stage1AddLinkLib(lib_name) catch |err| {
|
||||
return mod.fail(&block.base, lib_name_src, "unable to add link lib '{s}': {s}", .{
|
||||
lib_name, @errorName(err),
|
||||
});
|
||||
};
|
||||
const target = mod.getTarget();
|
||||
if (target_util.is_libc_lib_name(target, lib_name)) {
|
||||
if (!mod.comp.bin_file.options.link_libc) {
|
||||
return mod.fail(
|
||||
&block.base,
|
||||
lib_name_src,
|
||||
"dependency on libc must be explicitly specified in the build command",
|
||||
.{},
|
||||
);
|
||||
}
|
||||
break :blk;
|
||||
}
|
||||
if (target_util.is_libcpp_lib_name(target, lib_name)) {
|
||||
if (!mod.comp.bin_file.options.link_libcpp) {
|
||||
return mod.fail(
|
||||
&block.base,
|
||||
lib_name_src,
|
||||
"dependency on libc++ must be explicitly specified in the build command",
|
||||
.{},
|
||||
);
|
||||
}
|
||||
break :blk;
|
||||
}
|
||||
if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
|
||||
return mod.fail(
|
||||
&block.base,
|
||||
lib_name_src,
|
||||
"dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
|
||||
.{ lib_name, lib_name },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const is_inline = fn_ty.fnCallingConvention() == .Inline;
|
||||
@ -5599,11 +5645,13 @@ fn zirFuncExtended(
|
||||
const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small);
|
||||
|
||||
var extra_index: usize = extra.end;
|
||||
if (small.has_lib_name) {
|
||||
|
||||
const lib_name: ?[]const u8 = if (small.has_lib_name) blk: {
|
||||
const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
return sema.mod.fail(&block.base, src, "TODO: implement Sema func lib name", .{});
|
||||
}
|
||||
break :blk lib_name;
|
||||
} else null;
|
||||
|
||||
const cc: std.builtin.CallingConvention = if (small.has_cc) blk: {
|
||||
const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
@ -5640,6 +5688,7 @@ fn zirFuncExtended(
|
||||
small.is_var_args,
|
||||
small.is_inferred_error,
|
||||
src_locs,
|
||||
lib_name,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user