Skip to content

Commit 8adabaa

Browse files
committed
Zcu: don't tell linkers about exports if there are compile errors
In the best case, this is redundant work, because we aren't actually going to emit a working binary this update. In the worst case, it causes bugs because the linker may not have *seen* the thing being exported due to the compile errors. Resolves: #24417
1 parent ce2c939 commit 8adabaa

3 files changed

Lines changed: 28 additions & 12 deletions

File tree

src/Compilation.zig

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4254,14 +4254,10 @@ fn appendCompileLogLines(log_text: *std.ArrayListUnmanaged(u8), zcu: *Zcu, loggi
42544254
}
42554255
}
42564256

4257-
fn anyErrors(comp: *Compilation) bool {
4258-
return (totalErrorCount(comp) catch return true) != 0;
4259-
}
4260-
4261-
fn totalErrorCount(comp: *Compilation) !u32 {
4262-
var errors = try comp.getAllErrorsAlloc();
4257+
pub fn anyErrors(comp: *Compilation) bool {
4258+
var errors = comp.getAllErrorsAlloc() catch return true;
42634259
defer errors.deinit(comp.gpa);
4264-
return errors.errorMessageCount();
4260+
return errors.errorMessageCount() > 0;
42654261
}
42664262

42674263
pub const ErrorNoteHashContext = struct {

src/Zcu/PerThread.zig

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3149,18 +3149,23 @@ pub fn processExports(pt: Zcu.PerThread) !void {
31493149
}
31503150
}
31513151

3152+
// If there are compile errors, we won't call `updateExports`. Not only would it be redundant
3153+
// work, but the linker may not have seen an exported `Nav` due to a compile error, so linker
3154+
// implementations would have to handle that case. This early return avoids that.
3155+
const skip_linker_work = zcu.comp.anyErrors();
3156+
31523157
// Map symbol names to `Export` for name collision detection.
31533158
var symbol_exports: SymbolExports = .{};
31543159
defer symbol_exports.deinit(gpa);
31553160

31563161
for (nav_exports.keys(), nav_exports.values()) |exported_nav, exports_list| {
31573162
const exported: Zcu.Exported = .{ .nav = exported_nav };
3158-
try pt.processExportsInner(&symbol_exports, exported, exports_list.items);
3163+
try pt.processExportsInner(&symbol_exports, exported, exports_list.items, skip_linker_work);
31593164
}
31603165

31613166
for (uav_exports.keys(), uav_exports.values()) |exported_uav, exports_list| {
31623167
const exported: Zcu.Exported = .{ .uav = exported_uav };
3163-
try pt.processExportsInner(&symbol_exports, exported, exports_list.items);
3168+
try pt.processExportsInner(&symbol_exports, exported, exports_list.items, skip_linker_work);
31643169
}
31653170
}
31663171

@@ -3171,6 +3176,7 @@ fn processExportsInner(
31713176
symbol_exports: *SymbolExports,
31723177
exported: Zcu.Exported,
31733178
export_indices: []const Zcu.Export.Index,
3179+
skip_linker_work: bool,
31743180
) error{OutOfMemory}!void {
31753181
const zcu = pt.zcu;
31763182
const gpa = zcu.gpa;
@@ -3216,13 +3222,14 @@ fn processExportsInner(
32163222
}
32173223
break :failed false;
32183224
}) {
3219-
// This `Decl` is failed, so was never sent to codegen.
3220-
// TODO: we should probably tell the backend to delete any old exports of this `Decl`?
3221-
return;
3225+
// This `Nav` is failed, so was never sent to codegen. There should be a compile error.
3226+
assert(skip_linker_work);
32223227
},
32233228
.uav => {},
32243229
}
32253230

3231+
if (skip_linker_work) return;
3232+
32263233
if (zcu.llvm_object) |llvm_object| {
32273234
try zcu.handleUpdateExports(export_indices, llvm_object.updateExports(pt, exported, export_indices));
32283235
} else if (zcu.comp.bin_file) |lf| {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export fn foo() void {
2+
const S = struct { x: u32 = "bad default" };
3+
const s: S = undefined;
4+
_ = s;
5+
}
6+
7+
// This test case explicitly runs on the LLVM backend as well as self-hosted, as
8+
// the original bug leading to this test occurred only with the LLVM backend.
9+
10+
// error
11+
// backend=stage2,llvm
12+
//
13+
// :2:33: error: expected type 'u32', found '*const [11:0]u8'

0 commit comments

Comments
 (0)