authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-01-24 13:35:10+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-16 04:08:45-04:00
log78855bd21866b515018259a2194e036e4b3120df
tree9d5df7cd0e5d909163475a5bdb30c94794460321
parentfbd90e487b4abe32422dc997467b1d81ad574d5d

make distinct error limit configurable

Closes #786

5 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 path740 /// (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};
743744
744fn addModuleTableToCacheHash(745fn 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();
14231425
...@@ -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 }
24762479
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 }
28562863
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 }
30063029
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.
138global_error_set: GlobalErrorSet = .{},138global_error_set: GlobalErrorSet = .{},
139139
140/// Maximum amount of distinct error values, set by --error-limit
141error_limit: ErrorInt,
142
140/// Incrementing integer used to compare against the corresponding Decl143/// Incrementing integer used to compare against the corresponding Decl
141/// field to determine whether a Decl's status applies to an ongoing update, or a144/// 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}
50225025
5026pub 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
5023pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index {5031pub 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 package420 \\ --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 module422 \\ --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 Code424 \\ -fPIC Force-enable Position Independent Code
424 \\ -fno-PIC Force-disable Position Independent Code425 \\ -fno-PIC Force-disable Position Independent Code
425 \\ -fPIE Force-enable Position Independent Executable426 \\ -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-style928 // 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()),
907907
908 // TODO revisit this when we have the concept of the error tag type908 .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 },
910913
911 // represents machine code; not a pointer914 // 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 },
969972
970 // TODO revisit this when we have the concept of the error tag type973 .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 },
974978
975 .void,979 .void,
976 .type,980 .type,
...@@ -1284,8 +1288,11 @@ pub const Type = struct {...@@ -1284,8 +1288,11 @@ pub const Type = struct {
12841288
1285 .opt_type => return ty.abiSizeAdvancedOptional(mod, strat),1289 .opt_type => return ty.abiSizeAdvancedOptional(mod, strat),
12861290
1287 // TODO revisit this when we have the concept of the error tag type1291 .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 },
12891296
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 },
13811388
1382 // TODO revisit this when we have the concept of the error tag type1389 .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 },
13861394
1387 .prefetch_options => unreachable, // missing call to resolveTypeFields1395 .prefetch_options => unreachable, // missing call to resolveTypeFields
1388 .export_options => unreachable, // missing call to resolveTypeFields1396 .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 },
15781586
1579 // TODO revisit this when we have the concept of the error tag type1587 .error_set_type, .inferred_error_set_type => return mod.errorSetBits(),
1580 .error_set_type, .inferred_error_set_type => return 16,
15811588
1582 .error_union_type => {1589 .error_union_type => {
1583 // Optionals and error unions are not packed so their bitsize1590 // 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,
16121619
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(),
16171623
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 {
21722178
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 types2181 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(),
21942199
2195 // TODO revisit this when error sets support custom int types2200 .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 },
21972203
2198 .anon_struct_type => unreachable,2204 .anon_struct_type => unreachable,
21992205
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 type704 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 already720 .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 type995 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,