| author | |
| committer | |
| log | b2aedb07096fa4ed8766d3aa87e70704cee68265 |
| tree | 415ec2d04881991f541477ec0d0c1d96a21d056d |
| parent | 8edd7219c0d5cc5799ae26ee8299b4d4114f7aed |
| parent | 31daea74d23be813737892a166cc16ade1272a1a |
| signature |
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 backend | 319 | \\ -fstage1 Force using bootstrap compiler as the codegen backend |
| 310 | \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend | 320 | \\ -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.zig | 323 | \\ --build-file [file] Override path to build.zig |
| 312 | \\ --cache-dir [path] Override path to local Zig cache directory | 324 | \\ --cache-dir [path] Override path to local Zig cache directory |
| 313 | \\ --global-cache-dir [path] Override path to global Zig cache directory | 325 | \\ --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 terminal | 45 | /// 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 | } |
| 2455 | 2456 | ||
| 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 | else | 1981 | 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. |
| 155 | color: Color = .auto, | 155 | color: Color = .auto, |
| 156 | 156 | ||
| 157 | /// How many lines of reference trace should be included per compile error. | ||
| 158 | /// Null means only show snippet on first error. | ||
| 159 | reference_trace: ?u32 = null, | ||
| 160 | |||
| 157 | libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default, | 161 | libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default, |
| 158 | 162 | ||
| 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 = &.{}, | ||
| 351 | 356 | ||
| 352 | /// Splits the error message up into lines to properly indent them | 357 | /// 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) = .{}, |
| 166 | 166 | ||
| 167 | global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{}, | 167 | global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{}, |
| 168 | 168 | ||
| 169 | reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct { | ||
| 170 | referencer: Decl.Index, | ||
| 171 | src: LazySrcLoc, | ||
| 172 | }) = .{}, | ||
| 173 | |||
| 169 | pub const StringLiteralContext = struct { | 174 | pub const StringLiteralContext = struct { |
| 170 | bytes: *std.ArrayListUnmanaged(u8), | 175 | bytes: *std.ArrayListUnmanaged(u8), |
| 171 | 176 | ||
| ... | @@ -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 | }; | ||
| 2087 | 2099 | ||
| 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 | }; |
| 2128 | 2147 | ||
| 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); | ||
| 3414 | 3434 | ||
| 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"); |
| 111 | const build_options = @import("build_options"); | 111 | const build_options = @import("build_options"); |
| 112 | 112 | ||
| 113 | pub const default_branch_quota = 1000; | 113 | pub const default_branch_quota = 1000; |
| 114 | pub const default_reference_trace_len = 2; | ||
| 114 | 115 | ||
| 115 | pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref); | 116 | pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref); |
| 116 | 117 | ||
| ... | @@ -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, | ||
| 147 | 149 | ||
| 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 be | 1299 | // 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)) orelse | 1376 | 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 | } |
| 1940 | 1960 | ||
| 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); |
| 4754 | 4817 | ||
| ... | @@ -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 | }; |
| 4851 | 4917 | ||
| 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 | } |
| 5353 | 5413 | ||
| 5354 | fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 5414 | fn 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))).?); |
| 17411 | 17478 | ||
| 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 | }); |
| 21655 | 21722 | ||
| 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 | } |
| 21716 | 21784 | ||
| 21717 | fn namespaceLookupVal( | 21785 | fn namespaceLookupVal( |
| ... | @@ -24771,6 +24839,20 @@ fn beginComptimePtrMutation( | ... | @@ -24771,6 +24839,20 @@ fn beginComptimePtrMutation( |
| 24771 | else => unreachable, | 24839 | else => unreachable, |
| 24772 | }, | 24840 | }, |
| 24773 | 24841 | ||
| 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 | } |
| 25969 | 26045 | ||
| 26046 | fn 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 | |||
| 25970 | fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void { | 26059 | fn 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 backend | 396 | \\ -fno-Clang Prevent using Clang as the C/C++ compilation backend |
| 397 | \\ -fstage1 Force using bootstrap compiler as the codegen backend | 397 | \\ -fstage1 Force using bootstrap compiler as the codegen backend |
| 398 | \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend | 398 | \\ -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 thread | 401 | \\ -fsingle-threaded Code assumes there is only one thread |
| 400 | \\ -fno-single-threaded Code may not assume there is only one thread | 402 | \\ -fno-single-threaded Code may not assume there is only one thread |
| 401 | \\ -fbuiltin Enable implicit builtin knowledge of functions | 403 | \\ -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; | ||
| 745 | 748 | ||
| 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-style | 750 | // 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 backend | 3758 | \\ -fstage1 Force using bootstrap compiler as the codegen backend |
| 3746 | \\ -fno-stage1 Prevent using bootstrap compiler as the codegen backend | 3759 | \\ -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.zig | 3762 | \\ --build-file [file] Override path to build.zig |
| 3748 | \\ --cache-dir [path] Override path to local Zig cache directory | 3763 | \\ --cache-dir [path] Override path to local Zig cache directory |
| 3749 | \\ --global-cache-dir [path] Override path to global Zig cache directory | 3764 | \\ --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), |
| 236 | 237 | ||
| 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), |
| 411 | 411 | ||
| 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.Node | 1552 | // 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 in | 1555 | // TODO: force self-hosted linkers with stage2 backend to avoid LLD creeping in |
| 1555 | // until the auto-select mechanism deems them worthy | 1556 | // 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 tag | 2396 | // 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | fn 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 | |||
| 22 | test { | ||
| 23 | _ = NamespacedGlobals(.{ | ||
| 24 | .mach = .{ | ||
| 25 | .globals = struct {}, | ||
| 26 | }, | ||
| 27 | }); | ||
| 28 | } | ||
test/behavior/bugs/12794.zig created+38| ... | @@ -0,0 +1,38 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | fn 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 | |||
| 20 | fn namespacedComponents(comptime modules: anytype) NamespacedComponents(modules) { | ||
| 21 | var x: NamespacedComponents(modules) = undefined; | ||
| 22 | x.components = modules.components; | ||
| 23 | return x; | ||
| 24 | } | ||
| 25 | |||
| 26 | pub fn World(comptime modules: anytype) type { | ||
| 27 | const all_components = namespacedComponents(modules); | ||
| 28 | _ = all_components; | ||
| 29 | return struct {}; | ||
| 30 | } | ||
| 31 | |||
| 32 | test { | ||
| 33 | _ = World(.{ | ||
| 34 | .components = .{ | ||
| 35 | .location = struct {}, | ||
| 36 | }, | ||
| 37 | }); | ||
| 38 | } | ||
test/behavior/bugs/12801-1.zig created+13| ... | @@ -0,0 +1,13 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | |||
| 4 | comptime capacity: fn () u64 = capacity_, | ||
| 5 | fn capacity_() u64 { | ||
| 6 | return 64; | ||
| 7 | } | ||
| 8 | |||
| 9 | test { | ||
| 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | |||
| 4 | const 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 | }; | ||
| 16 | test { | ||
| 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 | |||
| 1341 | test "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 | |||
| 1375 | test "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 | |||
| 1386 | test "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 | |||
| 362 | test "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 @@ | ||
| 1 | pub 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 @@ | ||
| 1 | fn foo() bool { | ||
| 2 | return false; | ||
| 3 | } | ||
| 4 | |||
| 5 | pub 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=native | 10 | // target=native |
| 11 | // | 11 | // |
| 12 | // :1:1: error: dependency loop detected | 12 | // :1:1: error: dependency loop detected |
| 13 | // :2:19: note: referenced here |