| author | |
| committer | |
| log | 78855bd21866b515018259a2194e036e4b3120df |
| tree | 9d5df7cd0e5d909163475a5bdb30c94794460321 |
| parent | fbd90e487b4abe32422dc997467b1d81ad574d5d |
Closes #7865 files changed, 81 insertions(+), 28 deletions(-)
src/Compilation.zig+23| ... | @@ -739,6 +739,7 @@ pub const InitOptions = struct { | ... | @@ -739,6 +739,7 @@ pub const InitOptions = struct { |
| 739 | pdb_source_path: ?[]const u8 = null, | 739 | pdb_source_path: ?[]const u8 = null, |
| 740 | /// (Windows) PDB output path | 740 | /// (Windows) PDB output path |
| 741 | pdb_out_path: ?[]const u8 = null, | 741 | pdb_out_path: ?[]const u8 = null, |
| 742 | error_limit: ?Module.ErrorInt = null, | ||
| 742 | }; | 743 | }; |
| 743 | 744 | ||
| 744 | fn addModuleTableToCacheHash( | 745 | fn addModuleTableToCacheHash( |
| ... | @@ -1418,6 +1419,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1418,6 +1419,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1418 | .local_zir_cache = local_zir_cache, | 1419 | .local_zir_cache = local_zir_cache, |
| 1419 | .emit_h = emit_h, | 1420 | .emit_h = emit_h, |
| 1420 | .tmp_hack_arena = std.heap.ArenaAllocator.init(gpa), | 1421 | .tmp_hack_arena = std.heap.ArenaAllocator.init(gpa), |
| 1422 | .error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1), | ||
| 1421 | }; | 1423 | }; |
| 1422 | try module.init(); | 1424 | try module.init(); |
| 1423 | 1425 | ||
| ... | @@ -2472,6 +2474,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes | ... | @@ -2472,6 +2474,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes |
| 2472 | man.hash.add(comp.bin_file.options.skip_linker_dependencies); | 2474 | man.hash.add(comp.bin_file.options.skip_linker_dependencies); |
| 2473 | man.hash.add(comp.bin_file.options.parent_compilation_link_libc); | 2475 | man.hash.add(comp.bin_file.options.parent_compilation_link_libc); |
| 2474 | man.hash.add(mod.emit_h != null); | 2476 | man.hash.add(mod.emit_h != null); |
| 2477 | man.hash.add(mod.error_limit); | ||
| 2475 | } | 2478 | } |
| 2476 | 2479 | ||
| 2477 | try man.addOptionalFile(comp.bin_file.options.linker_script); | 2480 | try man.addOptionalFile(comp.bin_file.options.linker_script); |
| ... | @@ -2852,6 +2855,10 @@ pub fn totalErrorCount(self: *Compilation) u32 { | ... | @@ -2852,6 +2855,10 @@ pub fn totalErrorCount(self: *Compilation) u32 { |
| 2852 | } | 2855 | } |
| 2853 | } | 2856 | } |
| 2854 | } | 2857 | } |
| 2858 | |||
| 2859 | if (module.global_error_set.entries.len - 1 > module.error_limit) { | ||
| 2860 | total += 1; | ||
| 2861 | } | ||
| 2855 | } | 2862 | } |
| 2856 | 2863 | ||
| 2857 | // The "no entry point found" error only counts if there are no semantic analysis errors. | 2864 | // The "no entry point found" error only counts if there are no semantic analysis errors. |
| ... | @@ -3002,6 +3009,22 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { | ... | @@ -3002,6 +3009,22 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { |
| 3002 | for (module.failed_exports.values()) |value| { | 3009 | for (module.failed_exports.values()) |value| { |
| 3003 | try addModuleErrorMsg(module, &bundle, value.*); | 3010 | try addModuleErrorMsg(module, &bundle, value.*); |
| 3004 | } | 3011 | } |
| 3012 | |||
| 3013 | const actual_error_count = module.global_error_set.entries.len - 1; | ||
| 3014 | if (actual_error_count > module.error_limit) { | ||
| 3015 | try bundle.addRootErrorMessage(.{ | ||
| 3016 | .msg = try bundle.printString("module used more errors than possible: used {d}, max {d}", .{ | ||
| 3017 | actual_error_count, module.error_limit, | ||
| 3018 | }), | ||
| 3019 | .notes_len = 1, | ||
| 3020 | }); | ||
| 3021 | const notes_start = try bundle.reserveNotes(1); | ||
| 3022 | bundle.extra.items[notes_start] = @intFromEnum(try bundle.addErrorMessage(.{ | ||
| 3023 | .msg = try bundle.printString("use '--error-limit {d}' to increase limit", .{ | ||
| 3024 | actual_error_count, | ||
| 3025 | }), | ||
| 3026 | })); | ||
| 3027 | } | ||
| 3005 | } | 3028 | } |
| 3006 | 3029 | ||
| 3007 | if (bundle.root_list.items.len == 0) { | 3030 | if (bundle.root_list.items.len == 0) { |
src/Module.zig+8| ... | @@ -137,6 +137,9 @@ deletion_set: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, | ... | @@ -137,6 +137,9 @@ deletion_set: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, |
| 137 | /// Key is the error name, index is the error tag value. Index 0 has a length-0 string. | 137 | /// Key is the error name, index is the error tag value. Index 0 has a length-0 string. |
| 138 | global_error_set: GlobalErrorSet = .{}, | 138 | global_error_set: GlobalErrorSet = .{}, |
| 139 | 139 | ||
| 140 | /// Maximum amount of distinct error values, set by --error-limit | ||
| 141 | error_limit: ErrorInt, | ||
| 142 | |||
| 140 | /// Incrementing integer used to compare against the corresponding Decl | 143 | /// Incrementing integer used to compare against the corresponding Decl |
| 141 | /// field to determine whether a Decl's status applies to an ongoing update, or a | 144 | /// field to determine whether a Decl's status applies to an ongoing update, or a |
| 142 | /// previous analysis. | 145 | /// previous analysis. |
| ... | @@ -5020,6 +5023,11 @@ pub fn getErrorValueFromSlice( | ... | @@ -5020,6 +5023,11 @@ pub fn getErrorValueFromSlice( |
| 5020 | return getErrorValue(mod, interned_name); | 5023 | return getErrorValue(mod, interned_name); |
| 5021 | } | 5024 | } |
| 5022 | 5025 | ||
| 5026 | pub fn errorSetBits(mod: *Module) u16 { | ||
| 5027 | if (mod.error_limit == 0) return 0; | ||
| 5028 | return std.math.log2_int_ceil(ErrorInt, mod.error_limit + 1); // +1 for no error | ||
| 5029 | } | ||
| 5030 | |||
| 5023 | pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index { | 5031 | pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index { |
| 5024 | const src_decl = mod.declPtr(block.src_decl); | 5032 | const src_decl = mod.declPtr(block.src_decl); |
| 5025 | return mod.createAnonymousDeclFromDecl(src_decl, block.namespace, block.wip_capture_scope, typed_value); | 5033 | return mod.createAnonymousDeclFromDecl(src_decl, block.namespace, block.wip_capture_scope, typed_value); |
src/main.zig+9| ... | @@ -420,6 +420,7 @@ const usage_build_generic = | ... | @@ -420,6 +420,7 @@ const usage_build_generic = |
| 420 | \\ --deps [dep],[dep],... Set dependency names for the root package | 420 | \\ --deps [dep],[dep],... Set dependency names for the root package |
| 421 | \\ dep: [[import=]name] | 421 | \\ dep: [[import=]name] |
| 422 | \\ --main-mod-path Set the directory of the root module | 422 | \\ --main-mod-path Set the directory of the root module |
| 423 | \\ --error-limit [num] Set the maximum amount of distinct error values | ||
| 423 | \\ -fPIC Force-enable Position Independent Code | 424 | \\ -fPIC Force-enable Position Independent Code |
| 424 | \\ -fno-PIC Force-disable Position Independent Code | 425 | \\ -fno-PIC Force-disable Position Independent Code |
| 425 | \\ -fPIE Force-enable Position Independent Executable | 426 | \\ -fPIE Force-enable Position Independent Executable |
| ... | @@ -921,6 +922,8 @@ fn buildOutputType( | ... | @@ -921,6 +922,8 @@ fn buildOutputType( |
| 921 | var error_tracing: ?bool = null; | 922 | var error_tracing: ?bool = null; |
| 922 | var pdb_out_path: ?[]const u8 = null; | 923 | var pdb_out_path: ?[]const u8 = null; |
| 923 | var dwarf_format: ?std.dwarf.Format = null; | 924 | var dwarf_format: ?std.dwarf.Format = null; |
| 925 | var error_limit: ?Module.ErrorInt = null; | ||
| 926 | |||
| 924 | // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. | 927 | // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. |
| 925 | // This array is populated by zig cc frontend and then has to be converted to zig-style | 928 | // This array is populated by zig cc frontend and then has to be converted to zig-style |
| 926 | // CPU features. | 929 | // CPU features. |
| ... | @@ -1050,6 +1053,11 @@ fn buildOutputType( | ... | @@ -1050,6 +1053,11 @@ fn buildOutputType( |
| 1050 | root_deps_str = args_iter.nextOrFatal(); | 1053 | root_deps_str = args_iter.nextOrFatal(); |
| 1051 | } else if (mem.eql(u8, arg, "--main-mod-path")) { | 1054 | } else if (mem.eql(u8, arg, "--main-mod-path")) { |
| 1052 | main_mod_path = args_iter.nextOrFatal(); | 1055 | main_mod_path = args_iter.nextOrFatal(); |
| 1056 | } else if (mem.eql(u8, arg, "--error-limit")) { | ||
| 1057 | const next_arg = args_iter.nextOrFatal(); | ||
| 1058 | error_limit = std.fmt.parseUnsigned(Module.ErrorInt, next_arg, 0) catch |err| { | ||
| 1059 | fatal("unable to parse error limit '{s}': {s}", .{ next_arg, @errorName(err) }); | ||
| 1060 | }; | ||
| 1053 | } else if (mem.eql(u8, arg, "-cflags")) { | 1061 | } else if (mem.eql(u8, arg, "-cflags")) { |
| 1054 | extra_cflags.shrinkRetainingCapacity(0); | 1062 | extra_cflags.shrinkRetainingCapacity(0); |
| 1055 | while (true) { | 1063 | while (true) { |
| ... | @@ -3556,6 +3564,7 @@ fn buildOutputType( | ... | @@ -3556,6 +3564,7 @@ fn buildOutputType( |
| 3556 | .reference_trace = reference_trace, | 3564 | .reference_trace = reference_trace, |
| 3557 | .error_tracing = error_tracing, | 3565 | .error_tracing = error_tracing, |
| 3558 | .pdb_out_path = pdb_out_path, | 3566 | .pdb_out_path = pdb_out_path, |
| 3567 | .error_limit = error_limit, | ||
| 3559 | }) catch |err| switch (err) { | 3568 | }) catch |err| switch (err) { |
| 3560 | error.LibCUnavailable => { | 3569 | error.LibCUnavailable => { |
| 3561 | const target = target_info.target; | 3570 | const target = target_info.target; |
src/type.zig+26-20| ... | @@ -905,8 +905,11 @@ pub const Type = struct { | ... | @@ -905,8 +905,11 @@ pub const Type = struct { |
| 905 | .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), | 905 | .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), |
| 906 | .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()), | 906 | .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()), |
| 907 | 907 | ||
| 908 | // TODO revisit this when we have the concept of the error tag type | 908 | .error_set_type, .inferred_error_set_type => { |
| 909 | .error_set_type, .inferred_error_set_type => return .{ .scalar = .@"2" }, | 909 | const bits = mod.errorSetBits(); |
| 910 | if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" }; | ||
| 911 | return .{ .scalar = intAbiAlignment(bits, target) }; | ||
| 912 | }, | ||
| 910 | 913 | ||
| 911 | // represents machine code; not a pointer | 914 | // represents machine code; not a pointer |
| 912 | .func_type => |func_type| return .{ | 915 | .func_type => |func_type| return .{ |
| ... | @@ -967,10 +970,11 @@ pub const Type = struct { | ... | @@ -967,10 +970,11 @@ pub const Type = struct { |
| 967 | else => return .{ .scalar = .@"16" }, | 970 | else => return .{ .scalar = .@"16" }, |
| 968 | }, | 971 | }, |
| 969 | 972 | ||
| 970 | // TODO revisit this when we have the concept of the error tag type | 973 | .anyerror, .adhoc_inferred_error_set => { |
| 971 | .anyerror, | 974 | const bits = mod.errorSetBits(); |
| 972 | .adhoc_inferred_error_set, | 975 | if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" }; |
| 973 | => return .{ .scalar = .@"2" }, | 976 | return .{ .scalar = intAbiAlignment(bits, target) }; |
| 977 | }, | ||
| 974 | 978 | ||
| 975 | .void, | 979 | .void, |
| 976 | .type, | 980 | .type, |
| ... | @@ -1284,8 +1288,11 @@ pub const Type = struct { | ... | @@ -1284,8 +1288,11 @@ pub const Type = struct { |
| 1284 | 1288 | ||
| 1285 | .opt_type => return ty.abiSizeAdvancedOptional(mod, strat), | 1289 | .opt_type => return ty.abiSizeAdvancedOptional(mod, strat), |
| 1286 | 1290 | ||
| 1287 | // TODO revisit this when we have the concept of the error tag type | 1291 | .error_set_type, .inferred_error_set_type => { |
| 1288 | .error_set_type, .inferred_error_set_type => return AbiSizeAdvanced{ .scalar = 2 }, | 1292 | const bits = mod.errorSetBits(); |
| 1293 | if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; | ||
| 1294 | return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target) }; | ||
| 1295 | }, | ||
| 1289 | 1296 | ||
| 1290 | .error_union_type => |error_union_type| { | 1297 | .error_union_type => |error_union_type| { |
| 1291 | const payload_ty = error_union_type.payload_type.toType(); | 1298 | const payload_ty = error_union_type.payload_type.toType(); |
| ... | @@ -1379,10 +1386,11 @@ pub const Type = struct { | ... | @@ -1379,10 +1386,11 @@ pub const Type = struct { |
| 1379 | .enum_literal, | 1386 | .enum_literal, |
| 1380 | => return AbiSizeAdvanced{ .scalar = 0 }, | 1387 | => return AbiSizeAdvanced{ .scalar = 0 }, |
| 1381 | 1388 | ||
| 1382 | // TODO revisit this when we have the concept of the error tag type | 1389 | .anyerror, .adhoc_inferred_error_set => { |
| 1383 | .anyerror, | 1390 | const bits = mod.errorSetBits(); |
| 1384 | .adhoc_inferred_error_set, | 1391 | if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; |
| 1385 | => return AbiSizeAdvanced{ .scalar = 2 }, | 1392 | return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target) }; |
| 1393 | }, | ||
| 1386 | 1394 | ||
| 1387 | .prefetch_options => unreachable, // missing call to resolveTypeFields | 1395 | .prefetch_options => unreachable, // missing call to resolveTypeFields |
| 1388 | .export_options => unreachable, // missing call to resolveTypeFields | 1396 | .export_options => unreachable, // missing call to resolveTypeFields |
| ... | @@ -1576,8 +1584,7 @@ pub const Type = struct { | ... | @@ -1576,8 +1584,7 @@ pub const Type = struct { |
| 1576 | return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8; | 1584 | return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8; |
| 1577 | }, | 1585 | }, |
| 1578 | 1586 | ||
| 1579 | // TODO revisit this when we have the concept of the error tag type | 1587 | .error_set_type, .inferred_error_set_type => return mod.errorSetBits(), |
| 1580 | .error_set_type, .inferred_error_set_type => return 16, | ||
| 1581 | 1588 | ||
| 1582 | .error_union_type => { | 1589 | .error_union_type => { |
| 1583 | // Optionals and error unions are not packed so their bitsize | 1590 | // Optionals and error unions are not packed so their bitsize |
| ... | @@ -1610,10 +1617,9 @@ pub const Type = struct { | ... | @@ -1610,10 +1617,9 @@ pub const Type = struct { |
| 1610 | .bool => return 1, | 1617 | .bool => return 1, |
| 1611 | .void => return 0, | 1618 | .void => return 0, |
| 1612 | 1619 | ||
| 1613 | // TODO revisit this when we have the concept of the error tag type | ||
| 1614 | .anyerror, | 1620 | .anyerror, |
| 1615 | .adhoc_inferred_error_set, | 1621 | .adhoc_inferred_error_set, |
| 1616 | => return 16, | 1622 | => return mod.errorSetBits(), |
| 1617 | 1623 | ||
| 1618 | .anyopaque => unreachable, | 1624 | .anyopaque => unreachable, |
| 1619 | .type => unreachable, | 1625 | .type => unreachable, |
| ... | @@ -2172,8 +2178,7 @@ pub const Type = struct { | ... | @@ -2172,8 +2178,7 @@ pub const Type = struct { |
| 2172 | 2178 | ||
| 2173 | while (true) switch (ty.toIntern()) { | 2179 | while (true) switch (ty.toIntern()) { |
| 2174 | .anyerror_type, .adhoc_inferred_error_set_type => { | 2180 | .anyerror_type, .adhoc_inferred_error_set_type => { |
| 2175 | // TODO revisit this when error sets support custom int types | 2181 | return .{ .signedness = .unsigned, .bits = mod.errorSetBits() }; |
| 2176 | return .{ .signedness = .unsigned, .bits = 16 }; | ||
| 2177 | }, | 2182 | }, |
| 2178 | .usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() }, | 2183 | .usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() }, |
| 2179 | .isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() }, | 2184 | .isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() }, |
| ... | @@ -2192,8 +2197,9 @@ pub const Type = struct { | ... | @@ -2192,8 +2197,9 @@ pub const Type = struct { |
| 2192 | .enum_type => |enum_type| ty = enum_type.tag_ty.toType(), | 2197 | .enum_type => |enum_type| ty = enum_type.tag_ty.toType(), |
| 2193 | .vector_type => |vector_type| ty = vector_type.child.toType(), | 2198 | .vector_type => |vector_type| ty = vector_type.child.toType(), |
| 2194 | 2199 | ||
| 2195 | // TODO revisit this when error sets support custom int types | 2200 | .error_set_type, .inferred_error_set_type => { |
| 2196 | .error_set_type, .inferred_error_set_type => return .{ .signedness = .unsigned, .bits = 16 }, | 2201 | return .{ .signedness = .unsigned, .bits = mod.errorSetBits() }; |
| 2202 | }, | ||
| 2197 | 2203 | ||
| 2198 | .anon_struct_type => unreachable, | 2204 | .anon_struct_type => unreachable, |
| 2199 | 2205 |
src/value.zig+15-8| ... | @@ -701,15 +701,20 @@ pub const Value = struct { | ... | @@ -701,15 +701,20 @@ pub const Value = struct { |
| 701 | } | 701 | } |
| 702 | }, | 702 | }, |
| 703 | .ErrorSet => { | 703 | .ErrorSet => { |
| 704 | // TODO revisit this when we have the concept of the error tag type | 704 | const bits = mod.errorSetBits(); |
| 705 | const Int = u16; | 705 | const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8); |
| 706 | |||
| 706 | const name = switch (ip.indexToKey(val.toIntern())) { | 707 | const name = switch (ip.indexToKey(val.toIntern())) { |
| 707 | .err => |err| err.name, | 708 | .err => |err| err.name, |
| 708 | .error_union => |error_union| error_union.val.err_name, | 709 | .error_union => |error_union| error_union.val.err_name, |
| 709 | else => unreachable, | 710 | else => unreachable, |
| 710 | }; | 711 | }; |
| 711 | const int = @as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(name).?)); | 712 | var bigint_buffer: BigIntSpace = undefined; |
| 712 | std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], @as(Int, @intCast(int)), endian); | 713 | const bigint = BigIntMutable.init( |
| 714 | &bigint_buffer.limbs, | ||
| 715 | mod.global_error_set.getIndex(name).?, | ||
| 716 | ).toConst(); | ||
| 717 | bigint.writeTwosComplement(buffer[0..byte_count], endian); | ||
| 713 | }, | 718 | }, |
| 714 | .Union => switch (ty.containerLayout(mod)) { | 719 | .Union => switch (ty.containerLayout(mod)) { |
| 715 | .Auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already | 720 | .Auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already |
| ... | @@ -987,10 +992,12 @@ pub const Value = struct { | ... | @@ -987,10 +992,12 @@ pub const Value = struct { |
| 987 | } | 992 | } |
| 988 | }, | 993 | }, |
| 989 | .ErrorSet => { | 994 | .ErrorSet => { |
| 990 | // TODO revisit this when we have the concept of the error tag type | 995 | const bits = mod.errorSetBits(); |
| 991 | const Int = u16; | 996 | const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8); |
| 992 | const int = std.mem.readInt(Int, buffer[0..@sizeOf(Int)], endian); | 997 | const int = std.mem.readVarInt(u64, buffer[0..byte_count], endian); |
| 993 | const name = mod.global_error_set.keys()[@as(usize, @intCast(int))]; | 998 | const index = (int << @as(u6, @intCast(64 - bits))) >> @as(u6, @intCast(64 - bits)); |
| 999 | const name = mod.global_error_set.keys()[@intCast(index)]; | ||
| 1000 | |||
| 994 | return (try mod.intern(.{ .err = .{ | 1001 | return (try mod.intern(.{ .err = .{ |
| 995 | .ty = ty.toIntern(), | 1002 | .ty = ty.toIntern(), |
| 996 | .name = name, | 1003 | .name = name, |