authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-09-16 23:49:00+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-09-16 23:49:00+03:00
logb2aedb07096fa4ed8766d3aa87e70704cee68265
tree415ec2d04881991f541477ec0d0c1d96a21d056d
parent8edd7219c0d5cc5799ae26ee8299b4d4114f7aed
parent31daea74d23be813737892a166cc16ade1272a1a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12796 from Vexu/referenced-by-v2

stage2: add referenced by trace to compile errors attempt #2 (+ some fixes)

21 files changed, 492 insertions(+), 52 deletions(-)

lib/build_runner.zig+12
...@@ -185,6 +185,16 @@ pub fn main() !void {...@@ -185,6 +185,16 @@ pub fn main() !void {
185 builder.use_stage1 = true;185 builder.use_stage1 = true;
186 } else if (mem.eql(u8, arg, "-fno-stage1")) {186 } else if (mem.eql(u8, arg, "-fno-stage1")) {
187 builder.use_stage1 = false;187 builder.use_stage1 = false;
188 } else if (mem.eql(u8, arg, "-freference-trace")) {
189 builder.reference_trace = 256;
190 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
191 const num = arg["-freference-trace=".len..];
192 builder.reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
193 std.debug.print("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
194 process.exit(1);
195 };
196 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
197 builder.reference_trace = null;
188 } else if (mem.eql(u8, arg, "--")) {198 } else if (mem.eql(u8, arg, "--")) {
189 builder.args = argsRest(args, arg_idx);199 builder.args = argsRest(args, arg_idx);
190 break;200 break;
...@@ -308,6 +318,8 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void...@@ -308,6 +318,8 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void
308 \\Advanced Options:318 \\Advanced Options:
309 \\ -fstage1 Force using bootstrap compiler as the codegen backend319 \\ -fstage1 Force using bootstrap compiler as the codegen backend
310 \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend320 \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend
321 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
322 \\ -fno-reference-trace Disable reference trace
311 \\ --build-file [file] Override path to build.zig323 \\ --build-file [file] Override path to build.zig
312 \\ --cache-dir [path] Override path to local Zig cache directory324 \\ --cache-dir [path] Override path to local Zig cache directory
313 \\ --global-cache-dir [path] Override path to global Zig cache directory325 \\ --global-cache-dir [path] Override path to global Zig cache directory
lib/std/build.zig+5
...@@ -45,6 +45,7 @@ pub const Builder = struct {...@@ -45,6 +45,7 @@ pub const Builder = struct {
45 /// The purpose of executing the command is for a human to read compile errors from the terminal45 /// The purpose of executing the command is for a human to read compile errors from the terminal
46 prominent_compile_errors: bool,46 prominent_compile_errors: bool,
47 color: enum { auto, on, off } = .auto,47 color: enum { auto, on, off } = .auto,
48 reference_trace: ?u32 = null,
48 use_stage1: ?bool = null,49 use_stage1: ?bool = null,
49 invalid_user_input: bool,50 invalid_user_input: bool,
50 zig_exe: []const u8,51 zig_exe: []const u8,
...@@ -2453,6 +2454,10 @@ pub const LibExeObjStep = struct {...@@ -2453,6 +2454,10 @@ pub const LibExeObjStep = struct {
2453 try zig_args.append(@tagName(builder.color));2454 try zig_args.append(@tagName(builder.color));
2454 }2455 }
24552456
2457 if (builder.reference_trace) |some| {
2458 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-freference-trace={d}", .{some}));
2459 }
2460
2456 if (self.use_stage1) |stage1| {2461 if (self.use_stage1) |stage1| {
2457 if (stage1) {2462 if (stage1) {
2458 try zig_args.append("-fstage1");2463 try zig_args.append("-fstage1");
src/AstGen.zig+1-1
...@@ -1981,7 +1981,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)...@@ -1981,7 +1981,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
1981 else1981 else
1982 .@"break";1982 .@"break";
1983 if (break_tag == .break_inline) {1983 if (break_tag == .break_inline) {
1984 _ = try parent_gz.addNode(.check_comptime_control_flow, node);1984 _ = try parent_gz.addUnNode(.check_comptime_control_flow, Zir.indexToRef(continue_block), node);
1985 }1985 }
1986 _ = try parent_gz.addBreak(break_tag, continue_block, .void_value);1986 _ = try parent_gz.addBreak(break_tag, continue_block, .void_value);
1987 return Zir.Inst.Ref.unreachable_value;1987 return Zir.Inst.Ref.unreachable_value;
src/Compilation.zig+62
...@@ -154,6 +154,10 @@ owned_link_dir: ?std.fs.Dir,...@@ -154,6 +154,10 @@ owned_link_dir: ?std.fs.Dir,
154/// Don't use this for anything other than stage1 compatibility.154/// Don't use this for anything other than stage1 compatibility.
155color: Color = .auto,155color: Color = .auto,
156156
157/// How many lines of reference trace should be included per compile error.
158/// Null means only show snippet on first error.
159reference_trace: ?u32 = null,
160
157libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default,161libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default,
158162
159/// This mutex guards all `Compilation` mutable state.163/// This mutex guards all `Compilation` mutable state.
...@@ -348,6 +352,7 @@ pub const AllErrors = struct {...@@ -348,6 +352,7 @@ pub const AllErrors = struct {
348 /// Does not include the trailing newline.352 /// Does not include the trailing newline.
349 source_line: ?[]const u8,353 source_line: ?[]const u8,
350 notes: []Message = &.{},354 notes: []Message = &.{},
355 reference_trace: []Message = &.{},
351356
352 /// Splits the error message up into lines to properly indent them357 /// Splits the error message up into lines to properly indent them
353 /// to allow for long, good-looking error messages.358 /// to allow for long, good-looking error messages.
...@@ -447,6 +452,34 @@ pub const AllErrors = struct {...@@ -447,6 +452,34 @@ pub const AllErrors = struct {
447 for (src.notes) |note| {452 for (src.notes) |note| {
448 try note.renderToWriter(ttyconf, stderr, "note", .Cyan, indent);453 try note.renderToWriter(ttyconf, stderr, "note", .Cyan, indent);
449 }454 }
455 if (src.reference_trace.len != 0) {
456 ttyconf.setColor(stderr, .Reset);
457 ttyconf.setColor(stderr, .Dim);
458 try stderr.print("referenced by:\n", .{});
459 for (src.reference_trace) |reference| {
460 switch (reference) {
461 .src => |ref_src| try stderr.print(" {s}: {s}:{d}:{d}\n", .{
462 ref_src.msg,
463 ref_src.src_path,
464 ref_src.line + 1,
465 ref_src.column + 1,
466 }),
467 .plain => |plain| if (plain.count != 0) {
468 try stderr.print(
469 " {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n",
470 .{ plain.count, plain.count + src.reference_trace.len - 1 },
471 );
472 } else {
473 try stderr.print(
474 " remaining reference traces hidden; use '-freference-trace' to see all reference traces\n",
475 .{},
476 );
477 },
478 }
479 }
480 try stderr.writeByte('\n');
481 ttyconf.setColor(stderr, .Reset);
482 }
450 },483 },
451 .plain => |plain| {484 .plain => |plain| {
452 ttyconf.setColor(stderr, color);485 ttyconf.setColor(stderr, color);
...@@ -572,6 +605,32 @@ pub const AllErrors = struct {...@@ -572,6 +605,32 @@ pub const AllErrors = struct {
572 });605 });
573 return;606 return;
574 }607 }
608
609 const reference_trace = try allocator.alloc(Message, module_err_msg.reference_trace.len);
610 for (reference_trace) |*reference, i| {
611 const module_reference = module_err_msg.reference_trace[i];
612 if (module_reference.hidden != 0) {
613 reference.* = .{ .plain = .{ .msg = undefined, .count = module_reference.hidden } };
614 break;
615 } else if (module_reference.decl == null) {
616 reference.* = .{ .plain = .{ .msg = undefined, .count = 0 } };
617 break;
618 }
619 const source = try module_reference.src_loc.file_scope.getSource(module.gpa);
620 const span = try module_reference.src_loc.span(module.gpa);
621 const loc = std.zig.findLineColumn(source.bytes, span.main);
622 const file_path = try module_reference.src_loc.file_scope.fullPath(allocator);
623 reference.* = .{
624 .src = .{
625 .src_path = file_path,
626 .msg = try allocator.dupe(u8, std.mem.sliceTo(module_reference.decl.?, 0)),
627 .span = span,
628 .line = @intCast(u32, loc.line),
629 .column = @intCast(u32, loc.column),
630 .source_line = null,
631 },
632 };
633 }
575 const file_path = try module_err_msg.src_loc.file_scope.fullPath(allocator);634 const file_path = try module_err_msg.src_loc.file_scope.fullPath(allocator);
576 try errors.append(.{635 try errors.append(.{
577 .src = .{636 .src = .{
...@@ -581,6 +640,7 @@ pub const AllErrors = struct {...@@ -581,6 +640,7 @@ pub const AllErrors = struct {
581 .line = @intCast(u32, err_loc.line),640 .line = @intCast(u32, err_loc.line),
582 .column = @intCast(u32, err_loc.column),641 .column = @intCast(u32, err_loc.column),
583 .notes = notes_buf[0..note_i],642 .notes = notes_buf[0..note_i],
643 .reference_trace = reference_trace,
584 .source_line = try allocator.dupe(u8, err_loc.source_line),644 .source_line = try allocator.dupe(u8, err_loc.source_line),
585 },645 },
586 });646 });
...@@ -929,6 +989,7 @@ pub const InitOptions = struct {...@@ -929,6 +989,7 @@ pub const InitOptions = struct {
929 clang_preprocessor_mode: ClangPreprocessorMode = .no,989 clang_preprocessor_mode: ClangPreprocessorMode = .no,
930 /// This is for stage1 and should be deleted upon completion of self-hosting.990 /// This is for stage1 and should be deleted upon completion of self-hosting.
931 color: Color = .auto,991 color: Color = .auto,
992 reference_trace: ?u32 = null,
932 test_filter: ?[]const u8 = null,993 test_filter: ?[]const u8 = null,
933 test_name_prefix: ?[]const u8 = null,994 test_name_prefix: ?[]const u8 = null,
934 subsystem: ?std.Target.SubSystem = null,995 subsystem: ?std.Target.SubSystem = null,
...@@ -1838,6 +1899,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1838,6 +1899,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1838 .disable_c_depfile = options.disable_c_depfile,1899 .disable_c_depfile = options.disable_c_depfile,
1839 .owned_link_dir = owned_link_dir,1900 .owned_link_dir = owned_link_dir,
1840 .color = options.color,1901 .color = options.color,
1902 .reference_trace = options.reference_trace,
1841 .time_report = options.time_report,1903 .time_report = options.time_report,
1842 .stack_report = options.stack_report,1904 .stack_report = options.stack_report,
1843 .unwind_tables = unwind_tables,1905 .unwind_tables = unwind_tables,
src/Module.zig+20
...@@ -166,6 +166,11 @@ decls_free_list: std.ArrayListUnmanaged(Decl.Index) = .{},...@@ -166,6 +166,11 @@ decls_free_list: std.ArrayListUnmanaged(Decl.Index) = .{},
166166
167global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{},167global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{},
168168
169reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct {
170 referencer: Decl.Index,
171 src: LazySrcLoc,
172}) = .{},
173
169pub const StringLiteralContext = struct {174pub const StringLiteralContext = struct {
170 bytes: *std.ArrayListUnmanaged(u8),175 bytes: *std.ArrayListUnmanaged(u8),
171176
...@@ -2084,6 +2089,13 @@ pub const ErrorMsg = struct {...@@ -2084,6 +2089,13 @@ pub const ErrorMsg = struct {
2084 src_loc: SrcLoc,2089 src_loc: SrcLoc,
2085 msg: []const u8,2090 msg: []const u8,
2086 notes: []ErrorMsg = &.{},2091 notes: []ErrorMsg = &.{},
2092 reference_trace: []Trace = &.{},
2093
2094 pub const Trace = struct {
2095 decl: ?[*:0]const u8,
2096 src_loc: SrcLoc,
2097 hidden: u32 = 0,
2098 };
20872099
2088 pub fn create(2100 pub fn create(
2089 gpa: Allocator,2101 gpa: Allocator,
...@@ -2122,8 +2134,15 @@ pub const ErrorMsg = struct {...@@ -2122,8 +2134,15 @@ pub const ErrorMsg = struct {
2122 }2134 }
2123 gpa.free(err_msg.notes);2135 gpa.free(err_msg.notes);
2124 gpa.free(err_msg.msg);2136 gpa.free(err_msg.msg);
2137 gpa.free(err_msg.reference_trace);
2125 err_msg.* = undefined;2138 err_msg.* = undefined;
2126 }2139 }
2140
2141 pub fn clearTrace(err_msg: *ErrorMsg, gpa: Allocator) void {
2142 if (err_msg.reference_trace.len == 0) return;
2143 gpa.free(err_msg.reference_trace);
2144 err_msg.reference_trace = &.{};
2145 }
2127};2146};
21282147
2129/// Canonical reference to a position within a source file.2148/// Canonical reference to a position within a source file.
...@@ -3411,6 +3430,7 @@ pub fn deinit(mod: *Module) void {...@@ -3411,6 +3430,7 @@ pub fn deinit(mod: *Module) void {
3411 mod.decls_free_list.deinit(gpa);3430 mod.decls_free_list.deinit(gpa);
3412 mod.allocated_decls.deinit(gpa);3431 mod.allocated_decls.deinit(gpa);
3413 mod.global_assembly.deinit(gpa);3432 mod.global_assembly.deinit(gpa);
3433 mod.reference_table.deinit(gpa);
34143434
3415 mod.string_literal_table.deinit(gpa);3435 mod.string_literal_table.deinit(gpa);
3416 mod.string_literal_bytes.deinit(gpa);3436 mod.string_literal_bytes.deinit(gpa);
src/Sema.zig+119-30
...@@ -111,6 +111,7 @@ const crash_report = @import("crash_report.zig");...@@ -111,6 +111,7 @@ const crash_report = @import("crash_report.zig");
111const build_options = @import("build_options");111const build_options = @import("build_options");
112112
113pub const default_branch_quota = 1000;113pub const default_branch_quota = 1000;
114pub const default_reference_trace_len = 2;
114115
115pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);116pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);
116117
...@@ -144,6 +145,7 @@ pub const Block = struct {...@@ -144,6 +145,7 @@ pub const Block = struct {
144 /// Non zero if a non-inline loop or a runtime conditional have been encountered.145 /// Non zero if a non-inline loop or a runtime conditional have been encountered.
145 /// Stores to to comptime variables are only allowed when var.runtime_index <= runtime_index.146 /// Stores to to comptime variables are only allowed when var.runtime_index <= runtime_index.
146 runtime_index: Value.RuntimeIndex = .zero,147 runtime_index: Value.RuntimeIndex = .zero,
148 inline_block: Zir.Inst.Index = 0,
147149
148 is_comptime: bool,150 is_comptime: bool,
149 is_typeof: bool = false,151 is_typeof: bool = false,
...@@ -1157,9 +1159,20 @@ fn analyzeBodyInner(...@@ -1157,9 +1159,20 @@ fn analyzeBodyInner(
1157 },1159 },
1158 .check_comptime_control_flow => {1160 .check_comptime_control_flow => {
1159 if (!block.is_comptime) {1161 if (!block.is_comptime) {
1160 if (block.runtime_cond orelse block.runtime_loop) |runtime_src| {1162 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1161 const inst_data = sema.code.instructions.items(.data)[inst].node;1163 const src = inst_data.src();
1162 const src = LazySrcLoc.nodeOffset(inst_data);1164 const inline_block = Zir.refToIndex(inst_data.operand).?;
1165
1166 var check_block = block;
1167 const target_runtime_index = while (true) {
1168 if (check_block.inline_block == inline_block) {
1169 break check_block.runtime_index;
1170 }
1171 check_block = check_block.parent.?;
1172 } else unreachable;
1173
1174 if (@enumToInt(target_runtime_index) < @enumToInt(block.runtime_index)) {
1175 const runtime_src = block.runtime_cond orelse block.runtime_loop.?;
1163 const msg = msg: {1176 const msg = msg: {
1164 const msg = try sema.errMsg(block, src, "comptime control flow inside runtime block", .{});1177 const msg = try sema.errMsg(block, src, "comptime control flow inside runtime block", .{});
1165 errdefer msg.destroy(sema.gpa);1178 errdefer msg.destroy(sema.gpa);
...@@ -1272,10 +1285,15 @@ fn analyzeBodyInner(...@@ -1272,10 +1285,15 @@ fn analyzeBodyInner(
1272 // current list of parameters and restore it later.1285 // current list of parameters and restore it later.
1273 // Note: this probably needs to be resolved in a more general manner.1286 // Note: this probably needs to be resolved in a more general manner.
1274 const prev_params = block.params;1287 const prev_params = block.params;
1288 const prev_inline_block = block.inline_block;
1289 if (tags[inline_body[inline_body.len - 1]] == .repeat_inline) {
1290 block.inline_block = inline_body[0];
1291 }
1275 block.params = .{};1292 block.params = .{};
1276 defer {1293 defer {
1277 block.params.deinit(gpa);1294 block.params.deinit(gpa);
1278 block.params = prev_params;1295 block.params = prev_params;
1296 block.inline_block = prev_inline_block;
1279 }1297 }
1280 const opt_break_data = try sema.analyzeBodyBreak(block, inline_body);1298 const opt_break_data = try sema.analyzeBodyBreak(block, inline_body);
1281 // A runtime conditional branch that needs a post-hoc block to be1299 // A runtime conditional branch that needs a post-hoc block to be
...@@ -1353,6 +1371,8 @@ fn analyzeBodyInner(...@@ -1353,6 +1371,8 @@ fn analyzeBodyInner(
1353 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];1371 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
1354 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime known");1372 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime known");
1355 const inline_body = if (cond.val.toBool()) then_body else else_body;1373 const inline_body = if (cond.val.toBool()) then_body else else_body;
1374 const old_runtime_index = block.runtime_index;
1375 defer block.runtime_index = old_runtime_index;
1356 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse1376 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1357 break always_noreturn;1377 break always_noreturn;
1358 if (inst == break_data.block_inst) {1378 if (inst == break_data.block_inst) {
...@@ -1939,13 +1959,53 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {...@@ -1939,13 +1959,53 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
1939 }1959 }
19401960
1941 const mod = sema.mod;1961 const mod = sema.mod;
1942 {1962 ref: {
1943 errdefer err_msg.destroy(mod.gpa);1963 errdefer err_msg.destroy(mod.gpa);
1944 if (err_msg.src_loc.lazy == .unneeded) {1964 if (err_msg.src_loc.lazy == .unneeded) {
1945 return error.NeededSourceLocation;1965 return error.NeededSourceLocation;
1946 }1966 }
1947 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);1967 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
1948 try mod.failed_files.ensureUnusedCapacity(mod.gpa, 1);1968 try mod.failed_files.ensureUnusedCapacity(mod.gpa, 1);
1969
1970 const max_references = blk: {
1971 if (sema.mod.comp.reference_trace) |num| break :blk num;
1972 // Do not add multiple traces without explicit request.
1973 if (sema.mod.failed_decls.count() != 0) break :ref;
1974 break :blk default_reference_trace_len;
1975 };
1976
1977 var referenced_by = if (sema.func) |some| some.owner_decl else sema.owner_decl_index;
1978 var reference_stack = std.ArrayList(Module.ErrorMsg.Trace).init(sema.gpa);
1979 defer reference_stack.deinit();
1980
1981 // Avoid infinite loops.
1982 var seen = std.AutoHashMap(Module.Decl.Index, void).init(sema.gpa);
1983 defer seen.deinit();
1984
1985 var cur_reference_trace: u32 = 0;
1986 while (sema.mod.reference_table.get(referenced_by)) |ref| : (cur_reference_trace += 1) {
1987 const gop = try seen.getOrPut(ref.referencer);
1988 if (gop.found_existing) break;
1989 if (cur_reference_trace < max_references) {
1990 const decl = sema.mod.declPtr(ref.referencer);
1991 try reference_stack.append(.{ .decl = decl.name, .src_loc = ref.src.toSrcLoc(decl) });
1992 }
1993 referenced_by = ref.referencer;
1994 }
1995 if (sema.mod.comp.reference_trace == null and cur_reference_trace > 0) {
1996 try reference_stack.append(.{
1997 .decl = null,
1998 .src_loc = undefined,
1999 .hidden = 0,
2000 });
2001 } else if (cur_reference_trace > max_references) {
2002 try reference_stack.append(.{
2003 .decl = undefined,
2004 .src_loc = undefined,
2005 .hidden = cur_reference_trace - max_references,
2006 });
2007 }
2008 err_msg.reference_trace = reference_stack.toOwnedSlice();
1949 }2009 }
1950 if (sema.owner_func) |func| {2010 if (sema.owner_func) |func| {
1951 func.state = .sema_failure;2011 func.state = .sema_failure;
...@@ -4749,6 +4809,9 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -4749,6 +4809,9 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
4749 .inlining = parent_block.inlining,4809 .inlining = parent_block.inlining,
4750 .is_comptime = parent_block.is_comptime,4810 .is_comptime = parent_block.is_comptime,
4751 .c_import_buf = &c_import_buf,4811 .c_import_buf = &c_import_buf,
4812 .runtime_cond = parent_block.runtime_cond,
4813 .runtime_loop = parent_block.runtime_loop,
4814 .runtime_index = parent_block.runtime_index,
4752 };4815 };
4753 defer child_block.instructions.deinit(sema.gpa);4816 defer child_block.instructions.deinit(sema.gpa);
47544817
...@@ -4847,6 +4910,9 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -4847,6 +4910,9 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
4847 .is_comptime = parent_block.is_comptime,4910 .is_comptime = parent_block.is_comptime,
4848 .want_safety = parent_block.want_safety,4911 .want_safety = parent_block.want_safety,
4849 .float_mode = parent_block.float_mode,4912 .float_mode = parent_block.float_mode,
4913 .runtime_cond = parent_block.runtime_cond,
4914 .runtime_loop = parent_block.runtime_loop,
4915 .runtime_index = parent_block.runtime_index,
4850 };4916 };
48514917
4852 defer child_block.instructions.deinit(gpa);4918 defer child_block.instructions.deinit(gpa);
...@@ -5341,14 +5407,8 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -5341,14 +5407,8 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
5341 const src = inst_data.src();5407 const src = inst_data.src();
5342 const decl_name = inst_data.get(sema.code);5408 const decl_name = inst_data.get(sema.code);
5343 const decl_index = try sema.lookupIdentifier(block, src, decl_name);5409 const decl_index = try sema.lookupIdentifier(block, src, decl_name);
5344 return sema.analyzeDeclRef(decl_index) catch |err| switch (err) {5410 try sema.addReferencedBy(block, src, decl_index);
5345 error.AnalysisFail => {5411 return sema.analyzeDeclRef(decl_index);
5346 const msg = sema.err orelse return err;
5347 try sema.errNote(block, src, msg, "referenced here", .{});
5348 return err;
5349 },
5350 else => return err,
5351 };
5352}5412}
53535413
5354fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {5414fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -6082,6 +6142,7 @@ fn analyzeCall(...@@ -6082,6 +6142,7 @@ fn analyzeCall(
6082 error.AnalysisFail => {6142 error.AnalysisFail => {
6083 const err_msg = sema.err orelse return err;6143 const err_msg = sema.err orelse return err;
6084 try sema.errNote(block, call_src, err_msg, "called from here", .{});6144 try sema.errNote(block, call_src, err_msg, "called from here", .{});
6145 err_msg.clearTrace(sema.gpa);
6085 return err;6146 return err;
6086 },6147 },
6087 else => |e| return e,6148 else => |e| return e,
...@@ -9743,6 +9804,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9743,6 +9804,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9743 .inlining = block.inlining,9804 .inlining = block.inlining,
9744 .is_comptime = block.is_comptime,9805 .is_comptime = block.is_comptime,
9745 .switch_else_err_ty = else_error_ty,9806 .switch_else_err_ty = else_error_ty,
9807 .runtime_cond = block.runtime_cond,
9808 .runtime_loop = block.runtime_loop,
9809 .runtime_index = block.runtime_index,
9746 };9810 };
9747 const merges = &child_block.label.?.merges;9811 const merges = &child_block.label.?.merges;
9748 defer child_block.instructions.deinit(gpa);9812 defer child_block.instructions.deinit(gpa);
...@@ -14873,6 +14937,9 @@ fn zirTypeofPeer(...@@ -14873,6 +14937,9 @@ fn zirTypeofPeer(
14873 .inlining = block.inlining,14937 .inlining = block.inlining,
14874 .is_comptime = false,14938 .is_comptime = false,
14875 .is_typeof = true,14939 .is_typeof = true,
14940 .runtime_cond = block.runtime_cond,
14941 .runtime_loop = block.runtime_loop,
14942 .runtime_index = block.runtime_index,
14876 };14943 };
14877 defer child_block.instructions.deinit(sema.gpa);14944 defer child_block.instructions.deinit(sema.gpa);
14878 // Ignore the result, we only care about the instructions in `args`.14945 // Ignore the result, we only care about the instructions in `args`.
...@@ -17407,7 +17474,7 @@ fn reifyStruct(...@@ -17407,7 +17474,7 @@ fn reifyStruct(
17407 if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) {17474 if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) {
17408 return sema.fail(block, src, "alignment must fit in 'u32'", .{});17475 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
17409 }17476 }
17410 const abi_align = @intCast(u29, alignment_val.toUnsignedInt(target));17477 const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?);
1741117478
17412 const field_name = try name_val.toAllocatedBytes(17479 const field_name = try name_val.toAllocatedBytes(
17413 Type.initTag(.const_slice_u8),17480 Type.initTag(.const_slice_u8),
...@@ -21653,12 +21720,19 @@ fn finishFieldCallBind(...@@ -21653,12 +21720,19 @@ fn finishFieldCallBind(
21653 .@"addrspace" = ptr_ty.ptrAddressSpace(),21720 .@"addrspace" = ptr_ty.ptrAddressSpace(),
21654 });21721 });
2165521722
21723 const container_ty = ptr_ty.childType();
21724 if (container_ty.zigTypeTag() == .Struct) {
21725 if (container_ty.structFieldValueComptime(field_index)) |default_val| {
21726 return sema.addConstant(field_ty, default_val);
21727 }
21728 }
21729
21656 if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| {21730 if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| {
21657 const pointer = try sema.addConstant(21731 const pointer = try sema.addConstant(
21658 ptr_field_ty,21732 ptr_field_ty,
21659 try Value.Tag.field_ptr.create(arena, .{21733 try Value.Tag.field_ptr.create(arena, .{
21660 .container_ptr = struct_ptr_val,21734 .container_ptr = struct_ptr_val,
21661 .container_ty = ptr_ty.childType(),21735 .container_ty = container_ty,
21662 .field_index = field_index,21736 .field_index = field_index,
21663 }),21737 }),
21664 );21738 );
...@@ -21704,14 +21778,8 @@ fn namespaceLookupRef(...@@ -21704,14 +21778,8 @@ fn namespaceLookupRef(
21704 decl_name: []const u8,21778 decl_name: []const u8,
21705) CompileError!?Air.Inst.Ref {21779) CompileError!?Air.Inst.Ref {
21706 const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;21780 const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
21707 return sema.analyzeDeclRef(decl) catch |err| switch (err) {21781 try sema.addReferencedBy(block, src, decl);
21708 error.AnalysisFail => {21782 return try sema.analyzeDeclRef(decl);
21709 const msg = sema.err orelse return err;
21710 try sema.errNote(block, src, msg, "referenced here", .{});
21711 return err;
21712 },
21713 else => return err,
21714 };
21715}21783}
2171621784
21717fn namespaceLookupVal(21785fn namespaceLookupVal(
...@@ -24771,6 +24839,20 @@ fn beginComptimePtrMutation(...@@ -24771,6 +24839,20 @@ fn beginComptimePtrMutation(
24771 else => unreachable,24839 else => unreachable,
24772 },24840 },
2477324841
24842 .empty_struct_value => {
24843 const duped = try sema.arena.create(Value);
24844 duped.* = Value.initTag(.the_only_possible_value);
24845 return beginComptimePtrMutationInner(
24846 sema,
24847 block,
24848 src,
24849 parent.ty.structFieldType(field_index),
24850 duped,
24851 ptr_elem_ty,
24852 parent.decl_ref_mut,
24853 );
24854 },
24855
24774 else => unreachable,24856 else => unreachable,
24775 },24857 },
24776 .reinterpret => |reinterpret| {24858 .reinterpret => |reinterpret| {
...@@ -25950,14 +26032,8 @@ fn analyzeDeclVal(...@@ -25950,14 +26032,8 @@ fn analyzeDeclVal(
25950 if (sema.decl_val_table.get(decl_index)) |result| {26032 if (sema.decl_val_table.get(decl_index)) |result| {
25951 return result;26033 return result;
25952 }26034 }
25953 const decl_ref = sema.analyzeDeclRef(decl_index) catch |err| switch (err) {26035 try sema.addReferencedBy(block, src, decl_index);
25954 error.AnalysisFail => {26036 const decl_ref = try sema.analyzeDeclRef(decl_index);
25955 const msg = sema.err orelse return err;
25956 try sema.errNote(block, src, msg, "referenced here", .{});
25957 return err;
25958 },
25959 else => return err,
25960 };
25961 const result = try sema.analyzeLoad(block, src, decl_ref, src);26037 const result = try sema.analyzeLoad(block, src, decl_ref, src);
25962 if (Air.refToIndex(result)) |index| {26038 if (Air.refToIndex(result)) |index| {
25963 if (sema.air_instructions.items(.tag)[index] == .constant and !block.is_typeof) {26039 if (sema.air_instructions.items(.tag)[index] == .constant and !block.is_typeof) {
...@@ -25967,6 +26043,19 @@ fn analyzeDeclVal(...@@ -25967,6 +26043,19 @@ fn analyzeDeclVal(
25967 return result;26043 return result;
25968}26044}
2596926045
26046fn addReferencedBy(
26047 sema: *Sema,
26048 block: *Block,
26049 src: LazySrcLoc,
26050 decl_index: Decl.Index,
26051) !void {
26052 if (sema.mod.comp.reference_trace == @as(u32, 0)) return;
26053 try sema.mod.reference_table.put(sema.gpa, decl_index, .{
26054 .referencer = block.src_decl,
26055 .src = src,
26056 });
26057}
26058
25970fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void {26059fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void {
25971 const decl = sema.mod.declPtr(decl_index);26060 const decl = sema.mod.declPtr(decl_index);
25972 if (decl.analysis == .in_progress) {26061 if (decl.analysis == .in_progress) {
src/Zir.zig+2-2
...@@ -287,7 +287,7 @@ pub const Inst = struct {...@@ -287,7 +287,7 @@ pub const Inst = struct {
287 /// Uses the `break` union field.287 /// Uses the `break` union field.
288 break_inline,288 break_inline,
289 /// Checks that comptime control flow does not happen inside a runtime block.289 /// Checks that comptime control flow does not happen inside a runtime block.
290 /// Uses the `node` union field.290 /// Uses the `un_node` union field.
291 check_comptime_control_flow,291 check_comptime_control_flow,
292 /// Function call.292 /// Function call.
293 /// Uses the `pl_node` union field with payload `Call`.293 /// Uses the `pl_node` union field with payload `Call`.
...@@ -1600,7 +1600,7 @@ pub const Inst = struct {...@@ -1600,7 +1600,7 @@ pub const Inst = struct {
1600 .bool_br_or = .bool_br,1600 .bool_br_or = .bool_br,
1601 .@"break" = .@"break",1601 .@"break" = .@"break",
1602 .break_inline = .@"break",1602 .break_inline = .@"break",
1603 .check_comptime_control_flow = .node,1603 .check_comptime_control_flow = .un_node,
1604 .call = .pl_node,1604 .call = .pl_node,
1605 .cmp_lt = .pl_node,1605 .cmp_lt = .pl_node,
1606 .cmp_lte = .pl_node,1606 .cmp_lte = .pl_node,
src/main.zig+35-14
...@@ -396,6 +396,8 @@ const usage_build_generic =...@@ -396,6 +396,8 @@ const usage_build_generic =
396 \\ -fno-Clang Prevent using Clang as the C/C++ compilation backend396 \\ -fno-Clang Prevent using Clang as the C/C++ compilation backend
397 \\ -fstage1 Force using bootstrap compiler as the codegen backend397 \\ -fstage1 Force using bootstrap compiler as the codegen backend
398 \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend398 \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend
399 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
400 \\ -fno-reference-trace Disable reference trace
399 \\ -fsingle-threaded Code assumes there is only one thread401 \\ -fsingle-threaded Code assumes there is only one thread
400 \\ -fno-single-threaded Code may not assume there is only one thread402 \\ -fno-single-threaded Code may not assume there is only one thread
401 \\ -fbuiltin Enable implicit builtin knowledge of functions403 \\ -fbuiltin Enable implicit builtin knowledge of functions
...@@ -742,6 +744,7 @@ fn buildOutputType(...@@ -742,6 +744,7 @@ fn buildOutputType(
742 var headerpad_size: ?u32 = null;744 var headerpad_size: ?u32 = null;
743 var headerpad_max_install_names: bool = false;745 var headerpad_max_install_names: bool = false;
744 var dead_strip_dylibs: bool = false;746 var dead_strip_dylibs: bool = false;
747 var reference_trace: ?u32 = null;
745748
746 // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.749 // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
747 // This array is populated by zig cc frontend and then has to be converted to zig-style750 // This array is populated by zig cc frontend and then has to be converted to zig-style
...@@ -928,14 +931,14 @@ fn buildOutputType(...@@ -928,14 +931,14 @@ fn buildOutputType(
928 fatal("expected parameter after {s}", .{arg});931 fatal("expected parameter after {s}", .{arg});
929 };932 };
930 stack_size_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {933 stack_size_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {
931 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });934 fatal("unable to parse stack size '{s}': {s}", .{ next_arg, @errorName(err) });
932 };935 };
933 } else if (mem.eql(u8, arg, "--image-base")) {936 } else if (mem.eql(u8, arg, "--image-base")) {
934 const next_arg = args_iter.next() orelse {937 const next_arg = args_iter.next() orelse {
935 fatal("expected parameter after {s}", .{arg});938 fatal("expected parameter after {s}", .{arg});
936 };939 };
937 image_base_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {940 image_base_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {
938 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });941 fatal("unable to parse image base override '{s}': {s}", .{ next_arg, @errorName(err) });
939 };942 };
940 } else if (mem.eql(u8, arg, "--name")) {943 } else if (mem.eql(u8, arg, "--name")) {
941 provided_name = args_iter.next() orelse {944 provided_name = args_iter.next() orelse {
...@@ -984,7 +987,7 @@ fn buildOutputType(...@@ -984,7 +987,7 @@ fn buildOutputType(
984 fatal("expected parameter after {s}", .{arg});987 fatal("expected parameter after {s}", .{arg});
985 };988 };
986 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {989 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
987 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });990 fatal("unable to parse pagezero size'{s}': {s}", .{ next_arg, @errorName(err) });
988 };991 };
989 } else if (mem.eql(u8, arg, "-search_paths_first")) {992 } else if (mem.eql(u8, arg, "-search_paths_first")) {
990 search_strategy = .paths_first;993 search_strategy = .paths_first;
...@@ -995,7 +998,7 @@ fn buildOutputType(...@@ -995,7 +998,7 @@ fn buildOutputType(
995 fatal("expected parameter after {s}", .{arg});998 fatal("expected parameter after {s}", .{arg});
996 };999 };
997 headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {1000 headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
998 fatal("unable to parser '{s}': {s}", .{ arg, @errorName(err) });1001 fatal("unable to parse headerpat size '{s}': {s}", .{ next_arg, @errorName(err) });
999 };1002 };
1000 } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) {1003 } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) {
1001 headerpad_max_install_names = true;1004 headerpad_max_install_names = true;
...@@ -1214,6 +1217,15 @@ fn buildOutputType(...@@ -1214,6 +1217,15 @@ fn buildOutputType(
1214 use_stage1 = true;1217 use_stage1 = true;
1215 } else if (mem.eql(u8, arg, "-fno-stage1")) {1218 } else if (mem.eql(u8, arg, "-fno-stage1")) {
1216 use_stage1 = false;1219 use_stage1 = false;
1220 } else if (mem.eql(u8, arg, "-freference-trace")) {
1221 reference_trace = 256;
1222 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
1223 const num = arg["-freference-trace=".len..];
1224 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
1225 fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
1226 };
1227 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
1228 reference_trace = null;
1217 } else if (mem.eql(u8, arg, "-rdynamic")) {1229 } else if (mem.eql(u8, arg, "-rdynamic")) {
1218 rdynamic = true;1230 rdynamic = true;
1219 } else if (mem.eql(u8, arg, "-fsoname")) {1231 } else if (mem.eql(u8, arg, "-fsoname")) {
...@@ -1785,11 +1797,11 @@ fn buildOutputType(...@@ -1785,11 +1797,11 @@ fn buildOutputType(
1785 fatal("expected linker arg after '{s}'", .{arg});1797 fatal("expected linker arg after '{s}'", .{arg});
1786 }1798 }
1787 linker_optimization = std.fmt.parseUnsigned(u8, linker_args.items[i], 10) catch |err| {1799 linker_optimization = std.fmt.parseUnsigned(u8, linker_args.items[i], 10) catch |err| {
1788 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1800 fatal("unable to parse optimization level '{s}': {s}", .{ linker_args.items[i], @errorName(err) });
1789 };1801 };
1790 } else if (mem.startsWith(u8, arg, "-O")) {1802 } else if (mem.startsWith(u8, arg, "-O")) {
1791 linker_optimization = std.fmt.parseUnsigned(u8, arg["-O".len..], 10) catch |err| {1803 linker_optimization = std.fmt.parseUnsigned(u8, arg["-O".len..], 10) catch |err| {
1792 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1804 fatal("unable to parse optimization level '{s}': {s}", .{ arg, @errorName(err) });
1793 };1805 };
1794 } else if (mem.eql(u8, arg, "-pagezero_size")) {1806 } else if (mem.eql(u8, arg, "-pagezero_size")) {
1795 i += 1;1807 i += 1;
...@@ -1798,7 +1810,7 @@ fn buildOutputType(...@@ -1798,7 +1810,7 @@ fn buildOutputType(
1798 }1810 }
1799 const next_arg = linker_args.items[i];1811 const next_arg = linker_args.items[i];
1800 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {1812 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
1801 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1813 fatal("unable to parse pagezero size '{s}': {s}", .{ next_arg, @errorName(err) });
1802 };1814 };
1803 } else if (mem.eql(u8, arg, "-headerpad")) {1815 } else if (mem.eql(u8, arg, "-headerpad")) {
1804 i += 1;1816 i += 1;
...@@ -1807,7 +1819,7 @@ fn buildOutputType(...@@ -1807,7 +1819,7 @@ fn buildOutputType(
1807 }1819 }
1808 const next_arg = linker_args.items[i];1820 const next_arg = linker_args.items[i];
1809 headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {1821 headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
1810 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1822 fatal("unable to parse headerpad size '{s}': {s}", .{ next_arg, @errorName(err) });
1811 };1823 };
1812 } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) {1824 } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) {
1813 headerpad_max_install_names = true;1825 headerpad_max_install_names = true;
...@@ -1899,7 +1911,7 @@ fn buildOutputType(...@@ -1899,7 +1911,7 @@ fn buildOutputType(
1899 fatal("expected linker arg after '{s}'", .{arg});1911 fatal("expected linker arg after '{s}'", .{arg});
1900 }1912 }
1901 version.major = std.fmt.parseUnsigned(u32, linker_args.items[i], 10) catch |err| {1913 version.major = std.fmt.parseUnsigned(u32, linker_args.items[i], 10) catch |err| {
1902 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1914 fatal("unable to parse major image version '{s}': {s}", .{ linker_args.items[i], @errorName(err) });
1903 };1915 };
1904 have_version = true;1916 have_version = true;
1905 } else if (mem.eql(u8, arg, "--minor-image-version")) {1917 } else if (mem.eql(u8, arg, "--minor-image-version")) {
...@@ -1908,7 +1920,7 @@ fn buildOutputType(...@@ -1908,7 +1920,7 @@ fn buildOutputType(
1908 fatal("expected linker arg after '{s}'", .{arg});1920 fatal("expected linker arg after '{s}'", .{arg});
1909 }1921 }
1910 version.minor = std.fmt.parseUnsigned(u32, linker_args.items[i], 10) catch |err| {1922 version.minor = std.fmt.parseUnsigned(u32, linker_args.items[i], 10) catch |err| {
1911 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1923 fatal("unable to parse minor image version '{s}': {s}", .{ linker_args.items[i], @errorName(err) });
1912 };1924 };
1913 have_version = true;1925 have_version = true;
1914 } else if (mem.eql(u8, arg, "-e") or mem.eql(u8, arg, "--entry")) {1926 } else if (mem.eql(u8, arg, "-e") or mem.eql(u8, arg, "--entry")) {
...@@ -1923,7 +1935,7 @@ fn buildOutputType(...@@ -1923,7 +1935,7 @@ fn buildOutputType(
1923 fatal("expected linker arg after '{s}'", .{arg});1935 fatal("expected linker arg after '{s}'", .{arg});
1924 }1936 }
1925 stack_size_override = std.fmt.parseUnsigned(u64, linker_args.items[i], 0) catch |err| {1937 stack_size_override = std.fmt.parseUnsigned(u64, linker_args.items[i], 0) catch |err| {
1926 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1938 fatal("unable to parse stack size override '{s}': {s}", .{ linker_args.items[i], @errorName(err) });
1927 };1939 };
1928 } else if (mem.eql(u8, arg, "--image-base")) {1940 } else if (mem.eql(u8, arg, "--image-base")) {
1929 i += 1;1941 i += 1;
...@@ -1931,7 +1943,7 @@ fn buildOutputType(...@@ -1931,7 +1943,7 @@ fn buildOutputType(
1931 fatal("expected linker arg after '{s}'", .{arg});1943 fatal("expected linker arg after '{s}'", .{arg});
1932 }1944 }
1933 image_base_override = std.fmt.parseUnsigned(u64, linker_args.items[i], 0) catch |err| {1945 image_base_override = std.fmt.parseUnsigned(u64, linker_args.items[i], 0) catch |err| {
1934 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1946 fatal("unable to parse image base override '{s}': {s}", .{ linker_args.items[i], @errorName(err) });
1935 };1947 };
1936 } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {1948 } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {
1937 i += 1;1949 i += 1;
...@@ -1984,7 +1996,7 @@ fn buildOutputType(...@@ -1984,7 +1996,7 @@ fn buildOutputType(
1984 linker_args.items[i],1996 linker_args.items[i],
1985 10,1997 10,
1986 ) catch |err| {1998 ) catch |err| {
1987 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1999 fatal("unable to parse major subsystem version '{s}': {s}", .{ linker_args.items[i], @errorName(err) });
1988 };2000 };
1989 } else if (mem.eql(u8, arg, "--minor-subsystem-version")) {2001 } else if (mem.eql(u8, arg, "--minor-subsystem-version")) {
1990 i += 1;2002 i += 1;
...@@ -1997,7 +2009,7 @@ fn buildOutputType(...@@ -1997,7 +2009,7 @@ fn buildOutputType(
1997 linker_args.items[i],2009 linker_args.items[i],
1998 10,2010 10,
1999 ) catch |err| {2011 ) catch |err| {
2000 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });2012 fatal("unable to parse minor subsystem version '{s}': {s}", .{ linker_args.items[i], @errorName(err) });
2001 };2013 };
2002 } else if (mem.eql(u8, arg, "-framework")) {2014 } else if (mem.eql(u8, arg, "-framework")) {
2003 i += 1;2015 i += 1;
...@@ -2996,6 +3008,7 @@ fn buildOutputType(...@@ -2996,6 +3008,7 @@ fn buildOutputType(
2996 .headerpad_size = headerpad_size,3008 .headerpad_size = headerpad_size,
2997 .headerpad_max_install_names = headerpad_max_install_names,3009 .headerpad_max_install_names = headerpad_max_install_names,
2998 .dead_strip_dylibs = dead_strip_dylibs,3010 .dead_strip_dylibs = dead_strip_dylibs,
3011 .reference_trace = reference_trace,
2999 }) catch |err| switch (err) {3012 }) catch |err| switch (err) {
3000 error.LibCUnavailable => {3013 error.LibCUnavailable => {
3001 const target = target_info.target;3014 const target = target_info.target;
...@@ -3744,6 +3757,8 @@ pub const usage_build =...@@ -3744,6 +3757,8 @@ pub const usage_build =
3744 \\Options:3757 \\Options:
3745 \\ -fstage1 Force using bootstrap compiler as the codegen backend3758 \\ -fstage1 Force using bootstrap compiler as the codegen backend
3746 \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend3759 \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend
3760 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
3761 \\ -fno-reference-trace Disable reference trace
3747 \\ --build-file [file] Override path to build.zig3762 \\ --build-file [file] Override path to build.zig
3748 \\ --cache-dir [path] Override path to local Zig cache directory3763 \\ --cache-dir [path] Override path to local Zig cache directory
3749 \\ --global-cache-dir [path] Override path to global Zig cache directory3764 \\ --global-cache-dir [path] Override path to global Zig cache directory
...@@ -3816,6 +3831,12 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -3816,6 +3831,12 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
3816 } else if (mem.eql(u8, arg, "-fno-stage1")) {3831 } else if (mem.eql(u8, arg, "-fno-stage1")) {
3817 use_stage1 = false;3832 use_stage1 = false;
3818 try child_argv.append(arg);3833 try child_argv.append(arg);
3834 } else if (mem.eql(u8, arg, "-freference-trace")) {
3835 try child_argv.append(arg);
3836 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
3837 try child_argv.append(arg);
3838 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
3839 try child_argv.append(arg);
3819 }3840 }
3820 }3841 }
3821 try child_argv.append(arg);3842 try child_argv.append(arg);
src/print_zir.zig+1-1
...@@ -232,6 +232,7 @@ const Writer = struct {...@@ -232,6 +232,7 @@ const Writer = struct {
232 .make_ptr_const,232 .make_ptr_const,
233 .validate_deref,233 .validate_deref,
234 .overflow_arithmetic_ptr,234 .overflow_arithmetic_ptr,
235 .check_comptime_control_flow,
235 => try self.writeUnNode(stream, inst),236 => try self.writeUnNode(stream, inst),
236237
237 .ref,238 .ref,
...@@ -406,7 +407,6 @@ const Writer = struct {...@@ -406,7 +407,6 @@ const Writer = struct {
406 .alloc_inferred_comptime_mut,407 .alloc_inferred_comptime_mut,
407 .ret_ptr,408 .ret_ptr,
408 .ret_type,409 .ret_type,
409 .check_comptime_control_flow,
410 => try self.writeNode(stream, inst),410 => try self.writeNode(stream, inst),
411411
412 .error_value,412 .error_value,
src/test.zig+1
...@@ -1551,6 +1551,7 @@ pub const TestContext = struct {...@@ -1551,6 +1551,7 @@ pub const TestContext = struct {
1551 .self_exe_path = zig_exe_path,1551 .self_exe_path = zig_exe_path,
1552 // TODO instead of turning off color, pass in a std.Progress.Node1552 // TODO instead of turning off color, pass in a std.Progress.Node
1553 .color = .off,1553 .color = .off,
1554 .reference_trace = 0,
1554 // TODO: force self-hosted linkers with stage2 backend to avoid LLD creeping in1555 // TODO: force self-hosted linkers with stage2 backend to avoid LLD creeping in
1555 // until the auto-select mechanism deems them worthy1556 // until the auto-select mechanism deems them worthy
1556 .use_lld = switch (case.backend) {1557 .use_lld = switch (case.backend) {
src/value.zig+9-3
...@@ -2391,12 +2391,15 @@ pub const Value = extern union {...@@ -2391,12 +2391,15 @@ pub const Value = extern union {
2391 union_obj.val.hash(active_field_ty, hasher, mod);2391 union_obj.val.hash(active_field_ty, hasher, mod);
2392 },2392 },
2393 .Fn => {2393 .Fn => {
2394 const func: *Module.Fn = val.castTag(.function).?.data;2394 // Note that his hashes the *Fn/*ExternFn rather than the *Decl. This is
2395 // Note that his hashes the *Fn rather than the *Decl. This is
2396 // to differentiate function bodies from function pointers.2395 // to differentiate function bodies from function pointers.
2397 // This is currently redundant since we already hash the zig type tag2396 // This is currently redundant since we already hash the zig type tag
2398 // at the top of this function.2397 // at the top of this function.
2399 std.hash.autoHash(hasher, func);2398 if (val.castTag(.function)) |func| {
2399 std.hash.autoHash(hasher, func.data);
2400 } else if (val.castTag(.extern_fn)) |func| {
2401 std.hash.autoHash(hasher, func.data);
2402 } else unreachable;
2400 },2403 },
2401 .Frame => {2404 .Frame => {
2402 @panic("TODO implement hashing frame values");2405 @panic("TODO implement hashing frame values");
...@@ -2775,6 +2778,9 @@ pub const Value = extern union {...@@ -2775,6 +2778,9 @@ pub const Value = extern union {
2775 const tuple = ty.tupleFields();2778 const tuple = ty.tupleFields();
2776 return tuple.values[index];2779 return tuple.values[index];
2777 }2780 }
2781 if (ty.structFieldValueComptime(index)) |some| {
2782 return some;
2783 }
2778 unreachable;2784 unreachable;
2779 },2785 },
2780 .undef => return Value.undef,2786 .undef => return Value.undef,
test/behavior.zig+4
...@@ -87,6 +87,10 @@ test {...@@ -87,6 +87,10 @@ test {
87 _ = @import("behavior/bugs/12486.zig");87 _ = @import("behavior/bugs/12486.zig");
88 _ = @import("behavior/bugs/12680.zig");88 _ = @import("behavior/bugs/12680.zig");
89 _ = @import("behavior/bugs/12776.zig");89 _ = @import("behavior/bugs/12776.zig");
90 _ = @import("behavior/bugs/12786.zig");
91 _ = @import("behavior/bugs/12794.zig");
92 _ = @import("behavior/bugs/12801-1.zig");
93 _ = @import("behavior/bugs/12801-2.zig");
90 _ = @import("behavior/byteswap.zig");94 _ = @import("behavior/byteswap.zig");
91 _ = @import("behavior/byval_arg_var.zig");95 _ = @import("behavior/byval_arg_var.zig");
92 _ = @import("behavior/call.zig");96 _ = @import("behavior/call.zig");
test/behavior/bugs/12786.zig created+28
...@@ -0,0 +1,28 @@
1const std = @import("std");
2
3fn NamespacedGlobals(comptime modules: anytype) type {
4 return @Type(.{
5 .Struct = .{
6 .layout = .Auto,
7 .is_tuple = false,
8 .fields = &.{
9 .{
10 .name = "globals",
11 .field_type = modules.mach.globals,
12 .default_value = null,
13 .is_comptime = false,
14 .alignment = @alignOf(modules.mach.globals),
15 },
16 },
17 .decls = &[_]std.builtin.Type.Declaration{},
18 },
19 });
20}
21
22test {
23 _ = NamespacedGlobals(.{
24 .mach = .{
25 .globals = struct {},
26 },
27 });
28}
test/behavior/bugs/12794.zig created+38
...@@ -0,0 +1,38 @@
1const std = @import("std");
2
3fn NamespacedComponents(comptime modules: anytype) type {
4 return @Type(.{
5 .Struct = .{
6 .layout = .Auto,
7 .is_tuple = false,
8 .fields = &.{.{
9 .name = "components",
10 .field_type = @TypeOf(modules.components),
11 .default_value = null,
12 .is_comptime = false,
13 .alignment = @alignOf(@TypeOf(modules.components)),
14 }},
15 .decls = &[_]std.builtin.Type.Declaration{},
16 },
17 });
18}
19
20fn namespacedComponents(comptime modules: anytype) NamespacedComponents(modules) {
21 var x: NamespacedComponents(modules) = undefined;
22 x.components = modules.components;
23 return x;
24}
25
26pub fn World(comptime modules: anytype) type {
27 const all_components = namespacedComponents(modules);
28 _ = all_components;
29 return struct {};
30}
31
32test {
33 _ = World(.{
34 .components = .{
35 .location = struct {},
36 },
37 });
38}
test/behavior/bugs/12801-1.zig created+13
...@@ -0,0 +1,13 @@
1const std = @import("std");
2const builtin = @import("builtin");
3
4comptime capacity: fn () u64 = capacity_,
5fn capacity_() u64 {
6 return 64;
7}
8
9test {
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11
12 try std.testing.expect((@This(){}).capacity() == 64);
13}
test/behavior/bugs/12801-2.zig created+24
...@@ -0,0 +1,24 @@
1const std = @import("std");
2const builtin = @import("builtin");
3
4const Auto = struct {
5 auto: [max_len]u8 = undefined,
6 offset: u64 = 0,
7
8 comptime capacity: *const fn () u64 = capacity,
9
10 const max_len: u64 = 32;
11
12 fn capacity() u64 {
13 return max_len;
14 }
15};
16test {
17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
20
21 const a: Auto = .{ .offset = 16, .capacity = Auto.capacity };
22 try std.testing.expect(a.capacity() == 32);
23 try std.testing.expect((a.capacity)() == 32);
24}
test/behavior/eval.zig+61
...@@ -1337,3 +1337,64 @@ test "lazy value is resolved as slice operand" {...@@ -1337,3 +1337,64 @@ test "lazy value is resolved as slice operand" {
1337 try expect(@ptrToInt(ptr1) == @ptrToInt(ptr2));1337 try expect(@ptrToInt(ptr1) == @ptrToInt(ptr2));
1338 try expect(ptr1.len == ptr2.len);1338 try expect(ptr1.len == ptr2.len);
1339}1339}
1340
1341test "break from inline loop depends on runtime condition" {
1342 const S = struct {
1343 fn foo(a: u8) bool {
1344 return a == 4;
1345 }
1346 };
1347 const arr = [_]u8{ 1, 2, 3, 4 };
1348 {
1349 const blk = blk: {
1350 inline for (arr) |val| {
1351 if (S.foo(val)) {
1352 break :blk val;
1353 }
1354 }
1355 return error.TestFailed;
1356 };
1357 try expect(blk == 4);
1358 }
1359
1360 {
1361 comptime var i = 0;
1362 const blk = blk: {
1363 inline while (i < arr.len) : (i += 1) {
1364 const val = arr[i];
1365 if (S.foo(val)) {
1366 break :blk val;
1367 }
1368 }
1369 return error.TestFailed;
1370 };
1371 try expect(blk == 4);
1372 }
1373}
1374
1375test "inline for inside a runtime condition" {
1376 var a = false;
1377 if (a) {
1378 const arr = .{ 1, 2, 3 };
1379 inline for (arr) |val| {
1380 if (val < 3) continue;
1381 try expect(val == 3);
1382 }
1383 }
1384}
1385
1386test "continue in inline for inside a comptime switch" {
1387 const arr = .{ 1, 2, 3 };
1388 var count: u8 = 0;
1389 switch (arr[1]) {
1390 2 => {
1391 inline for (arr) |val| {
1392 if (val == 2) continue;
1393
1394 count += val;
1395 }
1396 },
1397 else => {},
1398 }
1399 try expect(count == 4);
1400}
test/behavior/generics.zig+11
...@@ -358,3 +358,14 @@ test "nested generic function" {...@@ -358,3 +358,14 @@ test "nested generic function" {
358 try expect(@typeInfo(@TypeOf(S.g)).Fn.is_generic);358 try expect(@typeInfo(@TypeOf(S.g)).Fn.is_generic);
359 try S.foo(u32, S.bar, 123);359 try S.foo(u32, S.bar, 123);
360}360}
361
362test "extern function used as generic parameter" {
363 const S = struct {
364 extern fn foo() void;
365 extern fn bar() void;
366 inline fn baz(comptime _: anytype) type {
367 return struct {};
368 }
369 };
370 try expect(S.baz(S.foo) != S.baz(S.bar));
371}
test/cases/compile_errors/comptime_continue_to_outer_inline_loop.zig created+21
...@@ -0,0 +1,21 @@
1pub export fn entry() void {
2 var a = false;
3 const arr1 = .{ 1, 2, 3 };
4 loop: inline for (arr1) |val1| {
5 _ = val1;
6 if (a) {
7 const arr = .{ 1, 2, 3 };
8 inline for (arr) |val| {
9 if (val < 3) continue :loop;
10 if (val != 3) unreachable;
11 }
12 }
13 }
14}
15
16// error
17// backend=stage2
18// target=native
19//
20// :9:30: error: comptime control flow inside runtime block
21// :6:13: note: runtime control flow here
test/cases/compile_errors/comptime_store_in_comptime_switch_in_runtime_if.zig created+25
...@@ -0,0 +1,25 @@
1fn foo() bool {
2 return false;
3}
4
5pub export fn entry() void {
6 const Widget = union(enum) { a: u0 };
7
8 comptime var a = 1;
9 const info = @typeInfo(Widget).Union;
10 inline for (info.fields) |field| {
11 if (foo()) {
12 switch (field.field_type) {
13 u0 => a = 2,
14 else => unreachable,
15 }
16 }
17 }
18}
19
20// error
21// backend=stage2
22// target=native
23//
24// :13:27: error: store to comptime variable depends on runtime condition
25// :11:16: note: runtime condition here
test/cases/compile_errors/top_level_decl_dependency_loop.zig-1
...@@ -10,4 +10,3 @@ export fn entry() void {...@@ -10,4 +10,3 @@ export fn entry() void {
10// target=native10// target=native
11//11//
12// :1:1: error: dependency loop detected12// :1:1: error: dependency loop detected
13// :2:19: note: referenced here