authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-04 14:40:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-04 14:40:59-07:00
log7a27f0d80c5ce9d596b2b43699e131ab387e1317
tree8b0d7bb597244f9b8bdc03a87be62154a9706ad8
parent1f0fd643025d4508f84a236453168173290a01a0

Sema: restore the extern lib name functionality


3 files changed, 90 insertions(+), 133 deletions(-)

BRANCH_TODO-128
......@@ -55,132 +55,4 @@
5555 natural alignment for fields and do not have any comptime fields. this
5656 will save 16 bytes per struct field in the compilation.
5757
58pub fn analyzeNamespace(
59 mod: *Module,
60 namespace: *Scope.Namespace,
61 decls: []const ast.Node.Index,
62) InnerError!void {
63 for (decls) |decl_node| switch (node_tags[decl_node]) {
64 .@"comptime" => {
65 const name_index = mod.getNextAnonNameIndex();
66 const name = try std.fmt.allocPrint(mod.gpa, "__comptime_{d}", .{name_index});
67 defer mod.gpa.free(name);
68
69 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
70
71 const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
72 namespace.decls.putAssumeCapacity(new_decl, {});
73 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
74 },
75
76 // Container fields are handled in AstGen.
77 .container_field_init,
78 .container_field_align,
79 .container_field,
80 => continue,
81
82 .test_decl => {
83 if (mod.comp.bin_file.options.is_test) {
84 log.err("TODO: analyze test decl", .{});
85 }
86 },
87 .@"usingnamespace" => {
88 const name_index = mod.getNextAnonNameIndex();
89 const name = try std.fmt.allocPrint(mod.gpa, "__usingnamespace_{d}", .{name_index});
90 defer mod.gpa.free(name);
91
92 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
93
94 const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
95 namespace.decls.putAssumeCapacity(new_decl, {});
96
97 mod.ensureDeclAnalyzed(new_decl) catch |err| switch (err) {
98 error.OutOfMemory => return error.OutOfMemory,
99 error.AnalysisFail => continue,
100 };
101 },
102 else => unreachable,
103 };
104}
105
106/// Trailing:
107/// 0. `EmitH` if `module.emit_h != null`.
108/// 1. A per-Decl link object. Represents the position of the code in the output file.
109/// This is populated regardless of semantic analysis and code generation.
110/// Depending on the target, will be one of:
111/// * Elf.TextBlock
112/// * Coff.TextBlock
113/// * MachO.TextBlock
114/// * C.DeclBlock
115/// * Wasm.DeclBlock
116/// * void
117/// 2. If it is a function, a per-Decl link function object. Represents the
118/// function in the linked output file, if the `Decl` is a function.
119/// This is stored here and not in `Fn` because `Decl` survives across updates but
120/// `Fn` does not. Depending on the target, will be one of:
121/// * Elf.SrcFn
122/// * Coff.SrcFn
123/// * MachO.SrcFn
124/// * C.FnBlock
125/// * Wasm.FnData
126/// * SpirV.FnData
127
128
129 extra_index += @boolToInt(has_align);
130 extra_index += @boolToInt(has_section);
131
132 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
133 /// Even after we finish analysis, the ZIR is kept in memory, so that
134 /// comptime and inline function calls can happen.
135 /// Parameter names are stored here so that they may be referenced for debug info,
136 /// without having source code bytes loaded into memory.
137 /// The number of parameters is determined by referring to the type.
138 /// The first N elements of `extra` are indexes into `string_bytes` to
139 /// a null-terminated string.
140 /// This memory is managed with gpa, must be freed when the function is freed.
141 zir: Zir,
142
143
144 if (fn_proto.lib_name) |lib_name_token| blk: {
145 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});
146 mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {
147 return mod.failTok(
148 &fn_type_scope.base,
149 lib_name_token,
150 "unable to add link lib '{s}': {s}",
151 .{ lib_name_str, @errorName(err) },
152 );
153 };
154 const target = mod.comp.getTarget();
155 if (target_util.is_libc_lib_name(target, lib_name_str)) {
156 if (!mod.comp.bin_file.options.link_libc) {
157 return mod.failTok(
158 &fn_type_scope.base,
159 lib_name_token,
160 "dependency on libc must be explicitly specified in the build command",
161 .{},
162 );
163 }
164 break :blk;
165 }
166 if (target_util.is_libcpp_lib_name(target, lib_name_str)) {
167 if (!mod.comp.bin_file.options.link_libcpp) {
168 return mod.failTok(
169 &fn_type_scope.base,
170 lib_name_token,
171 "dependency on libc++ must be explicitly specified in the build command",
172 .{},
173 );
174 }
175 break :blk;
176 }
177 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
178 return mod.failTok(
179 &fn_type_scope.base,
180 lib_name_token,
181 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
182 .{ lib_name_str, lib_name_str },
183 );
184 }
185 }
18658
src/Module.zig+36
......@@ -1603,6 +1603,34 @@ pub const SrcLoc = struct {
16031603 const token_starts = tree.tokens.items(.start);
16041604 return token_starts[tok_index];
16051605 },
1606
1607 .node_offset_lib_name => |node_off| {
1608 const tree = try src_loc.file_scope.getTree(gpa);
1609 const node_datas = tree.nodes.items(.data);
1610 const node_tags = tree.nodes.items(.tag);
1611 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
1612 var params: [1]ast.Node.Index = undefined;
1613 const full = switch (node_tags[parent_node]) {
1614 .fn_proto_simple => tree.fnProtoSimple(&params, parent_node),
1615 .fn_proto_multi => tree.fnProtoMulti(parent_node),
1616 .fn_proto_one => tree.fnProtoOne(&params, parent_node),
1617 .fn_proto => tree.fnProto(parent_node),
1618 .fn_decl => blk: {
1619 const fn_proto = node_datas[parent_node].lhs;
1620 break :blk switch (node_tags[fn_proto]) {
1621 .fn_proto_simple => tree.fnProtoSimple(&params, fn_proto),
1622 .fn_proto_multi => tree.fnProtoMulti(fn_proto),
1623 .fn_proto_one => tree.fnProtoOne(&params, fn_proto),
1624 .fn_proto => tree.fnProto(fn_proto),
1625 else => unreachable,
1626 };
1627 },
1628 else => unreachable,
1629 };
1630 const tok_index = full.lib_name.?;
1631 const token_starts = tree.tokens.items(.start);
1632 return token_starts[tok_index];
1633 },
16061634 }
16071635 }
16081636};
......@@ -1768,6 +1796,12 @@ pub const LazySrcLoc = union(enum) {
17681796 /// to the type expression.
17691797 /// The Decl is determined contextually.
17701798 node_offset_anyframe_type: i32,
1799 /// The source location points to the string literal of `extern "foo"`, found
1800 /// by taking this AST node index offset from the containing
1801 /// Decl AST node, which points to a function prototype or variable declaration
1802 /// expression AST node. Next, navigate to the string literal of the `extern "foo"`.
1803 /// The Decl is determined contextually.
1804 node_offset_lib_name: i32,
17711805
17721806 /// Upgrade to a `SrcLoc` based on the `Decl` or file in the provided scope.
17731807 pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc {
......@@ -1808,6 +1842,7 @@ pub const LazySrcLoc = union(enum) {
18081842 .node_offset_fn_type_cc,
18091843 .node_offset_fn_type_ret_ty,
18101844 .node_offset_anyframe_type,
1845 .node_offset_lib_name,
18111846 => .{
18121847 .file_scope = scope.getFileScope(),
18131848 .parent_decl_node = scope.srcDecl().?.src_node,
......@@ -1855,6 +1890,7 @@ pub const LazySrcLoc = union(enum) {
18551890 .node_offset_fn_type_cc,
18561891 .node_offset_fn_type_ret_ty,
18571892 .node_offset_anyframe_type,
1893 .node_offset_lib_name,
18581894 => .{
18591895 .file_scope = decl.getFileScope(),
18601896 .parent_decl_node = decl.src_node,
src/Sema.zig+54-5
......@@ -63,6 +63,7 @@ const InnerError = Module.InnerError;
6363const Decl = Module.Decl;
6464const LazySrcLoc = Module.LazySrcLoc;
6565const RangeSet = @import("RangeSet.zig");
66const target_util = @import("target.zig");
6667
6768pub fn analyzeFnBody(
6869 sema: *Sema,
......@@ -2739,6 +2740,7 @@ fn zirFunc(
27392740 false,
27402741 inferred_error_set,
27412742 src_locs,
2743 null,
27422744 );
27432745}
27442746
......@@ -2754,11 +2756,14 @@ fn funcCommon(
27542756 var_args: bool,
27552757 inferred_error_set: bool,
27562758 src_locs: Zir.Inst.Func.SrcLocs,
2759 opt_lib_name: ?[]const u8,
27572760) InnerError!*Inst {
27582761 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
27592762 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
27602763 const return_type = try sema.resolveType(block, ret_ty_src, zir_return_type);
27612764
2765 const mod = sema.mod;
2766
27622767 const fn_ty: Type = fn_ty: {
27632768 // Hot path for some common function types.
27642769 if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value) {
......@@ -2789,7 +2794,7 @@ fn funcCommon(
27892794 }
27902795
27912796 if (align_val.tag() != .null_value) {
2792 return sema.mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
2797 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
27932798 }
27942799
27952800 break :fn_ty try Type.Tag.function.create(sema.arena, .{
......@@ -2801,7 +2806,48 @@ fn funcCommon(
28012806 };
28022807
28032808 if (body_inst == 0) {
2804 return sema.mod.constType(sema.arena, src, fn_ty);
2809 return mod.constType(sema.arena, src, fn_ty);
2810 }
2811
2812 if (opt_lib_name) |lib_name| blk: {
2813 const lib_name_src: LazySrcLoc = .{ .node_offset_lib_name = src_node_offset };
2814 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});
2815 mod.comp.stage1AddLinkLib(lib_name) catch |err| {
2816 return mod.fail(&block.base, lib_name_src, "unable to add link lib '{s}': {s}", .{
2817 lib_name, @errorName(err),
2818 });
2819 };
2820 const target = mod.getTarget();
2821 if (target_util.is_libc_lib_name(target, lib_name)) {
2822 if (!mod.comp.bin_file.options.link_libc) {
2823 return mod.fail(
2824 &block.base,
2825 lib_name_src,
2826 "dependency on libc must be explicitly specified in the build command",
2827 .{},
2828 );
2829 }
2830 break :blk;
2831 }
2832 if (target_util.is_libcpp_lib_name(target, lib_name)) {
2833 if (!mod.comp.bin_file.options.link_libcpp) {
2834 return mod.fail(
2835 &block.base,
2836 lib_name_src,
2837 "dependency on libc++ must be explicitly specified in the build command",
2838 .{},
2839 );
2840 }
2841 break :blk;
2842 }
2843 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
2844 return mod.fail(
2845 &block.base,
2846 lib_name_src,
2847 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
2848 .{ lib_name, lib_name },
2849 );
2850 }
28052851 }
28062852
28072853 const is_inline = fn_ty.fnCallingConvention() == .Inline;
......@@ -5599,11 +5645,13 @@ fn zirFuncExtended(
55995645 const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small);
56005646
56015647 var extra_index: usize = extra.end;
5602 if (small.has_lib_name) {
5648
5649 const lib_name: ?[]const u8 = if (small.has_lib_name) blk: {
56035650 const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]);
56045651 extra_index += 1;
5605 return sema.mod.fail(&block.base, src, "TODO: implement Sema func lib name", .{});
5606 }
5652 break :blk lib_name;
5653 } else null;
5654
56075655 const cc: std.builtin.CallingConvention = if (small.has_cc) blk: {
56085656 const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
56095657 extra_index += 1;
......@@ -5640,6 +5688,7 @@ fn zirFuncExtended(
56405688 small.is_var_args,
56415689 small.is_inferred_error,
56425690 src_locs,
5691 lib_name,
56435692 );
56445693}
56455694