| author | |
| committer | |
| log | 7a27f0d80c5ce9d596b2b43699e131ab387e1317 |
| tree | 8b0d7bb597244f9b8bdc03a87be62154a9706ad8 |
| parent | 1f0fd643025d4508f84a236453168173290a01a0 |
3 files changed, 90 insertions(+), 133 deletions(-)
BRANCH_TODO-128| ... | ... | @@ -55,132 +55,4 @@ |
| 55 | 55 | natural alignment for fields and do not have any comptime fields. this |
| 56 | 56 | will save 16 bytes per struct field in the compilation. |
| 57 | 57 | |
| 58 | pub 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 | } | |
| 186 | 58 |
src/Module.zig+36| ... | ... | @@ -1603,6 +1603,34 @@ pub const SrcLoc = struct { |
| 1603 | 1603 | const token_starts = tree.tokens.items(.start); |
| 1604 | 1604 | return token_starts[tok_index]; |
| 1605 | 1605 | }, |
| 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 | }, | |
| 1606 | 1634 | } |
| 1607 | 1635 | } |
| 1608 | 1636 | }; |
| ... | ... | @@ -1768,6 +1796,12 @@ pub const LazySrcLoc = union(enum) { |
| 1768 | 1796 | /// to the type expression. |
| 1769 | 1797 | /// The Decl is determined contextually. |
| 1770 | 1798 | 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, | |
| 1771 | 1805 | |
| 1772 | 1806 | /// Upgrade to a `SrcLoc` based on the `Decl` or file in the provided scope. |
| 1773 | 1807 | pub fn toSrcLoc(lazy: LazySrcLoc, scope: *Scope) SrcLoc { |
| ... | ... | @@ -1808,6 +1842,7 @@ pub const LazySrcLoc = union(enum) { |
| 1808 | 1842 | .node_offset_fn_type_cc, |
| 1809 | 1843 | .node_offset_fn_type_ret_ty, |
| 1810 | 1844 | .node_offset_anyframe_type, |
| 1845 | .node_offset_lib_name, | |
| 1811 | 1846 | => .{ |
| 1812 | 1847 | .file_scope = scope.getFileScope(), |
| 1813 | 1848 | .parent_decl_node = scope.srcDecl().?.src_node, |
| ... | ... | @@ -1855,6 +1890,7 @@ pub const LazySrcLoc = union(enum) { |
| 1855 | 1890 | .node_offset_fn_type_cc, |
| 1856 | 1891 | .node_offset_fn_type_ret_ty, |
| 1857 | 1892 | .node_offset_anyframe_type, |
| 1893 | .node_offset_lib_name, | |
| 1858 | 1894 | => .{ |
| 1859 | 1895 | .file_scope = decl.getFileScope(), |
| 1860 | 1896 | .parent_decl_node = decl.src_node, |
src/Sema.zig+54-5| ... | ... | @@ -63,6 +63,7 @@ const InnerError = Module.InnerError; |
| 63 | 63 | const Decl = Module.Decl; |
| 64 | 64 | const LazySrcLoc = Module.LazySrcLoc; |
| 65 | 65 | const RangeSet = @import("RangeSet.zig"); |
| 66 | const target_util = @import("target.zig"); | |
| 66 | 67 | |
| 67 | 68 | pub fn analyzeFnBody( |
| 68 | 69 | sema: *Sema, |
| ... | ... | @@ -2739,6 +2740,7 @@ fn zirFunc( |
| 2739 | 2740 | false, |
| 2740 | 2741 | inferred_error_set, |
| 2741 | 2742 | src_locs, |
| 2743 | null, | |
| 2742 | 2744 | ); |
| 2743 | 2745 | } |
| 2744 | 2746 | |
| ... | ... | @@ -2754,11 +2756,14 @@ fn funcCommon( |
| 2754 | 2756 | var_args: bool, |
| 2755 | 2757 | inferred_error_set: bool, |
| 2756 | 2758 | src_locs: Zir.Inst.Func.SrcLocs, |
| 2759 | opt_lib_name: ?[]const u8, | |
| 2757 | 2760 | ) InnerError!*Inst { |
| 2758 | 2761 | const src: LazySrcLoc = .{ .node_offset = src_node_offset }; |
| 2759 | 2762 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; |
| 2760 | 2763 | const return_type = try sema.resolveType(block, ret_ty_src, zir_return_type); |
| 2761 | 2764 | |
| 2765 | const mod = sema.mod; | |
| 2766 | ||
| 2762 | 2767 | const fn_ty: Type = fn_ty: { |
| 2763 | 2768 | // Hot path for some common function types. |
| 2764 | 2769 | if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value) { |
| ... | ... | @@ -2789,7 +2794,7 @@ fn funcCommon( |
| 2789 | 2794 | } |
| 2790 | 2795 | |
| 2791 | 2796 | 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", .{}); | |
| 2793 | 2798 | } |
| 2794 | 2799 | |
| 2795 | 2800 | break :fn_ty try Type.Tag.function.create(sema.arena, .{ |
| ... | ... | @@ -2801,7 +2806,48 @@ fn funcCommon( |
| 2801 | 2806 | }; |
| 2802 | 2807 | |
| 2803 | 2808 | 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 | } | |
| 2805 | 2851 | } |
| 2806 | 2852 | |
| 2807 | 2853 | const is_inline = fn_ty.fnCallingConvention() == .Inline; |
| ... | ... | @@ -5599,11 +5645,13 @@ fn zirFuncExtended( |
| 5599 | 5645 | const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small); |
| 5600 | 5646 | |
| 5601 | 5647 | 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: { | |
| 5603 | 5650 | const lib_name = sema.code.nullTerminatedString(sema.code.extra[extra_index]); |
| 5604 | 5651 | 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 | ||
| 5607 | 5655 | const cc: std.builtin.CallingConvention = if (small.has_cc) blk: { |
| 5608 | 5656 | const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 5609 | 5657 | extra_index += 1; |
| ... | ... | @@ -5640,6 +5688,7 @@ fn zirFuncExtended( |
| 5640 | 5688 | small.is_var_args, |
| 5641 | 5689 | small.is_inferred_error, |
| 5642 | 5690 | src_locs, |
| 5691 | lib_name, | |
| 5643 | 5692 | ); |
| 5644 | 5693 | } |
| 5645 | 5694 |