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