authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-04-29 12:35:38+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-04-30 08:57:51+01:00
log57634b7809d07c8a07a015bec55829937d5795e1
tree033baabefeb61b5c291a2b0f044a5b002c0b4f99
parent213c4fc25f214a0d8763bd7976db9ae3eec0f232
signaturelock-open Commit is signed but in an unrecognized format.

compiler: remove `i0` from the language

Resolves: https://github.com/ziglang/zig/issues/1593

12 files changed, 81 insertions(+), 79 deletions(-)

lib/std/zig/AstGen.zig+55-47
......@@ -8073,39 +8073,42 @@ fn identifier(
80738073 return rvalue(gz, ri, zir_const_ref, ident);
80748074 }
80758075
8076 if (ident_name_raw.len >= 2) integer: {
8077 // Keep in sync with logic in `comptimeExpr2`.
8078 const first_c = ident_name_raw[0];
8079 if (first_c == 'i' or first_c == 'u') {
8080 const signedness: std.builtin.Signedness = switch (first_c == 'i') {
8081 true => .signed,
8082 false => .unsigned,
8083 };
8084 if (ident_name_raw.len >= 3 and ident_name_raw[1] == '0') {
8085 return astgen.failNode(
8086 ident,
8087 "primitive integer type '{s}' has leading zero",
8088 .{ident_name_raw},
8089 );
8090 }
8091 const bit_count = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) {
8092 error.Overflow => return astgen.failNode(
8093 ident,
8094 "primitive integer type '{s}' exceeds maximum bit width of 65535",
8095 .{ident_name_raw},
8096 ),
8097 error.InvalidCharacter => break :integer,
8098 };
8099 const result = try gz.add(.{
8100 .tag = .int_type,
8101 .data = .{ .int_type = .{
8102 .src_node = gz.nodeIndexToRelative(ident),
8103 .signedness = signedness,
8104 .bit_count = bit_count,
8105 } },
8106 });
8107 return rvalue(gz, ri, result, ident);
8076 int_type: {
8077 if (ident_name_raw.len < 2) break :int_type;
8078 const signedness: std.builtin.Signedness = switch (ident_name_raw[0]) {
8079 'u' => .unsigned,
8080 'i' => .signed,
8081 else => break :int_type,
8082 };
8083 // `u0` already handled by `primitive_instrs`
8084 if (std.mem.eql(u8, ident_name_raw, "i0")) {
8085 return astgen.failNode(ident, "signed integer cannot have bit width 0", .{});
8086 }
8087 if (ident_name_raw[1] == '0') {
8088 assert(ident_name_raw.len >= 3); // `u0` and `i0` handled
8089 return astgen.failNode(
8090 ident,
8091 "primitive integer type '{s}' has leading zero",
8092 .{ident_name_raw},
8093 );
81088094 }
8095 const bit_count = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) {
8096 error.Overflow => return astgen.failNode(
8097 ident,
8098 "primitive integer type '{s}' exceeds maximum bit width of 65535",
8099 .{ident_name_raw},
8100 ),
8101 error.InvalidCharacter => break :int_type,
8102 };
8103 const result = try gz.add(.{
8104 .tag = .int_type,
8105 .data = .{ .int_type = .{
8106 .src_node = gz.nodeIndexToRelative(ident),
8107 .signedness = signedness,
8108 .bit_count = bit_count,
8109 } },
8110 });
8111 return rvalue(gz, ri, result, ident);
81098112 }
81108113 }
81118114
......@@ -10122,32 +10125,37 @@ const primitive_instrs = std.StaticStringMap(Zir.Inst.Ref).initComptime(.{
1012210125 .{ "c_ushort", .c_ushort_type },
1012310126 .{ "comptime_float", .comptime_float_type },
1012410127 .{ "comptime_int", .comptime_int_type },
10125 .{ "f128", .f128_type },
10126 .{ "f16", .f16_type },
10127 .{ "f32", .f32_type },
10128 .{ "f64", .f64_type },
10129 .{ "f80", .f80_type },
1013010128 .{ "false", .bool_false },
10131 .{ "i16", .i16_type },
10132 .{ "i32", .i32_type },
10133 .{ "i64", .i64_type },
10134 .{ "i128", .i128_type },
10135 .{ "i8", .i8_type },
10136 .{ "isize", .isize_type },
1013710129 .{ "noreturn", .noreturn_type },
1013810130 .{ "null", .null_value },
1013910131 .{ "true", .bool_true },
1014010132 .{ "type", .type_type },
10133 .{ "undefined", .undef },
10134 .{ "void", .void_type },
10135
10136 .{ "f16", .f16_type },
10137 .{ "f32", .f32_type },
10138 .{ "f64", .f64_type },
10139 .{ "f80", .f80_type },
10140 .{ "f128", .f128_type },
10141
10142 .{ "u0", .u0_type },
10143 .{ "u1", .u1_type },
10144 .{ "u8", .u8_type },
10145 .{ "i8", .i8_type },
1014110146 .{ "u16", .u16_type },
10147 .{ "i16", .i16_type },
1014210148 .{ "u29", .u29_type },
1014310149 .{ "u32", .u32_type },
10150 .{ "i32", .i32_type },
1014410151 .{ "u64", .u64_type },
10152 .{ "i64", .i64_type },
10153 .{ "u80", .u80_type },
1014510154 .{ "u128", .u128_type },
10146 .{ "u1", .u1_type },
10147 .{ "u8", .u8_type },
10148 .{ "undefined", .undef },
10155 .{ "i128", .i128_type },
10156 .{ "u256", .u256_type },
1014910157 .{ "usize", .usize_type },
10150 .{ "void", .void_type },
10158 .{ "isize", .isize_type },
1015110159});
1015210160
1015310161comptime {
lib/std/zig/Zir.zig-1
......@@ -2197,7 +2197,6 @@ pub const Inst = struct {
21972197 /// and `[]Ref`.
21982198 pub const Ref = enum(u32) {
21992199 u0_type,
2200 i0_type,
22012200 u1_type,
22022201 u8_type,
22032202 i8_type,
src/Air.zig-1
......@@ -1032,7 +1032,6 @@ pub const Inst = struct {
10321032 /// The ref `none` is an exception: it has the tag bit set but refers to the InternPool.
10331033 pub const Ref = enum(u32) {
10341034 u0_type = @intFromEnum(InternPool.Index.u0_type),
1035 i0_type = @intFromEnum(InternPool.Index.i0_type),
10361035 u1_type = @intFromEnum(InternPool.Index.u1_type),
10371036 u8_type = @intFromEnum(InternPool.Index.u8_type),
10381037 i8_type = @intFromEnum(InternPool.Index.i8_type),
src/InternPool.zig+1-8
......@@ -3902,7 +3902,6 @@ pub const Index = enum(u32) {
39023902 pub const last_value: Index = .empty_tuple;
39033903
39043904 u0_type,
3905 i0_type,
39063905 u1_type,
39073906 u8_type,
39083907 i8_type,
......@@ -4350,11 +4349,6 @@ pub const static_keys: [static_len]Key = .{
43504349 .bits = 0,
43514350 } },
43524351
4353 .{ .int_type = .{
4354 .signedness = .signed,
4355 .bits = 0,
4356 } },
4357
43584352 .{ .int_type = .{
43594353 .signedness = .unsigned,
43604354 .bits = 1,
......@@ -7207,6 +7201,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
72077201 try items.ensureUnusedCapacity(1);
72087202 switch (key) {
72097203 .int_type => |int_type| {
7204 if (int_type.signedness == .signed) assert(int_type.bits > 0);
72107205 const t: Tag = switch (int_type.signedness) {
72117206 .signed => .type_int_signed,
72127207 .unsigned => .type_int_unsigned,
......@@ -11447,7 +11442,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
1144711442 // mean that the range of type indices would not be dense.
1144811443 return switch (index) {
1144911444 .u0_type,
11450 .i0_type,
1145111445 .u1_type,
1145211446 .u8_type,
1145311447 .i8_type,
......@@ -11772,7 +11766,6 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.BaseAddr.Ta
1177211766pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
1177311767 return switch (index) {
1177411768 .u0_type,
11775 .i0_type,
1177611769 .u1_type,
1177711770 .u8_type,
1177811771 .i8_type,
src/Sema.zig+5-2
......@@ -19617,6 +19617,9 @@ fn zirReifyInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1961719617 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
1961819618 const signedness = try sema.resolveBuiltinEnum(block, signedness_src, extra.lhs, .Signedness, .{ .simple = .int_signedness });
1961919619 const bits: u16 = @intCast(try sema.resolveInt(block, bits_src, extra.rhs, .u16, .{ .simple = .int_bit_width }));
19620 if (bits == 0 and signedness == .signed) {
19621 return sema.fail(block, bits_src, "signed integer cannot have bit width 0", .{});
19622 }
1962019623 return .fromType(try sema.pt.intType(signedness, bits));
1962119624}
1962219625
......@@ -20708,7 +20711,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
2070820711 }
2070920712
2071020713 try sema.requireRuntimeBlock(block, src, operand_src);
20711 if (dest_scalar_ty.intInfo(zcu).bits == 0) {
20714 if (dest_scalar_ty.toIntern() == .u0_type) {
2071220715 if (block.wantSafety()) {
2071320716 // Emit an explicit safety check. We can do this one like `abs(x) < 1`.
2071420717 const abs_ref = try block.addTyOp(.abs, operand_ty, operand);
......@@ -20824,7 +20827,7 @@ fn zirRoundCast(
2082420827
2082520828 try sema.requireRuntimeBlock(block, src, operand_src);
2082620829
20827 if (dest_scalar_ty.intInfo(zcu).bits == 0) {
20830 if (dest_scalar_ty.toIntern() == .u0_type) {
2082820831 if (block.wantSafety()) {
2082920832 const abs_ref = try block.addTyOp(.abs, operand_ty, operand);
2083020833 const is_vector = dest_ty.zigTypeTag(zcu) == .vector;
src/Sema/LowerZon.zig+5-9
......@@ -448,16 +448,12 @@ fn lowerInt(
448448 // If lhs has less than the 32 bits rhs can hold, we need to check the max and
449449 // min values
450450 if (std.math.cast(u5, lhs_info.bits)) |bits| {
451 const min_int: i32 = if (lhs_info.signedness == .unsigned or bits == 0) b: {
452 break :b 0;
453 } else b: {
454 break :b -(@as(i32, 1) << (bits - 1));
455 };
456 const max_int: i32 = if (bits == 0) b: {
457 break :b 0;
458 } else b: {
459 break :b (@as(i32, 1) << (bits - @intFromBool(lhs_info.signedness == .signed))) - 1;
451 const unsigned_bits = bits - @intFromBool(lhs_info.signedness == .signed);
452 const min_int: i32 = switch (lhs_info.signedness) {
453 .unsigned => 0,
454 .signed => -(@as(i32, 1) << unsigned_bits),
460455 };
456 const max_int: i32 = (@as(i32, 1) << unsigned_bits) - 1;
461457 if (rhs < min_int or rhs > max_int) {
462458 return self.fail(
463459 node,
src/Sema/arith.zig+9-5
......@@ -20,7 +20,7 @@ pub fn incrementDefinedInt(
2020 const zcu = pt.zcu;
2121 assert(prev_val.typeOf(zcu).toIntern() == ty.toIntern());
2222 assert(!prev_val.isUndef(zcu));
23 if (ty.intInfo(zcu).bits == 0) {
23 if (ty.toIntern() == .u0_type) {
2424 return .{ .overflow = true, .val = try comptimeIntAdd(sema, prev_val, .one_comptime_int) };
2525 }
2626 const res = try intAdd(sema, prev_val, try pt.intValue(ty, 1), ty);
......@@ -1313,7 +1313,7 @@ fn bitwiseBinScalar(
13131313 0b11 => return pt.undefValue(ty),
13141314 };
13151315 };
1316 if (ty.toIntern() == .u0_type or ty.toIntern() == .i0_type) return pt.intValue(ty, 0);
1316 if (ty.toIntern() == .u0_type) return pt.intValue(ty, 0);
13171317 // zig fmt: off
13181318 switch (op) {
13191319 .@"and" => return intBitwiseAnd(sema, def_lhs, def_rhs, ty),
......@@ -2209,9 +2209,13 @@ fn intBitwiseNot(sema: *Sema, val: Value, ty: Type) !Value {
22092209 const zcu = pt.zcu;
22102210
22112211 if (val.isUndef(zcu)) return pt.undefValue(ty);
2212 if (ty.toIntern() == .bool_type) return .makeBool(!val.toBool());
2212 switch (ty.toIntern()) {
2213 .bool_type => return .makeBool(!val.toBool()),
2214 .u0_type => return val,
2215 else => {},
2216 }
2217
22132218 const info = ty.intInfo(zcu);
2214 if (info.bits == 0) return val;
22152219
22162220 var val_space: Value.BigIntSpace = undefined;
22172221 const val_bigint = val.toBigInt(&val_space, zcu);
......@@ -2231,7 +2235,7 @@ fn intValueAa(sema: *Sema, ty: Type) !Value {
22312235 const zcu = pt.zcu;
22322236
22332237 if (ty.toIntern() == .bool_type) return .true;
2234 if (ty.toIntern() == .u0_type or ty.toIntern() == .i0_type) return pt.intValue(ty, 0);
2238 if (ty.toIntern() == .u0_type) return pt.intValue(ty, 0);
22352239 const info = ty.intInfo(zcu);
22362240
22372241 const buf = try sema.arena.alloc(u8, (info.bits + 7) / 8);
src/Type.zig+1-1
......@@ -2272,7 +2272,7 @@ pub fn minInt(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value {
22722272pub fn minIntScalar(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value {
22732273 const zcu = pt.zcu;
22742274 const info = ty.intInfo(zcu);
2275 if (info.signedness == .unsigned or info.bits == 0) return pt.intValue(dest_ty, 0);
2275 if (info.signedness == .unsigned) return pt.intValue(dest_ty, 0);
22762276
22772277 if (std.math.cast(u6, info.bits - 1)) |shift| {
22782278 const n = @as(i64, std.math.minInt(i64)) >> (63 - shift);
src/Value.zig+1-1
......@@ -518,9 +518,9 @@ pub fn readFromPackedMemory(
518518 },
519519 .int => {
520520 if (buffer.len == 0) return pt.intValue(ty, 0);
521 if (ty.toIntern() == .u0_type) return pt.intValue(ty, 0);
521522 const int_info = ty.intInfo(zcu);
522523 const bits = int_info.bits;
523 if (bits == 0) return pt.intValue(ty, 0);
524524
525525 // Fast path for integers <= u64
526526 if (bits <= 64) switch (int_info.signedness) {
src/codegen/llvm.zig+1-1
......@@ -2948,7 +2948,7 @@ pub const Object = struct {
29482948 const target = zcu.getTarget();
29492949 const ip = &zcu.intern_pool;
29502950 return switch (t.toIntern()) {
2951 .u0_type, .i0_type => unreachable, // no runtime bits
2951 .u0_type => unreachable, // no runtime bits
29522952 inline .u1_type,
29532953 .u8_type,
29542954 .i8_type,
src/codegen/llvm/FuncGen.zig+1-1
......@@ -7410,7 +7410,7 @@ fn toLlvmAtomicRmwBinOp(
74107410
74117411fn minIntConst(b: *Builder, min_ty: Type, as_ty: Builder.Type, zcu: *const Zcu) Allocator.Error!Builder.Constant {
74127412 const info = min_ty.intInfo(zcu);
7413 if (info.signedness == .unsigned or info.bits == 0) {
7413 if (info.signedness == .unsigned) {
74147414 return b.intConst(as_ty, 0);
74157415 }
74167416 if (std.math.cast(u6, info.bits - 1)) |shift| {
src/codegen/spirv/CodeGen.zig+2-2
......@@ -1327,12 +1327,12 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
13271327 .indirect => return try cg.resolveType(.u1, .indirect),
13281328 },
13291329 .int => {
1330 const int_info = ty.intInfo(zcu);
1331 if (int_info.bits == 0) {
1330 if (ty.toIntern() == .u0_type) {
13321331 assert(repr == .indirect);
13331332 if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
13341333 return try cg.module.opaqueType("u0");
13351334 }
1335 const int_info = ty.intInfo(zcu);
13361336 return try cg.module.intType(int_info.signedness, int_info.bits);
13371337 },
13381338 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),