| author | |
| committer | |
| log | 6561a98a61bb54c9d6c868f788da3eaa6f48d2c3 |
| tree | 429a38f476c8c0ecc1bf211df83b5596f8824ba6 |
| parent | f01833e03eea786a05635cfbe142f581e9281b51 |
| signature | Commit is signed but in an unrecognized format. |
Resolves: #236042 files changed, 190 insertions(+), 3 deletions(-)
src/Zcu/PerThread.zig+29-3| ... | @@ -2837,6 +2837,11 @@ pub fn processExports(pt: Zcu.PerThread) !void { | ... | @@ -2837,6 +2837,11 @@ pub fn processExports(pt: Zcu.PerThread) !void { |
| 2837 | const zcu = pt.zcu; | 2837 | const zcu = pt.zcu; |
| 2838 | const gpa = zcu.gpa; | 2838 | const gpa = zcu.gpa; |
| 2839 | 2839 | ||
| 2840 | if (zcu.single_exports.count() == 0 and zcu.multi_exports.count() == 0) { | ||
| 2841 | // We can avoid a call to `resolveReferences` in this case. | ||
| 2842 | return; | ||
| 2843 | } | ||
| 2844 | |||
| 2840 | // First, construct a mapping of every exported value and Nav to the indices of all its different exports. | 2845 | // First, construct a mapping of every exported value and Nav to the indices of all its different exports. |
| 2841 | var nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, std.ArrayListUnmanaged(Zcu.Export.Index)) = .empty; | 2846 | var nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, std.ArrayListUnmanaged(Zcu.Export.Index)) = .empty; |
| 2842 | var uav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, std.ArrayListUnmanaged(Zcu.Export.Index)) = .empty; | 2847 | var uav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, std.ArrayListUnmanaged(Zcu.Export.Index)) = .empty; |
| ... | @@ -2857,8 +2862,18 @@ pub fn processExports(pt: Zcu.PerThread) !void { | ... | @@ -2857,8 +2862,18 @@ pub fn processExports(pt: Zcu.PerThread) !void { |
| 2857 | // So, this ensureTotalCapacity serves as a reasonable (albeit very approximate) optimization. | 2862 | // So, this ensureTotalCapacity serves as a reasonable (albeit very approximate) optimization. |
| 2858 | try nav_exports.ensureTotalCapacity(gpa, zcu.single_exports.count() + zcu.multi_exports.count()); | 2863 | try nav_exports.ensureTotalCapacity(gpa, zcu.single_exports.count() + zcu.multi_exports.count()); |
| 2859 | 2864 | ||
| 2860 | for (zcu.single_exports.values()) |export_idx| { | 2865 | const unit_references = try zcu.resolveReferences(); |
| 2866 | |||
| 2867 | for (zcu.single_exports.keys(), zcu.single_exports.values()) |exporter, export_idx| { | ||
| 2861 | const exp = export_idx.ptr(zcu); | 2868 | const exp = export_idx.ptr(zcu); |
| 2869 | if (!unit_references.contains(exporter)) { | ||
| 2870 | // This export might already have been sent to the linker on a previous update, in which case we need to delete it. | ||
| 2871 | // The linker export API should be modified to eliminate this call. #23616 | ||
| 2872 | if (zcu.comp.bin_file) |lf| { | ||
| 2873 | lf.deleteExport(exp.exported, exp.opts.name); | ||
| 2874 | } | ||
| 2875 | continue; | ||
| 2876 | } | ||
| 2862 | const value_ptr, const found_existing = switch (exp.exported) { | 2877 | const value_ptr, const found_existing = switch (exp.exported) { |
| 2863 | .nav => |nav| gop: { | 2878 | .nav => |nav| gop: { |
| 2864 | const gop = try nav_exports.getOrPut(gpa, nav); | 2879 | const gop = try nav_exports.getOrPut(gpa, nav); |
| ... | @@ -2873,8 +2888,19 @@ pub fn processExports(pt: Zcu.PerThread) !void { | ... | @@ -2873,8 +2888,19 @@ pub fn processExports(pt: Zcu.PerThread) !void { |
| 2873 | try value_ptr.append(gpa, export_idx); | 2888 | try value_ptr.append(gpa, export_idx); |
| 2874 | } | 2889 | } |
| 2875 | 2890 | ||
| 2876 | for (zcu.multi_exports.values()) |info| { | 2891 | for (zcu.multi_exports.keys(), zcu.multi_exports.values()) |exporter, info| { |
| 2877 | for (zcu.all_exports.items[info.index..][0..info.len], info.index..) |exp, export_idx| { | 2892 | const exports = zcu.all_exports.items[info.index..][0..info.len]; |
| 2893 | if (!unit_references.contains(exporter)) { | ||
| 2894 | // This export might already have been sent to the linker on a previous update, in which case we need to delete it. | ||
| 2895 | // The linker export API should be modified to eliminate this loop. #23616 | ||
| 2896 | if (zcu.comp.bin_file) |lf| { | ||
| 2897 | for (exports) |exp| { | ||
| 2898 | lf.deleteExport(exp.exported, exp.opts.name); | ||
| 2899 | } | ||
| 2900 | } | ||
| 2901 | continue; | ||
| 2902 | } | ||
| 2903 | for (exports, info.index..) |exp, export_idx| { | ||
| 2878 | const value_ptr, const found_existing = switch (exp.exported) { | 2904 | const value_ptr, const found_existing = switch (exp.exported) { |
| 2879 | .nav => |nav| gop: { | 2905 | .nav => |nav| gop: { |
| 2880 | const gop = try nav_exports.getOrPut(gpa, nav); | 2906 | const gop = try nav_exports.getOrPut(gpa, nav); |
test/incremental/change_exports created+161| ... | @@ -0,0 +1,161 @@ | ||
| 1 | #target=x86_64-linux-selfhosted | ||
| 2 | #target=x86_64-linux-cbe | ||
| 3 | #target=x86_64-windows-cbe | ||
| 4 | |||
| 5 | #update=initial version | ||
| 6 | #file=main.zig | ||
| 7 | export fn foo() void {} | ||
| 8 | const bar: u32 = 123; | ||
| 9 | const other: u32 = 456; | ||
| 10 | comptime { | ||
| 11 | @export(&bar, .{ .name = "bar" }); | ||
| 12 | } | ||
| 13 | pub fn main() !void { | ||
| 14 | const S = struct { | ||
| 15 | extern fn foo() void; | ||
| 16 | extern const bar: u32; | ||
| 17 | }; | ||
| 18 | S.foo(); | ||
| 19 | try std.io.getStdOut().writer().print("{}\n", .{S.bar}); | ||
| 20 | } | ||
| 21 | const std = @import("std"); | ||
| 22 | #expect_stdout="123\n" | ||
| 23 | |||
| 24 | #update=add conflict | ||
| 25 | #file=main.zig | ||
| 26 | export fn foo() void {} | ||
| 27 | const bar: u32 = 123; | ||
| 28 | const other: u32 = 456; | ||
| 29 | comptime { | ||
| 30 | @export(&bar, .{ .name = "bar" }); | ||
| 31 | @export(&other, .{ .name = "foo" }); | ||
| 32 | } | ||
| 33 | pub fn main() !void { | ||
| 34 | const S = struct { | ||
| 35 | extern fn foo() void; | ||
| 36 | extern const bar: u32; | ||
| 37 | extern const other: u32; | ||
| 38 | }; | ||
| 39 | S.foo(); | ||
| 40 | try std.io.getStdOut().writer().print("{} {}\n", .{ S.bar, S.other }); | ||
| 41 | } | ||
| 42 | const std = @import("std"); | ||
| 43 | #expect_error=main.zig:6:5: error: exported symbol collision: foo | ||
| 44 | #expect_error=main.zig:1:1: note: other symbol here | ||
| 45 | |||
| 46 | #update=resolve conflict | ||
| 47 | #file=main.zig | ||
| 48 | export fn foo() void {} | ||
| 49 | const bar: u32 = 123; | ||
| 50 | const other: u32 = 456; | ||
| 51 | comptime { | ||
| 52 | @export(&bar, .{ .name = "bar" }); | ||
| 53 | @export(&other, .{ .name = "other" }); | ||
| 54 | } | ||
| 55 | pub fn main() !void { | ||
| 56 | const S = struct { | ||
| 57 | extern fn foo() void; | ||
| 58 | extern const bar: u32; | ||
| 59 | extern const other: u32; | ||
| 60 | }; | ||
| 61 | S.foo(); | ||
| 62 | try std.io.getStdOut().writer().print("{} {}\n", .{ S.bar, S.other }); | ||
| 63 | } | ||
| 64 | const std = @import("std"); | ||
| 65 | #expect_stdout="123 456\n" | ||
| 66 | |||
| 67 | #update=put exports in decl | ||
| 68 | #file=main.zig | ||
| 69 | export fn foo() void {} | ||
| 70 | const bar: u32 = 123; | ||
| 71 | const other: u32 = 456; | ||
| 72 | const does_exports = { | ||
| 73 | @export(&bar, .{ .name = "bar" }); | ||
| 74 | @export(&other, .{ .name = "other" }); | ||
| 75 | }; | ||
| 76 | comptime { | ||
| 77 | _ = does_exports; | ||
| 78 | } | ||
| 79 | pub fn main() !void { | ||
| 80 | const S = struct { | ||
| 81 | extern fn foo() void; | ||
| 82 | extern const bar: u32; | ||
| 83 | extern const other: u32; | ||
| 84 | }; | ||
| 85 | S.foo(); | ||
| 86 | try std.io.getStdOut().writer().print("{} {}\n", .{ S.bar, S.other }); | ||
| 87 | } | ||
| 88 | const std = @import("std"); | ||
| 89 | #expect_stdout="123 456\n" | ||
| 90 | |||
| 91 | #update=remove reference to exporting decl | ||
| 92 | #file=main.zig | ||
| 93 | export fn foo() void {} | ||
| 94 | const bar: u32 = 123; | ||
| 95 | const other: u32 = 456; | ||
| 96 | const does_exports = { | ||
| 97 | @export(&bar, .{ .name = "bar" }); | ||
| 98 | @export(&other, .{ .name = "other" }); | ||
| 99 | }; | ||
| 100 | comptime { | ||
| 101 | //_ = does_exports; | ||
| 102 | } | ||
| 103 | pub fn main() !void { | ||
| 104 | const S = struct { | ||
| 105 | extern fn foo() void; | ||
| 106 | }; | ||
| 107 | S.foo(); | ||
| 108 | } | ||
| 109 | const std = @import("std"); | ||
| 110 | #expect_stdout="" | ||
| 111 | |||
| 112 | #update=mark consts as export | ||
| 113 | #file=main.zig | ||
| 114 | export fn foo() void {} | ||
| 115 | export const bar: u32 = 123; | ||
| 116 | export const other: u32 = 456; | ||
| 117 | const does_exports = { | ||
| 118 | @export(&bar, .{ .name = "bar" }); | ||
| 119 | @export(&other, .{ .name = "other" }); | ||
| 120 | }; | ||
| 121 | comptime { | ||
| 122 | //_ = does_exports; | ||
| 123 | } | ||
| 124 | pub fn main() !void { | ||
| 125 | const S = struct { | ||
| 126 | extern fn foo() void; | ||
| 127 | extern const bar: u32; | ||
| 128 | extern const other: u32; | ||
| 129 | }; | ||
| 130 | S.foo(); | ||
| 131 | try std.io.getStdOut().writer().print("{} {}\n", .{ S.bar, S.other }); | ||
| 132 | } | ||
| 133 | const std = @import("std"); | ||
| 134 | #expect_stdout="123 456\n" | ||
| 135 | |||
| 136 | #update=reintroduce reference to exporting decl, introducing conflict | ||
| 137 | #file=main.zig | ||
| 138 | export fn foo() void {} | ||
| 139 | export const bar: u32 = 123; | ||
| 140 | export const other: u32 = 456; | ||
| 141 | const does_exports = { | ||
| 142 | @export(&bar, .{ .name = "bar" }); | ||
| 143 | @export(&other, .{ .name = "other" }); | ||
| 144 | }; | ||
| 145 | comptime { | ||
| 146 | _ = does_exports; | ||
| 147 | } | ||
| 148 | pub fn main() !void { | ||
| 149 | const S = struct { | ||
| 150 | extern fn foo() void; | ||
| 151 | extern const bar: u32; | ||
| 152 | extern const other: u32; | ||
| 153 | }; | ||
| 154 | S.foo(); | ||
| 155 | try std.io.getStdOut().writer().print("{} {}\n", .{ S.bar, S.other }); | ||
| 156 | } | ||
| 157 | const std = @import("std"); | ||
| 158 | #expect_error=main.zig:5:5: error: exported symbol collision: bar | ||
| 159 | #expect_error=main.zig:2:1: note: other symbol here | ||
| 160 | #expect_error=main.zig:6:5: error: exported symbol collision: other | ||
| 161 | #expect_error=main.zig:3:1: note: other symbol here | ||