authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-24 16:48:15-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-24 23:30:57-07:00
logb3cd38ea4a7520fabbb05d3d2e74351c7c8effdb
tree51a821b640352c1967490e96165e2d5abbd94c2b
parent4f04759c874d5fd41c7cadeb974b4459559bc2a7

link: add an explicit error set for flush() and flushModule()

This makes it easier to understand how control flow should happen in various cases; already just by doing this it is revealed that UndefinedSymbol and UndefinedSymbolReference should be merged, and that MissingMainEntrypoint should be removed in favor of the ErrorFlags mechanism thath we already have for missing the main entrypoint. The main motivation for this change, however, is preventing a compile error when there is conditional compilation inside linker implementations, causing the flush() error set to depend on compilation options. With this change, the error set is fixed, and, notably, the `-Donly-c` flag no longer has compilation errors due to this error set.

10 files changed, 116 insertions(+), 33 deletions(-)

src/link.zig+86-3
......@@ -677,9 +677,92 @@ pub const File = struct {
677677 }
678678 }
679679
680 /// TODO audit this error set. most of these should be collapsed into one error,
681 /// and ErrorFlags should be updated to convey the meaning to the user.
682 pub const FlushError = error{
683 CacheUnavailable,
684 CurrentWorkingDirectoryUnlinked,
685 DivisionByZero,
686 DllImportLibraryNotFound,
687 EmptyStubFile,
688 ExpectedFuncType,
689 FailedToEmit,
690 FailedToResolveRelocationTarget,
691 FileSystem,
692 FilesOpenedWithWrongFlags,
693 FlushFailure,
694 FrameworkNotFound,
695 FunctionSignatureMismatch,
696 GlobalTypeMismatch,
697 InvalidCharacter,
698 InvalidEntryKind,
699 InvalidFormat,
700 InvalidIndex,
701 InvalidMagicByte,
702 InvalidWasmVersion,
703 LLDCrashed,
704 LLDReportedFailure,
705 LLD_LinkingIsTODO_ForSpirV,
706 LibCInstallationMissingCRTDir,
707 LibCInstallationNotAvailable,
708 LibraryNotFound,
709 LinkingWithoutZigSourceUnimplemented,
710 MalformedArchive,
711 MalformedDwarf,
712 MalformedSection,
713 MemoryTooBig,
714 MemoryTooSmall,
715 MismatchedCpuArchitecture,
716 MissAlignment,
717 MissingEndForBody,
718 MissingEndForExpression,
719 /// TODO: this should be removed from the error set in favor of using ErrorFlags
720 MissingMainEntrypoint,
721 MissingSymbol,
722 MissingTableSymbols,
723 ModuleNameMismatch,
724 MultipleSymbolDefinitions,
725 NoObjectsToLink,
726 NotObject,
727 NotObjectFile,
728 NotSupported,
729 OutOfMemory,
730 Overflow,
731 PermissionDenied,
732 StreamTooLong,
733 SwapFile,
734 SymbolCollision,
735 SymbolMismatchingType,
736 TODOImplementPlan9Objs,
737 TODOImplementWritingLibFiles,
738 TODOImplementWritingStaticLibFiles,
739 UnableToSpawnSelf,
740 UnableToSpawnWasm,
741 UnableToWriteArchive,
742 UndefinedLocal,
743 /// TODO: merge with UndefinedSymbolReference
744 UndefinedSymbol,
745 /// TODO: merge with UndefinedSymbol
746 UndefinedSymbolReference,
747 Underflow,
748 UnexpectedRemainder,
749 UnexpectedTable,
750 UnexpectedValue,
751 UnhandledDwFormValue,
752 UnhandledSymbolType,
753 UnknownFeature,
754 Unseekable,
755 UnsupportedCpuArchitecture,
756 UnsupportedVersion,
757 } ||
758 fs.File.WriteFileError ||
759 fs.File.OpenError ||
760 std.ChildProcess.SpawnError ||
761 fs.Dir.CopyFileError;
762
680763 /// Commit pending changes and write headers. Takes into account final output mode
681764 /// and `use_lld`, not only `effectiveOutputMode`.
682 pub fn flush(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) !void {
765 pub fn flush(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void {
683766 if (build_options.only_c) {
684767 assert(base.tag == .c);
685768 return @fieldParentPtr(C, "base", base).flush(comp, prog_node);
......@@ -717,7 +800,7 @@ pub const File = struct {
717800
718801 /// Commit pending changes and write headers. Works based on `effectiveOutputMode`
719802 /// rather than final output mode.
720 pub fn flushModule(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) !void {
803 pub fn flushModule(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void {
721804 if (build_options.only_c) {
722805 assert(base.tag == .c);
723806 return @fieldParentPtr(C, "base", base).flushModule(comp, prog_node);
......@@ -880,7 +963,7 @@ pub const File = struct {
880963 }
881964 }
882965
883 pub fn linkAsArchive(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) !void {
966 pub fn linkAsArchive(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void {
884967 const tracy = trace(@src());
885968 defer tracy.end();
886969
src/link/Coff.zig+2-2
......@@ -1442,7 +1442,7 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
14421442 gop.value_ptr.* = current;
14431443}
14441444
1445pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {
1445pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
14461446 if (self.base.options.emit == null) {
14471447 if (build_options.have_llvm) {
14481448 if (self.llvm_object) |llvm_object| {
......@@ -1461,7 +1461,7 @@ pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !vo
14611461 }
14621462}
14631463
1464pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {
1464pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
14651465 const tracy = trace(@src());
14661466 defer tracy.end();
14671467
src/link/Elf.zig+2-2
......@@ -932,7 +932,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
932932 }
933933}
934934
935pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {
935pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
936936 if (self.base.options.emit == null) {
937937 if (build_options.have_llvm) {
938938 if (self.llvm_object) |llvm_object| {
......@@ -951,7 +951,7 @@ pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !voi
951951 }
952952}
953953
954pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {
954pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
955955 const tracy = trace(@src());
956956 defer tracy.end();
957957
src/link/MachO.zig+2-2
......@@ -405,7 +405,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
405405 return self;
406406}
407407
408pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void {
408pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
409409 if (self.base.options.emit == null) {
410410 if (build_options.have_llvm) {
411411 if (self.llvm_object) |llvm_object| {
......@@ -430,7 +430,7 @@ pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !v
430430 }
431431}
432432
433pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void {
433pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
434434 const tracy = trace(@src());
435435 defer tracy.end();
436436
src/link/MachO/dead_strip.zig+12-12
......@@ -17,7 +17,7 @@ const N_DEAD = @import("zld.zig").N_DEAD;
1717
1818const AtomTable = std.AutoHashMap(AtomIndex, void);
1919
20pub fn gcAtoms(zld: *Zld, reverse_lookups: [][]u32) !void {
20pub fn gcAtoms(zld: *Zld, reverse_lookups: [][]u32) Allocator.Error!void {
2121 const gpa = zld.gpa;
2222
2323 var arena = std.heap.ArenaAllocator.init(gpa);
......@@ -30,8 +30,8 @@ pub fn gcAtoms(zld: *Zld, reverse_lookups: [][]u32) !void {
3030 try alive.ensureTotalCapacity(@intCast(u32, zld.atoms.items.len));
3131
3232 try collectRoots(zld, &roots);
33 try mark(zld, roots, &alive, reverse_lookups);
34 try prune(zld, alive);
33 mark(zld, roots, &alive, reverse_lookups);
34 prune(zld, alive);
3535}
3636
3737fn collectRoots(zld: *Zld, roots: *AtomTable) !void {
......@@ -133,7 +133,7 @@ fn markLive(
133133 atom_index: AtomIndex,
134134 alive: *AtomTable,
135135 reverse_lookups: [][]u32,
136) anyerror!void {
136) void {
137137 if (alive.contains(atom_index)) return;
138138
139139 const atom = zld.getAtom(atom_index);
......@@ -171,7 +171,7 @@ fn markLive(
171171 const other_atom = zld.getAtom(other_atom_index);
172172 const other_sym = zld.getSymbol(other_atom.getSymbolWithLoc());
173173 if (other_sym.n_sect == sect_id) {
174 try markLive(zld, other_atom_index, alive, reverse_lookups);
174 markLive(zld, other_atom_index, alive, reverse_lookups);
175175 }
176176 }
177177 continue;
......@@ -194,11 +194,11 @@ fn markLive(
194194 zld.getAtom(target_atom_index).file,
195195 });
196196
197 try markLive(zld, target_atom_index, alive, reverse_lookups);
197 markLive(zld, target_atom_index, alive, reverse_lookups);
198198 }
199199}
200200
201fn refersLive(zld: *Zld, atom_index: AtomIndex, alive: AtomTable, reverse_lookups: [][]u32) !bool {
201fn refersLive(zld: *Zld, atom_index: AtomIndex, alive: AtomTable, reverse_lookups: [][]u32) bool {
202202 const atom = zld.getAtom(atom_index);
203203 const sym_loc = atom.getSymbolWithLoc();
204204
......@@ -240,10 +240,10 @@ fn refersLive(zld: *Zld, atom_index: AtomIndex, alive: AtomTable, reverse_lookup
240240 return false;
241241}
242242
243fn mark(zld: *Zld, roots: AtomTable, alive: *AtomTable, reverse_lookups: [][]u32) !void {
243fn mark(zld: *Zld, roots: AtomTable, alive: *AtomTable, reverse_lookups: [][]u32) void {
244244 var it = roots.keyIterator();
245245 while (it.next()) |root| {
246 try markLive(zld, root.*, alive, reverse_lookups);
246 markLive(zld, root.*, alive, reverse_lookups);
247247 }
248248
249249 var loop: bool = true;
......@@ -265,8 +265,8 @@ fn mark(zld: *Zld, roots: AtomTable, alive: *AtomTable, reverse_lookups: [][]u32
265265 const source_sect = object.getSourceSection(sect_id);
266266
267267 if (source_sect.isDontDeadStripIfReferencesLive()) {
268 if (try refersLive(zld, atom_index, alive.*, reverse_lookups)) {
269 try markLive(zld, atom_index, alive, reverse_lookups);
268 if (refersLive(zld, atom_index, alive.*, reverse_lookups)) {
269 markLive(zld, atom_index, alive, reverse_lookups);
270270 loop = true;
271271 }
272272 }
......@@ -275,7 +275,7 @@ fn mark(zld: *Zld, roots: AtomTable, alive: *AtomTable, reverse_lookups: [][]u32
275275 }
276276}
277277
278fn prune(zld: *Zld, alive: AtomTable) !void {
278fn prune(zld: *Zld, alive: AtomTable) void {
279279 log.debug("pruning dead atoms", .{});
280280 for (zld.objects.items) |*object| {
281281 var i: usize = 0;
src/link/MachO/zld.zig+1-1
......@@ -3735,7 +3735,7 @@ const SymbolResolver = struct {
37353735 unresolved: std.AutoArrayHashMap(u32, void),
37363736};
37373737
3738pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) !void {
3738pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
37393739 const tracy = trace(@src());
37403740 defer tracy.end();
37413741
src/link/NvPtx.zig+2-2
......@@ -93,11 +93,11 @@ pub fn freeDecl(self: *NvPtx, decl_index: Module.Decl.Index) void {
9393 return self.llvm_object.freeDecl(decl_index);
9494}
9595
96pub fn flush(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.Node) !void {
96pub fn flush(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
9797 return self.flushModule(comp, prog_node);
9898}
9999
100pub fn flushModule(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.Node) !void {
100pub fn flushModule(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
101101 if (!build_options.have_llvm) return;
102102 if (build_options.skip_non_native) {
103103 @panic("Attempted to compile for architecture that was disabled by build configuration");
src/link/Plan9.zig+2-2
......@@ -356,7 +356,7 @@ fn updateFinish(self: *Plan9, decl: *Module.Decl) !void {
356356 }
357357}
358358
359pub fn flush(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) !void {
359pub fn flush(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
360360 assert(!self.base.options.use_lld);
361361
362362 switch (self.base.options.effectiveOutputMode()) {
......@@ -392,7 +392,7 @@ fn declCount(self: *Plan9) usize {
392392 return self.data_decl_table.count() + fn_decl_count;
393393}
394394
395pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) !void {
395pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
396396 if (build_options.skip_non_native and builtin.object_format != .plan9) {
397397 @panic("Attempted to compile for object format that was disabled by build configuration");
398398 }
src/link/SpirV.zig+2-2
......@@ -176,7 +176,7 @@ pub fn freeDecl(self: *SpirV, decl_index: Module.Decl.Index) void {
176176 self.decl_table.swapRemoveAt(index);
177177}
178178
179pub fn flush(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) !void {
179pub fn flush(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
180180 if (build_options.have_llvm and self.base.options.use_lld) {
181181 return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.
182182 } else {
......@@ -184,7 +184,7 @@ pub fn flush(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) !v
184184 }
185185}
186186
187pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) !void {
187pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
188188 if (build_options.skip_non_native) {
189189 @panic("Attempted to compile for architecture that was disabled by build configuration");
190190 }
src/link/Wasm.zig+5-5
......@@ -501,7 +501,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void {
501501 if (symbol.isUndefined()) {
502502 log.err("Local symbols are not allowed to reference imports", .{});
503503 log.err(" symbol '{s}' defined in '{s}'", .{ sym_name, object.name });
504 return error.undefinedLocal;
504 return error.UndefinedLocal;
505505 }
506506 try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {});
507507 continue;
......@@ -2091,7 +2091,7 @@ fn resetState(wasm: *Wasm) void {
20912091 wasm.debug_pubtypes_index = null;
20922092}
20932093
2094pub fn flush(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void {
2094pub fn flush(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
20952095 if (wasm.base.options.emit == null) {
20962096 if (build_options.have_llvm) {
20972097 if (wasm.llvm_object) |llvm_object| {
......@@ -2107,7 +2107,7 @@ pub fn flush(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !vo
21072107 }
21082108}
21092109
2110pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !void {
2110pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
21112111 const tracy = trace(@src());
21122112 defer tracy.end();
21132113
......@@ -3195,7 +3195,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
31953195
31963196 const term = child.spawnAndWait() catch |err| {
31973197 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
3198 return error.UnableToSpawnwasm;
3198 return error.UnableToSpawnWasm;
31993199 };
32003200 switch (term) {
32013201 .Exited => |code| {
......@@ -3216,7 +3216,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
32163216
32173217 const term = child.wait() catch |err| {
32183218 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
3219 return error.UnableToSpawnwasm;
3219 return error.UnableToSpawnWasm;
32203220 };
32213221
32223222 switch (term) {