Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stage2: add compile log statement #7191

Merged
merged 13 commits into from
Dec 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1329,8 +1329,11 @@ pub fn totalErrorCount(self: *Compilation) usize {
var total: usize = self.failed_c_objects.items().len;

if (self.bin_file.options.module) |module| {
total += module.failed_decls.items().len +
module.failed_exports.items().len +
for (module.failed_decls.items()) |entry| {
assert(entry.value.items.len > 0);
total += entry.value.items.len;
}
total += module.failed_exports.items().len +
module.failed_files.items().len +
@boolToInt(module.failed_root_src_file != null);
}
Expand Down Expand Up @@ -1364,9 +1367,11 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
}
for (module.failed_decls.items()) |entry| {
const decl = entry.key;
const err_msg = entry.value;
const source = try decl.scope.getSource(module);
try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
const err_msg_list = entry.value;
for (err_msg_list.items) |err_msg| {
const source = try decl.scope.getSource(module);
try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
}
}
for (module.failed_exports.items()) |entry| {
const decl = entry.key.owner_decl;
Expand Down Expand Up @@ -1459,16 +1464,14 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
}

assert(decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits());

self.bin_file.updateDecl(module, decl) catch |err| {
switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => {
decl.analysis = .dependency_failure;
},
else => {
try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);
module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
try module.addDeclErr(decl, try ErrorMsg.create(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every instance of this change introduced a memory leak if ErrorMsg.create fails.

module.gpa,
decl.src(),
"unable to codegen: {}",
Expand All @@ -1487,8 +1490,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
decl.analysis = .dependency_failure;
},
else => {
try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);
module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
try module.addDeclErr(decl, try ErrorMsg.create(
module.gpa,
decl.src(),
"unable to generate C header: {}",
Expand All @@ -1510,8 +1512,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
.update_line_number => |decl| {
const module = self.bin_file.options.module.?;
self.bin_file.updateDeclLineNumber(module, decl) catch |err| {
try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);
module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
try module.addDeclErr(decl, try ErrorMsg.create(
module.gpa,
decl.src(),
"unable to update line number: {}",
Expand Down
46 changes: 29 additions & 17 deletions src/Module.zig
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ decl_table: std.ArrayHashMapUnmanaged(Scope.NameHash, *Decl, Scope.name_hash_has
/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
/// Note that a Decl can succeed but the Fn it represents can fail. In this case,
/// a Decl can have a failed_decls entry but have analysis status of success.
failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *Compilation.ErrorMsg) = .{},
failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, ArrayListUnmanaged(*Compilation.ErrorMsg)) = .{},
/// Using a map here for consistency with the other fields here.
/// The ErrorMsg memory is owned by the `Scope`, using Module's general purpose allocator.
failed_files: std.AutoArrayHashMapUnmanaged(*Scope, *Compilation.ErrorMsg) = .{},
Expand Down Expand Up @@ -845,8 +845,11 @@ pub fn deinit(self: *Module) void {
}
self.decl_table.deinit(gpa);

for (self.failed_decls.items()) |entry| {
entry.value.destroy(gpa);
for (self.failed_decls.items()) |*entry| {
for (entry.value.items) |compile_err| {
compile_err.destroy(gpa);
}
entry.value.deinit(gpa);
}
self.failed_decls.deinit(gpa);

Expand Down Expand Up @@ -942,8 +945,7 @@ pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => return error.AnalysisFail,
else => {
try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
self.failed_decls.putAssumeCapacityNoClobber(decl, try Compilation.ErrorMsg.create(
try self.addDeclErr(decl, try Compilation.ErrorMsg.create(
self.gpa,
decl.src(),
"unable to analyze: {}",
Expand Down Expand Up @@ -1550,7 +1552,7 @@ pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void
decl.analysis = .sema_failure;
const err_msg = try Compilation.ErrorMsg.create(self.gpa, tree.token_locs[name_tok].start, "redefinition of '{}'", .{decl.name});
errdefer err_msg.destroy(self.gpa);
try self.failed_decls.putNoClobber(self.gpa, decl, err_msg);
try self.addDeclErr(decl, err_msg);
} else {
if (!srcHashEql(decl.contents_hash, contents_hash)) {
try self.markOutdatedDecl(decl);
Expand Down Expand Up @@ -1592,7 +1594,7 @@ pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void
decl.analysis = .sema_failure;
const err_msg = try Compilation.ErrorMsg.create(self.gpa, name_loc.start, "redefinition of '{}'", .{decl.name});
errdefer err_msg.destroy(self.gpa);
try self.failed_decls.putNoClobber(self.gpa, decl, err_msg);
try self.addDeclErr(decl, err_msg);
} else if (!srcHashEql(decl.contents_hash, contents_hash)) {
try self.markOutdatedDecl(decl);
decl.contents_hash = contents_hash;
Expand Down Expand Up @@ -1718,8 +1720,11 @@ pub fn deleteDecl(self: *Module, decl: *Decl) !void {
try self.markOutdatedDecl(dep);
}
}
if (self.failed_decls.remove(decl)) |entry| {
entry.value.destroy(self.gpa);
if (self.failed_decls.remove(decl)) |*entry| {
for (entry.value.items) |compile_err| {
compile_err.destroy(self.gpa);
}
entry.value.deinit(self.gpa);
}
self.deleteDeclExports(decl);
self.comp.bin_file.freeDecl(decl);
Expand Down Expand Up @@ -1798,8 +1803,11 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
log.debug("mark {} outdated\n", .{decl.name});
try self.comp.work_queue.writeItem(.{ .analyze_decl = decl });
if (self.failed_decls.remove(decl)) |entry| {
entry.value.destroy(self.gpa);
if (self.failed_decls.remove(decl)) |*entry| {
for (entry.value.items) |compile_err| {
compile_err.destroy(self.gpa);
}
entry.value.deinit(self.gpa);
}
decl.analysis = .outdated;
}
Expand Down Expand Up @@ -2944,18 +2952,22 @@ pub fn failNode(
return self.fail(scope, src, format, args);
}

pub fn addDeclErr(self: *Module, decl: *Decl, err: *Compilation.ErrorMsg) error{OutOfMemory}!void {
const entry = try self.failed_decls.getOrPutValue(self.gpa, decl, .{});
try entry.value.append(self.gpa, err);
}

fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Compilation.ErrorMsg) InnerError {
{
errdefer err_msg.destroy(self.gpa);
try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
}
switch (scope.tag) {
.decl => {
const decl = scope.cast(Scope.DeclAnalysis).?.decl;
decl.analysis = .sema_failure;
decl.generation = self.generation;
self.failed_decls.putAssumeCapacityNoClobber(decl, err_msg);
try self.addDeclErr(decl, err_msg);
},
.block => {
const block = scope.cast(Scope.Block).?;
Expand All @@ -2965,25 +2977,25 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Com
block.decl.analysis = .sema_failure;
block.decl.generation = self.generation;
}
self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg);
try self.addDeclErr(block.decl, err_msg);
},
.gen_zir => {
const gen_zir = scope.cast(Scope.GenZIR).?;
gen_zir.decl.analysis = .sema_failure;
gen_zir.decl.generation = self.generation;
self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
try self.addDeclErr(gen_zir.decl, err_msg);
},
.local_val => {
const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir;
gen_zir.decl.analysis = .sema_failure;
gen_zir.decl.generation = self.generation;
self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
try self.addDeclErr(gen_zir.decl, err_msg);
},
.local_ptr => {
const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir;
gen_zir.decl.analysis = .sema_failure;
gen_zir.decl.generation = self.generation;
self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
try self.addDeclErr(gen_zir.decl, err_msg);
},
.zir_module => {
const zir_module = scope.cast(Scope.ZIRModule).?;
Expand Down
13 changes: 13 additions & 0 deletions src/astgen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2248,6 +2248,17 @@ fn import(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*
return addZIRUnOp(mod, scope, src, .import, target);
}

fn compileLog(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
const tree = scope.tree();
const arena = scope.arena();
const src = tree.token_locs[call.builtin_token].start;
const params = call.params();
var targets = try arena.alloc(*zir.Inst, params.len);
for (params) |param, param_i|
targets[param_i] = try expr(mod, scope, .none, param);
return addZIRInst(mod, scope, src, zir.Inst.CompileLog, .{ .to_log = targets }, .{});
}

fn typeOf(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
const tree = scope.tree();
const arena = scope.arena();
Expand Down Expand Up @@ -2291,6 +2302,8 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built
return rlWrap(mod, scope, rl, try addZIRNoOp(mod, scope, src, .breakpoint));
} else if (mem.eql(u8, builtin_name, "@import")) {
return rlWrap(mod, scope, rl, try import(mod, scope, call));
} else if (mem.eql(u8, builtin_name, "@compileLog")) {
return compileLog(mod, scope, call);
} else {
return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{}'", .{builtin_name});
}
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub fn generateHeader(
const writer = header.buf.writer();
renderFunctionSignature(&ctx, header, writer, decl) catch |err| {
if (err == error.AnalysisFail) {
try module.failed_decls.put(module.gpa, decl, ctx.error_msg);
try module.addDeclErr(decl, ctx.error_msg);
}
return err;
};
Expand Down
2 changes: 1 addition & 1 deletion src/link/C.zig
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub fn deinit(self: *C) void {
pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
codegen.generate(self, decl) catch |err| {
if (err == error.AnalysisFail) {
try module.failed_decls.put(module.gpa, decl, self.error_msg);
try module.addDeclErr(decl, self.error_msg);
}
return err;
};
Expand Down
2 changes: 1 addition & 1 deletion src/link/Coff.zig
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
.appended => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
try module.failed_decls.put(module.gpa, decl, em);
try module.addDeclErr(decl, em);
return;
},
};
Expand Down
2 changes: 1 addition & 1 deletion src/link/Elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2244,7 +2244,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
.appended => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
try module.failed_decls.put(module.gpa, decl, em);
try module.addDeclErr(decl, em);
return;
},
};
Expand Down
2 changes: 1 addition & 1 deletion src/link/MachO.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1062,7 +1062,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
.appended => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
try module.failed_decls.put(module.gpa, decl, em);
try module.addDeclErr(decl, em);
return;
},
};
Expand Down
2 changes: 1 addition & 1 deletion src/value.zig
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ pub const Value = extern union {
val = elem_ptr.array_ptr;
},
.empty_array => return out_stream.writeAll(".{}"),
.enum_literal => return out_stream.print(".{z}", .{self.cast(Payload.Bytes).?.data}),
.enum_literal => return out_stream.print(".{z}", .{@fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise).data}),
.bytes => return out_stream.print("\"{Z}\"", .{self.cast(Payload.Bytes).?.data}),
.repeated => {
try out_stream.writeAll("(repeated) ");
Expand Down
23 changes: 20 additions & 3 deletions src/zir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ pub const Inst = struct {
coerce_to_ptr_elem,
/// Emit an error message and fail compilation.
compileerror,
/// Log compile time variables and emit an error message.
compilelog,
/// Conditional branch. Splits control flow based on a boolean condition value.
condbr,
/// Special case, has no textual representation.
Expand Down Expand Up @@ -386,6 +388,7 @@ pub const Inst = struct {
.declval_in_module => DeclValInModule,
.coerce_result_block_ptr => CoerceResultBlockPtr,
.compileerror => CompileError,
.compilelog => CompileLog,
.loop => Loop,
.@"const" => Const,
.str => Str,
Expand Down Expand Up @@ -513,6 +516,7 @@ pub const Inst = struct {
.slice_start,
.import,
.switch_range,
.compilelog,
.typeof_peer,
=> false,

Expand Down Expand Up @@ -707,6 +711,19 @@ pub const Inst = struct {
kw_args: struct {},
};

pub const CompileLog = struct {
pub const base_tag = Tag.compilelog;
base: Inst,

positionals: struct {
to_log: []*Inst,
},
kw_args: struct {
/// If we have seen it already so don't make another error
seen: bool = false,
},
};

pub const Const = struct {
pub const base_tag = Tag.@"const";
base: Inst,
Expand Down Expand Up @@ -1925,15 +1942,15 @@ const EmitZIR = struct {
.sema_failure,
.sema_failure_retryable,
.dependency_failure,
=> if (self.old_module.failed_decls.get(ir_decl)) |err_msg| {
=> if (self.old_module.failed_decls.get(ir_decl)) |err_msg_list| {
const fail_inst = try self.arena.allocator.create(Inst.CompileError);
fail_inst.* = .{
.base = .{
.src = ir_decl.src(),
.tag = Inst.CompileError.base_tag,
},
.positionals = .{
.msg = try self.arena.allocator.dupe(u8, err_msg.msg),
.msg = try self.arena.allocator.dupe(u8, err_msg_list.items[0].msg),
},
.kw_args = .{},
};
Expand Down Expand Up @@ -2055,7 +2072,7 @@ const EmitZIR = struct {
try self.emitBody(body, &inst_table, &instructions);
},
.sema_failure => {
const err_msg = self.old_module.failed_decls.get(module_fn.owner_decl).?;
const err_msg = self.old_module.failed_decls.get(module_fn.owner_decl).?.items[0];
const fail_inst = try self.arena.allocator.create(Inst.CompileError);
fail_inst.* = .{
.base = .{
Expand Down
23 changes: 23 additions & 0 deletions src/zir_sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
.coerce_result_ptr => return analyzeInstCoerceResultPtr(mod, scope, old_inst.castTag(.coerce_result_ptr).?),
.coerce_to_ptr_elem => return analyzeInstCoerceToPtrElem(mod, scope, old_inst.castTag(.coerce_to_ptr_elem).?),
.compileerror => return analyzeInstCompileError(mod, scope, old_inst.castTag(.compileerror).?),
.compilelog => return analyzeInstCompileLog(mod, scope, old_inst.castTag(.compilelog).?),
.@"const" => return analyzeInstConst(mod, scope, old_inst.castTag(.@"const").?),
.dbg_stmt => return analyzeInstDbgStmt(mod, scope, old_inst.castTag(.dbg_stmt).?),
.declref => return analyzeInstDeclRef(mod, scope, old_inst.castTag(.declref).?),
Expand Down Expand Up @@ -489,6 +490,28 @@ fn analyzeInstCompileError(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileE
return mod.fail(scope, inst.base.src, "{}", .{inst.positionals.msg});
}

fn analyzeInstCompileLog(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileLog) InnerError!*Inst {
std.debug.print("| ", .{});
for (inst.positionals.to_log) |item, i| {
const to_log = try resolveInst(mod, scope, item);
if (to_log.value()) |val| {
std.debug.print("{}", .{val});
} else {
std.debug.print("(runtime value)", .{});
}
if (i != inst.positionals.to_log.len - 1) std.debug.print(", ", .{});
}
std.debug.print("\n", .{});
if (!inst.kw_args.seen) {
inst.kw_args.seen = true; // so that we do not give multiple compile errors if it gets evaled twice
switch (mod.fail(scope, inst.base.src, "found compile log statement", .{})) {
error.AnalysisFail => {}, // analysis continues
else => |e| return e,
}
}
return mod.constVoid(scope, inst.base.src);
}

fn analyzeInstArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst {
const b = try mod.requireRuntimeBlock(scope, inst.base.src);
const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
Expand Down
Loading