diff options
| -rw-r--r-- | lib/compiler/std-docs.zig | 20 | ||||
| -rw-r--r-- | lib/std/packed_int_array.zig | 96 | ||||
| -rw-r--r-- | src/Compilation.zig | 25 | ||||
| -rw-r--r-- | src/Sema.zig | 39 | ||||
| -rw-r--r-- | src/codegen.zig | 2 | ||||
| -rw-r--r-- | src/link/Dwarf.zig | 62 | ||||
| -rw-r--r-- | test/behavior/error.zig | 15 | ||||
| -rw-r--r-- | test/cases.zig | 1 | ||||
| -rw-r--r-- | test/cases/compile_errors/@errorCast_with_bad_type.zig | 31 | ||||
| -rw-r--r-- | test/cases/compile_errors/error_union_field_default_init.zig | 13 | ||||
| -rw-r--r-- | test/cases/compile_errors/type_error_union_field_type.zig | 16 | ||||
| -rw-r--r-- | test/cases/translate_c/align() attribute.c | 17 | ||||
| -rw-r--r-- | test/cbe.zig | 953 | ||||
| -rw-r--r-- | test/translate_c.zig | 21 |
14 files changed, 245 insertions, 1066 deletions
diff --git a/lib/compiler/std-docs.zig b/lib/compiler/std-docs.zig index 93a04a28e5..d86be67702 100644 --- a/lib/compiler/std-docs.zig +++ b/lib/compiler/std-docs.zig @@ -177,6 +177,26 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void { try w.writeFile(file); try w.writeByteNTimes(0, padding); } + + { + // Since this command is JIT compiled, the builtin module available in + // this source file corresponds to the user's host system. + const builtin_zig = @embedFile("builtin"); + + var file_header = std.tar.output.Header.init(); + file_header.typeflag = .regular; + try file_header.setPath("builtin", "builtin.zig"); + try file_header.setSize(builtin_zig.len); + try file_header.updateChecksum(); + try w.writeAll(std.mem.asBytes(&file_header)); + try w.writeAll(builtin_zig); + const padding = p: { + const remainder = builtin_zig.len % 512; + break :p if (remainder > 0) 512 - remainder else 0; + }; + try w.writeByteNTimes(0, padding); + } + // intentionally omitting the pointless trailer //try w.writeByteNTimes(0, 512 * 2); try response.end(); diff --git a/lib/std/packed_int_array.zig b/lib/std/packed_int_array.zig index 7264fed599..02c721e7cf 100644 --- a/lib/std/packed_int_array.zig +++ b/lib/std/packed_int_array.zig @@ -66,32 +66,31 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type { fn getBits(bytes: []const u8, comptime Container: type, bit_index: usize) Int { const container_bits = @bitSizeOf(Container); - const Shift = std.math.Log2Int(Container); const start_byte = bit_index / 8; const head_keep_bits = bit_index - (start_byte * 8); const tail_keep_bits = container_bits - (int_bits + head_keep_bits); //read bytes as container - const value_ptr = @as(*align(1) const Container, @ptrCast(&bytes[start_byte])); + const value_ptr: *align(1) const Container = @ptrCast(&bytes[start_byte]); var value = value_ptr.*; if (endian != native_endian) value = @byteSwap(value); switch (endian) { .big => { - value <<= @as(Shift, @intCast(head_keep_bits)); - value >>= @as(Shift, @intCast(head_keep_bits)); - value >>= @as(Shift, @intCast(tail_keep_bits)); + value <<= @intCast(head_keep_bits); + value >>= @intCast(head_keep_bits); + value >>= @intCast(tail_keep_bits); }, .little => { - value <<= @as(Shift, @intCast(tail_keep_bits)); - value >>= @as(Shift, @intCast(tail_keep_bits)); - value >>= @as(Shift, @intCast(head_keep_bits)); + value <<= @intCast(tail_keep_bits); + value >>= @intCast(tail_keep_bits); + value >>= @intCast(head_keep_bits); }, } - return @as(Int, @bitCast(@as(UnInt, @truncate(value)))); + return @bitCast(@as(UnInt, @truncate(value))); } /// Sets the integer at `index` to `val` within the packed data beginning @@ -114,16 +113,16 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type { const start_byte = bit_index / 8; const head_keep_bits = bit_index - (start_byte * 8); const tail_keep_bits = container_bits - (int_bits + head_keep_bits); - const keep_shift = switch (endian) { - .big => @as(Shift, @intCast(tail_keep_bits)), - .little => @as(Shift, @intCast(head_keep_bits)), + const keep_shift: Shift = switch (endian) { + .big => @intCast(tail_keep_bits), + .little => @intCast(head_keep_bits), }; //position the bits where they need to be in the container const value = @as(Container, @intCast(@as(UnInt, @bitCast(int)))) << keep_shift; //read existing bytes - const target_ptr = @as(*align(1) Container, @ptrCast(&bytes[start_byte])); + const target_ptr: *align(1) Container = @ptrCast(&bytes[start_byte]); var target = target_ptr.*; if (endian != native_endian) target = @byteSwap(target); @@ -156,7 +155,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type { if (length == 0) return PackedIntSliceEndian(Int, endian).init(new_bytes[0..0], 0); var new_slice = PackedIntSliceEndian(Int, endian).init(new_bytes, length); - new_slice.bit_offset = @as(u3, @intCast((bit_index - (start_byte * 8)))); + new_slice.bit_offset = @intCast((bit_index - (start_byte * 8))); return new_slice; } @@ -214,15 +213,14 @@ pub fn PackedIntArrayEndian(comptime Int: type, comptime endian: Endian, comptim /// Initialize a packed array using an unpacked array /// or, more likely, an array literal. pub fn init(ints: [int_count]Int) Self { - var self = @as(Self, undefined); + var self: Self = undefined; for (ints, 0..) |int, i| self.set(i, int); return self; } /// Initialize all entries of a packed array to the same value. pub fn initAllTo(int: Int) Self { - // TODO: use `var self = @as(Self, undefined);` https://github.com/ziglang/zig/issues/7635 - var self = Self{ .bytes = [_]u8{0} ** total_bytes, .len = int_count }; + var self: Self = undefined; self.setAll(int); return self; } @@ -365,11 +363,11 @@ test "PackedIntArray" { const expected_bytes = ((bits * int_count) + 7) / 8; try testing.expect(@sizeOf(PackedArray) == expected_bytes); - var data = @as(PackedArray, undefined); + var data: PackedArray = undefined; //write values, counting up - var i = @as(usize, 0); - var count = @as(I, 0); + var i: usize = 0; + var count: I = 0; while (i < data.len) : (i += 1) { data.set(i, count); if (bits > 0) count +%= 1; @@ -395,17 +393,29 @@ test "PackedIntIo" { } test "PackedIntArray init" { - const PackedArray = PackedIntArray(u3, 8); - var packed_array = PackedArray.init([_]u3{ 0, 1, 2, 3, 4, 5, 6, 7 }); - var i = @as(usize, 0); - while (i < packed_array.len) : (i += 1) try testing.expectEqual(@as(u3, @intCast(i)), packed_array.get(i)); + const S = struct { + fn doTheTest() !void { + const PackedArray = PackedIntArray(u3, 8); + var packed_array = PackedArray.init([_]u3{ 0, 1, 2, 3, 4, 5, 6, 7 }); + var i: usize = 0; + while (i < packed_array.len) : (i += 1) try testing.expectEqual(@as(u3, @intCast(i)), packed_array.get(i)); + } + }; + try S.doTheTest(); + try comptime S.doTheTest(); } test "PackedIntArray initAllTo" { - const PackedArray = PackedIntArray(u3, 8); - var packed_array = PackedArray.initAllTo(5); - var i = @as(usize, 0); - while (i < packed_array.len) : (i += 1) try testing.expectEqual(@as(u3, 5), packed_array.get(i)); + const S = struct { + fn doTheTest() !void { + const PackedArray = PackedIntArray(u3, 8); + var packed_array = PackedArray.initAllTo(5); + var i: usize = 0; + while (i < packed_array.len) : (i += 1) try testing.expectEqual(@as(u3, 5), packed_array.get(i)); + } + }; + try S.doTheTest(); + try comptime S.doTheTest(); } test "PackedIntSlice" { @@ -433,8 +443,8 @@ test "PackedIntSlice" { var data = P.init(&buffer, int_count); //write values, counting up - var i = @as(usize, 0); - var count = @as(I, 0); + var i: usize = 0; + var count: I = 0; while (i < data.len) : (i += 1) { data.set(i, count); if (bits > 0) count +%= 1; @@ -463,13 +473,13 @@ test "PackedIntSlice of PackedInt(Array/Slice)" { const Int = std.meta.Int(.unsigned, bits); const PackedArray = PackedIntArray(Int, int_count); - var packed_array = @as(PackedArray, undefined); + var packed_array: PackedArray = undefined; const limit = (1 << bits); - var i = @as(usize, 0); + var i: usize = 0; while (i < packed_array.len) : (i += 1) { - packed_array.set(i, @as(Int, @intCast(i % limit))); + packed_array.set(i, @intCast(i % limit)); } //slice of array @@ -524,20 +534,20 @@ test "PackedIntSlice accumulating bit offsets" { // anything { const PackedArray = PackedIntArray(u3, 16); - var packed_array = @as(PackedArray, undefined); + var packed_array: PackedArray = undefined; var packed_slice = packed_array.slice(0, packed_array.len); - var i = @as(usize, 0); + var i: usize = 0; while (i < packed_array.len - 1) : (i += 1) { packed_slice = packed_slice.slice(1, packed_slice.len); } } { const PackedArray = PackedIntArray(u11, 88); - var packed_array = @as(PackedArray, undefined); + var packed_array: PackedArray = undefined; var packed_slice = packed_array.slice(0, packed_array.len); - var i = @as(usize, 0); + var i: usize = 0; while (i < packed_array.len - 1) : (i += 1) { packed_slice = packed_slice.slice(1, packed_slice.len); } @@ -552,7 +562,7 @@ test "PackedInt(Array/Slice) sliceCast" { var packed_slice_cast_9 = packed_array.slice(0, (packed_array.len / 9) * 9).sliceCast(u9); const packed_slice_cast_3 = packed_slice_cast_9.sliceCast(u3); - var i = @as(usize, 0); + var i: usize = 0; while (i < packed_slice_cast_2.len) : (i += 1) { const val = switch (native_endian) { .big => 0b01, @@ -576,9 +586,9 @@ test "PackedInt(Array/Slice) sliceCast" { } i = 0; while (i < packed_slice_cast_3.len) : (i += 1) { - const val = switch (native_endian) { - .big => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000), - .little => if (i % 2 == 0) @as(u3, 0b111) else @as(u3, 0b000), + const val: u3 = switch (native_endian) { + .big => if (i % 2 == 0) 0b111 else 0b000, + .little => if (i % 2 == 0) 0b111 else 0b000, }; try testing.expect(packed_slice_cast_3.get(i) == val); } @@ -591,7 +601,7 @@ test "PackedInt(Array/Slice)Endian" { try testing.expect(packed_array_be.bytes[0] == 0b00000001); try testing.expect(packed_array_be.bytes[1] == 0b00100011); - var i = @as(usize, 0); + var i: usize = 0; while (i < packed_array_be.len) : (i += 1) { try testing.expect(packed_array_be.get(i) == i); } @@ -620,7 +630,7 @@ test "PackedInt(Array/Slice)Endian" { try testing.expect(packed_array_be.bytes[3] == 0b00000001); try testing.expect(packed_array_be.bytes[4] == 0b00000000); - var i = @as(usize, 0); + var i: usize = 0; while (i < packed_array_be.len) : (i += 1) { try testing.expect(packed_array_be.get(i) == i); } diff --git a/src/Compilation.zig b/src/Compilation.zig index 003ecb8e28..5a6e02d400 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3696,6 +3696,9 @@ fn workerDocsCopy(comp: *Compilation, wg: *WaitGroup) void { } fn docsCopyFallible(comp: *Compilation) anyerror!void { + const zcu = comp.module orelse + return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{}); + const emit = comp.docs_emit.?; var out_dir = emit.directory.handle.makeOpenPath(emit.sub_path, .{}) catch |err| { return comp.lockAndSetMiscFailure( @@ -3726,7 +3729,25 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { }; defer tar_file.close(); - const root = comp.root_mod.root; + var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .{}; + defer seen_table.deinit(comp.gpa); + + try seen_table.put(comp.gpa, zcu.main_mod, {}); + try seen_table.put(comp.gpa, zcu.std_mod, {}); + + var i: usize = 0; + while (i < seen_table.count()) : (i += 1) { + const mod = seen_table.keys()[i]; + try comp.docsCopyModule(mod, tar_file); + + const deps = mod.deps.values(); + try seen_table.ensureUnusedCapacity(comp.gpa, deps.len); + for (deps) |dep| seen_table.putAssumeCapacity(dep, {}); + } +} + +fn docsCopyModule(comp: *Compilation, module: *Package.Module, tar_file: std.fs.File) !void { + const root = module.root; const sub_path = if (root.sub_path.len == 0) "." else root.sub_path; var mod_dir = root.root_dir.handle.openDir(sub_path, .{ .iterate = true }) catch |err| { return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{}': {s}", .{ @@ -3765,7 +3786,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { var file_header = std.tar.output.Header.init(); file_header.typeflag = .regular; - try file_header.setPath(comp.root_name, entry.path); + try file_header.setPath(module.fully_qualified_name, entry.path); try file_header.setSize(stat.size); try file_header.updateChecksum(); diff --git a/src/Sema.zig b/src/Sema.zig index d21fed6910..4541d02f66 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -22626,20 +22626,33 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData const base_operand_ty = sema.typeOf(operand); const dest_tag = base_dest_ty.zigTypeTag(mod); const operand_tag = base_operand_ty.zigTypeTag(mod); - if (dest_tag != operand_tag) { - return sema.fail(block, src, "expected source and destination types to match, found '{s}' and '{s}'", .{ - @tagName(operand_tag), @tagName(dest_tag), - }); - } else if (dest_tag != .ErrorSet and dest_tag != .ErrorUnion) { + + if (dest_tag != .ErrorSet and dest_tag != .ErrorUnion) { return sema.fail(block, src, "expected error set or error union type, found '{s}'", .{@tagName(dest_tag)}); } - const dest_ty, const operand_ty = if (dest_tag == .ErrorUnion) .{ - base_dest_ty.errorUnionSet(mod), - base_operand_ty.errorUnionSet(mod), - } else .{ - base_dest_ty, - base_operand_ty, - }; + if (operand_tag != .ErrorSet and operand_tag != .ErrorUnion) { + return sema.fail(block, src, "expected error set or error union type, found '{s}'", .{@tagName(operand_tag)}); + } + if (dest_tag == .ErrorSet and operand_tag == .ErrorUnion) { + return sema.fail(block, src, "cannot cast an error union type to error set", .{}); + } + if (dest_tag == .ErrorUnion and operand_tag == .ErrorUnion and + base_dest_ty.errorUnionPayload(mod).toIntern() != base_operand_ty.errorUnionPayload(mod).toIntern()) + { + return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(block, src, "payload types of error unions must match", .{}); + errdefer msg.destroy(sema.gpa); + const dest_ty = base_dest_ty.errorUnionPayload(mod); + const operand_ty = base_operand_ty.errorUnionPayload(mod); + try sema.errNote(block, src, msg, "destination payload is '{}'", .{dest_ty.fmt(mod)}); + try sema.errNote(block, src, msg, "operand payload is '{}'", .{operand_ty.fmt(mod)}); + try addDeclaredHereNote(sema, msg, dest_ty); + try addDeclaredHereNote(sema, msg, operand_ty); + break :msg msg; + }); + } + const dest_ty = if (dest_tag == .ErrorUnion) base_dest_ty.errorUnionSet(mod) else base_dest_ty; + const operand_ty = if (operand_tag == .ErrorUnion) base_operand_ty.errorUnionSet(mod) else base_operand_ty; // operand must be defined since it can be an invalid error value const maybe_operand_val = try sema.resolveDefinedValue(block, operand_src, operand); @@ -22681,7 +22694,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData if (!dest_ty.isAnyError(mod)) check: { const operand_val = mod.intern_pool.indexToKey(val.toIntern()); var error_name: InternPool.NullTerminatedString = undefined; - if (dest_tag == .ErrorUnion) { + if (operand_tag == .ErrorUnion) { if (operand_val.error_union.val != .err_name) break :check; error_name = operand_val.error_union.val.err_name; } else { diff --git a/src/codegen.zig b/src/codegen.zig index c5da0ebcb7..004cf7a7be 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -486,7 +486,7 @@ pub fn generateSymbol( const abi_size = math.cast(usize, ty.abiSize(mod)) orelse return error.Overflow; const current_pos = code.items.len; - try code.resize(current_pos + abi_size); + try code.appendNTimes(0, abi_size); var bits: u16 = 0; for (struct_type.field_types.get(ip), 0..) |field_ty, index| { diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index e2d4669156..6a41bb3793 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -187,17 +187,16 @@ pub const DeclState = struct { // DW.AT.name, DW.FORM.string try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(7); + try dbg_info_buffer.ensureUnusedCapacity(21); dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); // DW.AT.name, DW.FORM.string dbg_info_buffer.appendSliceAssumeCapacity("maybe"); dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); try self.addTypeRelocGlobal(atom_index, Type.bool, @intCast(index)); // DW.AT.data_member_location, DW.FORM.udata - try dbg_info_buffer.ensureUnusedCapacity(6); dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.member dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); @@ -206,7 +205,7 @@ pub const DeclState = struct { dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.type, DW.FORM.ref4 index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(index)); // DW.AT.data_member_location, DW.FORM.udata const offset = abi_size - payload_ty.abiSize(mod); @@ -228,18 +227,17 @@ pub const DeclState = struct { // DW.AT.name, DW.FORM.string try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(5); + try dbg_info_buffer.ensureUnusedCapacity(21); dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); // DW.AT.name, DW.FORM.string dbg_info_buffer.appendSliceAssumeCapacity("ptr"); dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); const ptr_ty = ty.slicePtrFieldType(mod); try self.addTypeRelocGlobal(atom_index, ptr_ty, @intCast(index)); // DW.AT.data_member_location, DW.FORM.udata - try dbg_info_buffer.ensureUnusedCapacity(6); dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.member dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); @@ -248,19 +246,18 @@ pub const DeclState = struct { dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.type, DW.FORM.ref4 index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(index)); // DW.AT.data_member_location, DW.FORM.udata - try dbg_info_buffer.ensureUnusedCapacity(2); dbg_info_buffer.appendAssumeCapacity(ptr_bytes); // DW.AT.structure_type delimit children dbg_info_buffer.appendAssumeCapacity(0); } else { - try dbg_info_buffer.ensureUnusedCapacity(5); + try dbg_info_buffer.ensureUnusedCapacity(9); dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.ptr_type)); // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); try self.addTypeRelocGlobal(atom_index, ty.childType(mod), @intCast(index)); } }, @@ -271,13 +268,14 @@ pub const DeclState = struct { try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + try dbg_info_buffer.ensureUnusedCapacity(9); + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); try self.addTypeRelocGlobal(atom_index, ty.childType(mod), @intCast(index)); // DW.AT.subrange_type - try dbg_info_buffer.append(@intFromEnum(AbbrevCode.array_dim)); + dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.array_dim)); // DW.AT.type, DW.FORM.ref4 index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(index)); // DW.AT.count, DW.FORM.udata const len = ty.arrayLenIncludingSentinel(mod); @@ -304,7 +302,7 @@ pub const DeclState = struct { try dbg_info_buffer.writer().print("{d}\x00", .{field_index}); // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + try dbg_info_buffer.appendNTimes(0, 4); try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index)); // DW.AT.data_member_location, DW.FORM.udata const field_off = ty.structFieldOffset(field_index, mod); @@ -331,7 +329,7 @@ pub const DeclState = struct { try dbg_info_buffer.writer().print("{d}\x00", .{field_index}); // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + try dbg_info_buffer.appendNTimes(0, 4); try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index)); // DW.AT.data_member_location, DW.FORM.udata try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); @@ -352,7 +350,7 @@ pub const DeclState = struct { dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + try dbg_info_buffer.appendNTimes(0, 4); try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index)); // DW.AT.data_member_location, DW.FORM.udata try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); @@ -418,14 +416,14 @@ pub const DeclState = struct { try dbg_info_buffer.append(0); // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(9); + try dbg_info_buffer.ensureUnusedCapacity(13); dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); // DW.AT.name, DW.FORM.string dbg_info_buffer.appendSliceAssumeCapacity("payload"); dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.type, DW.FORM.ref4 const inner_union_index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(inner_union_index + 4); + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); try self.addTypeRelocLocal(atom_index, @intCast(inner_union_index), 5); // DW.AT.data_member_location, DW.FORM.udata try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset); @@ -452,7 +450,7 @@ pub const DeclState = struct { try dbg_info_buffer.append(0); // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + try dbg_info_buffer.appendNTimes(0, 4); try self.addTypeRelocGlobal(atom_index, Type.fromInterned(field_ty), @intCast(index)); // DW.AT.data_member_location, DW.FORM.udata try dbg_info_buffer.append(0); @@ -462,14 +460,14 @@ pub const DeclState = struct { if (is_tagged) { // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(5); + try dbg_info_buffer.ensureUnusedCapacity(9); dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); // DW.AT.name, DW.FORM.string dbg_info_buffer.appendSliceAssumeCapacity("tag"); dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); try self.addTypeRelocGlobal(atom_index, Type.fromInterned(union_obj.enum_tag_ty), @intCast(index)); // DW.AT.data_member_location, DW.FORM.udata try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset); @@ -498,14 +496,14 @@ pub const DeclState = struct { if (!payload_ty.isNoReturn(mod)) { // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(7); + try dbg_info_buffer.ensureUnusedCapacity(11); dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); // DW.AT.name, DW.FORM.string dbg_info_buffer.appendSliceAssumeCapacity("value"); dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(index)); // DW.AT.data_member_location, DW.FORM.udata try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off); @@ -513,14 +511,14 @@ pub const DeclState = struct { { // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(5); + try dbg_info_buffer.ensureUnusedCapacity(9); dbg_info_buffer.appendAssumeCapacity(@intFromEnum(AbbrevCode.struct_member)); // DW.AT.name, DW.FORM.string dbg_info_buffer.appendSliceAssumeCapacity("err"); dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); try self.addTypeRelocGlobal(atom_index, error_ty, @intCast(index)); // DW.AT.data_member_location, DW.FORM.udata try leb128.writeULEB128(dbg_info_buffer.writer(), error_off); @@ -661,7 +659,7 @@ pub const DeclState = struct { try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); const index = dbg_info.items.len; - try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4 + dbg_info.appendNTimesAssumeCapacity(0, 4); try self.addTypeRelocGlobal(atom_index, ty, @intCast(index)); // DW.AT.type, DW.FORM.ref4 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string } @@ -877,7 +875,7 @@ pub const DeclState = struct { try dbg_info.ensureUnusedCapacity(5 + name_with_null.len); const index = dbg_info.items.len; - try dbg_info.resize(index + 4); // dw.at.type, dw.form.ref4 + dbg_info.appendNTimesAssumeCapacity(0, 4); // dw.at.type, dw.form.ref4 try self.addTypeRelocGlobal(atom_index, child_ty, @intCast(index)); dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string } @@ -1133,7 +1131,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: InternPool.DeclInde }); // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`. assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len); - dbg_line_buffer.items.len += ptr_width_bytes; + dbg_line_buffer.appendNTimesAssumeCapacity(0, ptr_width_bytes); dbg_line_buffer.appendAssumeCapacity(DW.LNS.advance_line); // This is the "relocatable" relative line offset from the previous function's end curly @@ -1171,12 +1169,12 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: InternPool.DeclInde // "relocations" and have to be in this fixed place so that functions can be // moved in virtual address space. assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len); - dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT.low_pc, DW.FORM.addr + dbg_info_buffer.appendNTimesAssumeCapacity(0, ptr_width_bytes); // DW.AT.low_pc, DW.FORM.addr assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); - dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4 + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); // DW.AT.high_pc, DW.FORM.data4 if (fn_ret_has_bits) { try decl_state.addTypeRelocGlobal(di_atom_index, fn_ret_type, @intCast(dbg_info_buffer.items.len)); - dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4 + dbg_info_buffer.appendNTimesAssumeCapacity(0, 4); // DW.AT.type, DW.FORM.ref4 } dbg_info_buffer.appendSliceAssumeCapacity( decl_name_slice[0 .. decl_name_slice.len + 1], diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 8e4dd2c091..8380c89619 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -930,6 +930,16 @@ test "optional error set return type" { try expect(E.A == S.foo(false).?); } +test "optional error set function parameter" { + const S = struct { + fn doTheTest(a: ?anyerror) !void { + try std.testing.expect(a.? == error.OutOfMemory); + } + }; + try S.doTheTest(error.OutOfMemory); + try comptime S.doTheTest(error.OutOfMemory); +} + test "returning an error union containing a type with no runtime bits" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -1039,3 +1049,8 @@ test "errorCast to adhoc inferred error set" { }; try std.testing.expect((try S.baz()) == 1234); } + +test "errorCast from error sets to error unions" { + const err_union: Set1!void = @errorCast(error.A); + try expectError(error.A, err_union); +} diff --git a/test/cases.zig b/test/cases.zig index 9bbdde4777..2c51078abd 100644 --- a/test/cases.zig +++ b/test/cases.zig @@ -11,7 +11,6 @@ pub const BuildOptions = struct { pub fn addCases(cases: *Cases, build_options: BuildOptions, b: *std.Build) !void { try @import("compile_errors.zig").addCases(cases, b); - try @import("cbe.zig").addCases(cases, b); try @import("llvm_targets.zig").addCases(cases, build_options, b); try @import("nvptx.zig").addCases(cases, b); } diff --git a/test/cases/compile_errors/@errorCast_with_bad_type.zig b/test/cases/compile_errors/@errorCast_with_bad_type.zig new file mode 100644 index 0000000000..6fc42f79f3 --- /dev/null +++ b/test/cases/compile_errors/@errorCast_with_bad_type.zig @@ -0,0 +1,31 @@ +const err = error.Foo; + +export fn entry1() void { + const a: anyerror = @errorCast(1); + _ = a; +} +export fn entry2() void { + const a: i32 = @errorCast(err); + _ = a; +} +export fn entry3() void { + const e: anyerror!void = err; + const a: anyerror = @errorCast(e); + _ = a; +} +pub export fn entry4() void { + const a: anyerror!u32 = 123; + const b: anyerror!f32 = @errorCast(a); + _ = b; +} + +// error +// backend=stage2 +// target=x86_64-linux +// +// :4:25: error: expected error set or error union type, found 'ComptimeInt' +// :8:20: error: expected error set or error union type, found 'Int' +// :13:25: error: cannot cast an error union type to error set +// :18:29: error: payload types of error unions must match +// :18:29: note: destination payload is 'f32' +// :18:29: note: operand payload is 'u32' diff --git a/test/cases/compile_errors/error_union_field_default_init.zig b/test/cases/compile_errors/error_union_field_default_init.zig new file mode 100644 index 0000000000..c3d9a62389 --- /dev/null +++ b/test/cases/compile_errors/error_union_field_default_init.zig @@ -0,0 +1,13 @@ +const Input = struct { + value: u32 = @as(error{}!u32, 0), +}; +export fn foo() void { + var x: Input = Input{}; + _ = &x; +} + +// error +// +//:2:18: error: expected type 'u32', found 'error{}!u32' +//:2:18: note: cannot convert error union to payload type +//:2:18: note: consider using 'try', 'catch', or 'if' diff --git a/test/cases/compile_errors/type_error_union_field_type.zig b/test/cases/compile_errors/type_error_union_field_type.zig new file mode 100644 index 0000000000..74aa93bc6a --- /dev/null +++ b/test/cases/compile_errors/type_error_union_field_type.zig @@ -0,0 +1,16 @@ +fn CreateType() !type { + return struct {}; +} +const MyType = CreateType(); +const TestType = struct { + my_type: MyType, +}; +comptime { + _ = @sizeOf(TestType) + 1; +} + +// error +// +//:6:14: error: expected type 'type', found 'error{}!type' +//:6:14: note: cannot convert error union to payload type +//:6:14: note: consider using 'try', 'catch', or 'if' diff --git a/test/cases/translate_c/align() attribute.c b/test/cases/translate_c/align() attribute.c new file mode 100644 index 0000000000..600e8251fb --- /dev/null +++ b/test/cases/translate_c/align() attribute.c @@ -0,0 +1,17 @@ +__attribute__ ((aligned(128))) +extern char my_array[16]; +__attribute__ ((aligned(128))) +void my_fn(void) { } +void other_fn(void) { + char ARR[16] __attribute__ ((aligned (16))); +} + +// translate-c +// c_frontend=clang +// +// pub extern var my_array: [16]u8 align(128); +// pub export fn my_fn() align(128) void {} +// pub export fn other_fn() void { +// var ARR: [16]u8 align(16) = undefined; +// _ = &ARR; +// } diff --git a/test/cbe.zig b/test/cbe.zig deleted file mode 100644 index 35c2d8e8f9..0000000000 --- a/test/cbe.zig +++ /dev/null @@ -1,953 +0,0 @@ -const std = @import("std"); -const Cases = @import("src/Cases.zig"); -const nl = if (@import("builtin").os.tag == .windows) "\r\n" else "\n"; - -pub fn addCases(ctx: *Cases, b: *std.Build) !void { - // These tests should work with all platforms, but we're using linux_x64 for - // now for consistency. Will be expanded eventually. - const linux_x64: std.Target.Query = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - }; - - { - var case = ctx.exeFromCompiledC("hello world with updates", .{}, b); - - // Regular old hello world - case.addCompareOutput( - \\extern fn puts(s: [*:0]const u8) c_int; - \\pub export fn main() c_int { - \\ _ = puts("hello world!"); - \\ return 0; - \\} - , "hello world!" ++ nl); - - // Now change the message only - case.addCompareOutput( - \\extern fn puts(s: [*:0]const u8) c_int; - \\pub export fn main() c_int { - \\ _ = puts("yo"); - \\ return 0; - \\} - , "yo" ++ nl); - - // Add an unused Decl - case.addCompareOutput( - \\extern fn puts(s: [*:0]const u8) c_int; - \\pub export fn main() c_int { - \\ _ = puts("yo!"); - \\ return 0; - \\} - \\fn unused() void {} - , "yo!" ++ nl); - - // Comptime return type and calling convention expected. - case.addError( - \\var x: i32 = 1234; - \\pub export fn main() x { - \\ return 0; - \\} - \\export fn foo() callconv(y) c_int { - \\ return 0; - \\} - \\var y: @import("std").builtin.CallingConvention = .C; - , &.{ - ":2:22: error: expected type 'type', found 'i32'", - ":5:26: error: unable to resolve comptime value", - ":5:26: note: calling convention must be comptime-known", - }); - } - - { - var case = ctx.exeFromCompiledC("var args", .{}, b); - - case.addCompareOutput( - \\extern fn printf(format: [*:0]const u8, ...) c_int; - \\ - \\pub export fn main() c_int { - \\ _ = printf("Hello, %s!\n", "world"); - \\ return 0; - \\} - , "Hello, world!" ++ nl); - } - - { - var case = ctx.exeFromCompiledC("errorFromInt", .{}, b); - - case.addCompareOutput( - \\pub export fn main() c_int { - \\ // comptime checks - \\ const a = error.A; - \\ const b = error.B; - \\ const c = @errorFromInt(2); - \\ const d = @errorFromInt(1); - \\ if (!(c == b)) unreachable; - \\ if (!(a == d)) unreachable; - \\ // runtime checks - \\ var x = error.A; - \\ var y = error.B; - \\ var z = @errorFromInt(2); - \\ var f = @errorFromInt(1); - \\ if (!(y == z)) unreachable; - \\ if (!(x == f)) unreachable; - \\ return 0; - \\} - , ""); - case.addError( - \\pub export fn main() c_int { - \\ _ = @errorFromInt(0); - \\ return 0; - \\} - , &.{":2:21: error: integer value '0' represents no error"}); - case.addError( - \\pub export fn main() c_int { - \\ _ = @errorFromInt(3); - \\ return 0; - \\} - , &.{":2:21: error: integer value '3' represents no error"}); - } - - { - var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64, b); - - // Exit with 0 - case.addCompareOutput( - \\fn exitGood() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ ); - \\ unreachable; - \\} - \\ - \\pub export fn main() c_int { - \\ exitGood(); - \\} - , ""); - - // Pass a usize parameter to exit - case.addCompareOutput( - \\pub export fn main() c_int { - \\ exit(0); - \\} - \\ - \\fn exit(code: usize) noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (code) - \\ ); - \\ unreachable; - \\} - , ""); - - // Change the parameter to u8 - case.addCompareOutput( - \\pub export fn main() c_int { - \\ exit(0); - \\} - \\ - \\fn exit(code: u8) noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (code) - \\ ); - \\ unreachable; - \\} - , ""); - - // Do some arithmetic at the exit callsite - case.addCompareOutput( - \\pub export fn main() c_int { - \\ exitMath(1); - \\} - \\ - \\fn exitMath(a: u8) noreturn { - \\ exit(0 + a - a); - \\} - \\ - \\fn exit(code: u8) noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (code) - \\ ); - \\ unreachable; - \\} - \\ - , ""); - - // Invert the arithmetic - case.addCompareOutput( - \\pub export fn main() c_int { - \\ exitMath(1); - \\} - \\ - \\fn exitMath(a: u8) noreturn { - \\ exit(a + 0 - a); - \\} - \\ - \\fn exit(code: u8) noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (code) - \\ ); - \\ unreachable; - \\} - \\ - , ""); - } - - { - var case = ctx.exeFromCompiledC("alloc and retptr", .{}, b); - - case.addCompareOutput( - \\fn add(a: i32, b: i32) i32 { - \\ return a + b; - \\} - \\ - \\fn addIndirect(a: i32, b: i32) i32 { - \\ return add(a, b); - \\} - \\ - \\pub export fn main() c_int { - \\ return addIndirect(1, 2) - 3; - \\} - , ""); - } - - { - var case = ctx.exeFromCompiledC("inferred local const and var", .{}, b); - - case.addCompareOutput( - \\fn add(a: i32, b: i32) i32 { - \\ return a + b; - \\} - \\ - \\pub export fn main() c_int { - \\ const x = add(1, 2); - \\ var y = add(3, 0); - \\ y -= x; - \\ return y; - \\} - , ""); - } - { - var case = ctx.exeFromCompiledC("control flow", .{}, b); - - // Simple while loop - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var a: c_int = 0; - \\ while (a < 5) : (a+=1) {} - \\ return a - 5; - \\} - , ""); - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var a = true; - \\ while (!a) {} - \\ return 0; - \\} - , ""); - - // If expression - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var cond: c_int = 0; - \\ var a: c_int = @as(c_int, if (cond == 0) - \\ 2 - \\ else - \\ 3) + 9; - \\ return a - 11; - \\} - , ""); - - // If expression with breakpoint that does not get hit - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var x: i32 = 1; - \\ if (x != 1) @breakpoint(); - \\ return 0; - \\} - , ""); - - // Switch expression - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var cond: c_int = 0; - \\ var a: c_int = switch (cond) { - \\ 1 => 1, - \\ 2 => 2, - \\ 99...300, 12 => 3, - \\ 0 => 4, - \\ else => 5, - \\ }; - \\ return a - 4; - \\} - , ""); - - // Switch expression missing else case. - case.addError( - \\pub export fn main() c_int { - \\ var cond: c_int = 0; - \\ const a: c_int = switch (cond) { - \\ 1 => 1, - \\ 2 => 2, - \\ 3 => 3, - \\ 4 => 4, - \\ }; - \\ return a - 4; - \\} - , &.{":3:22: error: switch must handle all possibilities"}); - - // Switch expression, has an unreachable prong. - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var cond: c_int = 0; - \\ const a: c_int = switch (cond) { - \\ 1 => 1, - \\ 2 => 2, - \\ 99...300, 12 => 3, - \\ 0 => 4, - \\ 13 => unreachable, - \\ else => 5, - \\ }; - \\ return a - 4; - \\} - , ""); - - // Switch expression, has an unreachable prong and prongs write - // to result locations. - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var cond: c_int = 0; - \\ var a: c_int = switch (cond) { - \\ 1 => 1, - \\ 2 => 2, - \\ 99...300, 12 => 3, - \\ 0 => 4, - \\ 13 => unreachable, - \\ else => 5, - \\ }; - \\ return a - 4; - \\} - , ""); - - // Integer switch expression has duplicate case value. - case.addError( - \\pub export fn main() c_int { - \\ var cond: c_int = 0; - \\ const a: c_int = switch (cond) { - \\ 1 => 1, - \\ 2 => 2, - \\ 96, 11...13, 97 => 3, - \\ 0 => 4, - \\ 90, 12 => 100, - \\ else => 5, - \\ }; - \\ return a - 4; - \\} - , &.{ - ":8:13: error: duplicate switch value", - ":6:15: note: previous value here", - }); - - // Boolean switch expression has duplicate case value. - case.addError( - \\pub export fn main() c_int { - \\ var a: bool = false; - \\ const b: c_int = switch (a) { - \\ false => 1, - \\ true => 2, - \\ false => 3, - \\ }; - \\ _ = b; - \\} - , &.{ - ":6:9: error: duplicate switch value", - }); - - // Sparse (no range capable) switch expression has duplicate case value. - case.addError( - \\pub export fn main() c_int { - \\ const A: type = i32; - \\ const b: c_int = switch (A) { - \\ i32 => 1, - \\ bool => 2, - \\ f64, i32 => 3, - \\ else => 4, - \\ }; - \\ _ = b; - \\} - , &.{ - ":6:14: error: duplicate switch value", - ":4:9: note: previous value here", - }); - - // Ranges not allowed for some kinds of switches. - case.addError( - \\pub export fn main() c_int { - \\ const A: type = i32; - \\ const b: c_int = switch (A) { - \\ i32 => 1, - \\ bool => 2, - \\ f16...f64 => 3, - \\ else => 4, - \\ }; - \\ _ = b; - \\} - , &.{ - ":3:30: error: ranges not allowed when switching on type 'type'", - ":6:12: note: range here", - }); - - // Switch expression has unreachable else prong. - case.addError( - \\pub export fn main() c_int { - \\ var a: u2 = 0; - \\ const b: i32 = switch (a) { - \\ 0 => 10, - \\ 1 => 20, - \\ 2 => 30, - \\ 3 => 40, - \\ else => 50, - \\ }; - \\ _ = b; - \\} - , &.{ - ":8:14: error: unreachable else prong; all cases already handled", - }); - } - //{ - // var case = ctx.exeFromCompiledC("optionals", .{}, b); - - // // Simple while loop - // case.addCompareOutput( - // \\pub export fn main() c_int { - // \\ var count: c_int = 0; - // \\ var opt_ptr: ?*c_int = &count; - // \\ while (opt_ptr) |_| : (count += 1) { - // \\ if (count == 4) opt_ptr = null; - // \\ } - // \\ return count - 5; - // \\} - // , ""); - - // // Same with non pointer optionals - // case.addCompareOutput( - // \\pub export fn main() c_int { - // \\ var count: c_int = 0; - // \\ var opt_ptr: ?c_int = count; - // \\ while (opt_ptr) |_| : (count += 1) { - // \\ if (count == 4) opt_ptr = null; - // \\ } - // \\ return count - 5; - // \\} - // , ""); - //} - - { - var case = ctx.exeFromCompiledC("errors", .{}, b); - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var e1 = error.Foo; - \\ var e2 = error.Bar; - \\ assert(e1 != e2); - \\ assert(e1 == error.Foo); - \\ assert(e2 == error.Bar); - \\ return 0; - \\} - \\fn assert(b: bool) void { - \\ if (!b) unreachable; - \\} - , ""); - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var e: anyerror!c_int = 0; - \\ const i = e catch 69; - \\ return i; - \\} - , ""); - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var e: anyerror!c_int = error.Foo; - \\ const i = e catch 69; - \\ return 69 - i; - \\} - , ""); - case.addCompareOutput( - \\const E = error{e}; - \\const S = struct { x: u32 }; - \\fn f() E!u32 { - \\ const x = (try @as(E!S, S{ .x = 1 })).x; - \\ return x; - \\} - \\pub export fn main() c_int { - \\ const x = f() catch @as(u32, 0); - \\ if (x != 1) unreachable; - \\ return 0; - \\} - , ""); - } - - { - var case = ctx.exeFromCompiledC("structs", .{}, b); - case.addError( - \\const Point = struct { x: i32, y: i32 }; - \\pub export fn main() c_int { - \\ var p: Point = .{ - \\ .y = 24, - \\ .x = 12, - \\ .y = 24, - \\ }; - \\ return p.y - p.x - p.x; - \\} - , &.{ - ":4:10: error: duplicate struct field name", - ":6:10: note: duplicate name here", - ":3:21: note: struct declared here", - }); - case.addError( - \\const Point = struct { x: i32, y: i32 }; - \\pub export fn main() c_int { - \\ var p: Point = .{ - \\ .y = 24, - \\ }; - \\ return p.y - p.x - p.x; - \\} - , &.{ - ":3:21: error: missing struct field: x", - ":1:15: note: struct 'tmp.Point' declared here", - }); - case.addError( - \\const Point = struct { x: i32, y: i32 }; - \\pub export fn main() c_int { - \\ var p: Point = .{ - \\ .x = 12, - \\ .y = 24, - \\ .z = 48, - \\ }; - \\ return p.y - p.x - p.x; - \\} - , &.{ - ":6:10: error: no field named 'z' in struct 'tmp.Point'", - ":1:15: note: struct declared here", - }); - case.addCompareOutput( - \\const Point = struct { x: i32, y: i32 }; - \\pub export fn main() c_int { - \\ var p: Point = .{ - \\ .x = 12, - \\ .y = 24, - \\ }; - \\ return p.y - p.x - p.x; - \\} - , ""); - case.addCompareOutput( - \\const Point = struct { x: i32, y: i32, z: i32, a: i32, b: i32 }; - \\pub export fn main() c_int { - \\ var p: Point = .{ - \\ .x = 18, - \\ .y = 24, - \\ .z = 1, - \\ .a = 2, - \\ .b = 3, - \\ }; - \\ return p.y - p.x - p.z - p.a - p.b; - \\} - , ""); - } - - { - var case = ctx.exeFromCompiledC("unions", .{}, b); - - case.addError( - \\const U = union { - \\ a: u32, - \\ b - \\}; - , &.{ - ":3:5: error: union field missing type", - }); - - case.addError( - \\const E = enum { a, b }; - \\const U = union(E) { - \\ a: u32 = 1, - \\ b: f32 = 2, - \\}; - , &.{ - ":2:11: error: explicitly valued tagged union requires inferred enum tag type", - ":3:14: note: tag value specified here", - }); - - case.addError( - \\const U = union(enum) { - \\ a: u32 = 1, - \\ b: f32 = 2, - \\}; - , &.{ - ":1:11: error: explicitly valued tagged union missing integer tag type", - ":2:14: note: tag value specified here", - }); - } - - { - var case = ctx.exeFromCompiledC("enums", .{}, b); - - case.addError( - \\const E1 = packed enum { a, b, c }; - \\const E2 = extern enum { a, b, c }; - \\export fn foo() void { - \\ _ = E1.a; - \\} - \\export fn bar() void { - \\ _ = E2.a; - \\} - , &.{ - ":1:12: error: enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", - ":2:12: error: enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", - }); - - // comptime and types are caught in AstGen. - case.addError( - \\const E1 = enum { - \\ a, - \\ comptime b, - \\ c, - \\}; - \\const E2 = enum { - \\ a, - \\ b: i32, - \\ c, - \\}; - \\export fn foo() void { - \\ _ = E1.a; - \\} - \\export fn bar() void { - \\ _ = E2.a; - \\} - , &.{ - ":3:5: error: enum fields cannot be marked comptime", - ":8:8: error: enum fields do not have types", - ":6:12: note: consider 'union(enum)' here to make it a tagged union", - }); - - // @intFromEnum, @enumFromInt, enum literal coercion, field access syntax, comparison, switch - case.addCompareOutput( - \\const Number = enum { One, Two, Three }; - \\ - \\pub export fn main() c_int { - \\ var number1 = Number.One; - \\ var number2: Number = .Two; - \\ const number3: Number = @enumFromInt(2); - \\ if (number1 == number2) return 1; - \\ if (number2 == number3) return 1; - \\ if (@intFromEnum(number1) != 0) return 1; - \\ if (@intFromEnum(number2) != 1) return 1; - \\ if (@intFromEnum(number3) != 2) return 1; - \\ var x: Number = .Two; - \\ if (number2 != x) return 1; - \\ switch (x) { - \\ .One => return 1, - \\ .Two => return 0, - \\ number3 => return 2, - \\ } - \\} - , ""); - - // Specifying alignment is a parse error. - // This also tests going from a successful build to a parse error. - case.addError( - \\const E1 = enum { - \\ a, - \\ b align(4), - \\ c, - \\}; - \\export fn foo() void { - \\ _ = E1.a; - \\} - , &.{ - ":3:13: error: enum fields cannot be aligned", - }); - - // Redundant non-exhaustive enum mark. - // This also tests going from a parse error to an AstGen error. - case.addError( - \\const E1 = enum { - \\ a, - \\ _, - \\ b, - \\ c, - \\ _, - \\}; - \\export fn foo() void { - \\ _ = E1.a; - \\} - , &.{ - ":6:5: error: redundant non-exhaustive enum mark", - ":3:5: note: other mark here", - }); - - case.addError( - \\const E1 = enum { - \\ a, - \\ b, - \\ c, - \\ _ = 10, - \\}; - \\export fn foo() void { - \\ _ = E1.a; - \\} - , &.{ - ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value", - }); - - case.addError( - \\const E1 = enum { a, b, _ }; - \\export fn foo() void { - \\ _ = E1.a; - \\} - , &.{ - ":1:12: error: non-exhaustive enum missing integer tag type", - ":1:25: note: marked non-exhaustive here", - }); - - case.addError( - \\const E1 = enum { a, b, c, b, d }; - \\pub export fn main() c_int { - \\ _ = E1.a; - \\} - , &.{ - ":1:22: error: duplicate enum field name", - ":1:28: note: duplicate field here", - ":1:12: note: enum declared here", - }); - - case.addError( - \\pub export fn main() c_int { - \\ const a = true; - \\ _ = @intFromEnum(a); - \\} - , &.{ - ":3:20: error: expected enum or tagged union, found 'bool'", - }); - - case.addError( - \\pub export fn main() c_int { - \\ const a = 1; - \\ _ = @as(bool, @enumFromInt(a)); - \\} - , &.{ - ":3:19: error: expected enum, found 'bool'", - }); - - case.addError( - \\const E = enum { a, b, c }; - \\pub export fn main() c_int { - \\ _ = @as(E, @enumFromInt(3)); - \\} - , &.{ - ":3:16: error: enum 'tmp.E' has no tag with value '3'", - ":1:11: note: enum declared here", - }); - - case.addError( - \\const E = enum { a, b, c }; - \\pub export fn main() c_int { - \\ var x: E = .a; - \\ switch (x) { - \\ .a => {}, - \\ .c => {}, - \\ } - \\} - , &.{ - ":4:5: error: switch must handle all possibilities", - ":1:21: note: unhandled enumeration value: 'b'", - ":1:11: note: enum 'tmp.E' declared here", - }); - - case.addError( - \\const E = enum { a, b, c }; - \\pub export fn main() c_int { - \\ var x: E = .a; - \\ switch (x) { - \\ .a => {}, - \\ .b => {}, - \\ .b => {}, - \\ .c => {}, - \\ } - \\} - , &.{ - ":7:10: error: duplicate switch value", - ":6:10: note: previous value here", - }); - - case.addError( - \\const E = enum { a, b, c }; - \\pub export fn main() c_int { - \\ var x: E = .a; - \\ switch (x) { - \\ .a => {}, - \\ .b => {}, - \\ .c => {}, - \\ else => {}, - \\ } - \\} - , &.{ - ":8:14: error: unreachable else prong; all cases already handled", - }); - - case.addError( - \\const E = enum { a, b, c }; - \\pub export fn main() c_int { - \\ var x: E = .a; - \\ switch (x) { - \\ .a => {}, - \\ .b => {}, - \\ _ => {}, - \\ } - \\} - , &.{ - ":4:5: error: '_' prong only allowed when switching on non-exhaustive enums", - ":7:11: note: '_' prong here", - }); - - case.addError( - \\const E = enum { a, b, c }; - \\pub export fn main() c_int { - \\ _ = E.d; - \\} - , &.{ - ":3:11: error: enum 'tmp.E' has no member named 'd'", - ":1:11: note: enum declared here", - }); - - case.addError( - \\const E = enum { a, b, c }; - \\pub export fn main() c_int { - \\ var x: E = .d; - \\ _ = x; - \\} - , &.{ - ":3:17: error: no field named 'd' in enum 'tmp.E'", - ":1:11: note: enum declared here", - }); - } - - { - var case = ctx.exeFromCompiledC("shift right and left", .{}, b); - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var i: u32 = 16; - \\ assert(i >> 1, 8); - \\ return 0; - \\} - \\fn assert(a: u32, b: u32) void { - \\ if (a != b) unreachable; - \\} - , ""); - - case.addCompareOutput( - \\pub export fn main() c_int { - \\ var i: u32 = 16; - \\ assert(i << 1, 32); - \\ return 0; - \\} - \\fn assert(a: u32, b: u32) void { - \\ if (a != b) unreachable; - \\} - , ""); - } - - { - var case = ctx.exeFromCompiledC("inferred error sets", .{}, b); - - case.addCompareOutput( - \\pub export fn main() c_int { - \\ if (foo()) |_| { - \\ @panic("test fail"); - \\ } else |err| { - \\ if (err != error.ItBroke) { - \\ @panic("test fail"); - \\ } - \\ } - \\ return 0; - \\} - \\fn foo() !void { - \\ return error.ItBroke; - \\} - , ""); - } - - { - // TODO: add u64 tests, ran into issues with the literal generated for std.math.maxInt(u64) - var case = ctx.exeFromCompiledC("add and sub wrapping operations", .{}, b); - case.addCompareOutput( - \\pub export fn main() c_int { - \\ // Addition - \\ if (!add_u3(1, 1, 2)) return 1; - \\ if (!add_u3(7, 1, 0)) return 1; - \\ if (!add_i3(1, 1, 2)) return 1; - \\ if (!add_i3(3, 2, -3)) return 1; - \\ if (!add_i3(-3, -2, 3)) return 1; - \\ if (!add_c_int(1, 1, 2)) return 1; - \\ // TODO enable these when stage2 supports std.math.maxInt - \\ //if (!add_c_int(maxInt(c_int), 2, minInt(c_int) + 1)) return 1; - \\ //if (!add_c_int(maxInt(c_int) + 1, -2, maxInt(c_int))) return 1; - \\ - \\ // Subtraction - \\ if (!sub_u3(2, 1, 1)) return 1; - \\ if (!sub_u3(0, 1, 7)) return 1; - \\ if (!sub_i3(2, 1, 1)) return 1; - \\ if (!sub_i3(3, -2, -3)) return 1; - \\ if (!sub_i3(-3, 2, 3)) return 1; - \\ if (!sub_c_int(2, 1, 1)) return 1; - \\ // TODO enable these when stage2 supports std.math.maxInt - \\ //if (!sub_c_int(maxInt(c_int), -2, minInt(c_int) + 1)) return 1; - \\ //if (!sub_c_int(minInt(c_int) + 1, 2, maxInt(c_int))) return 1; - \\ - \\ return 0; - \\} - \\fn add_u3(lhs: u3, rhs: u3, expected: u3) bool { - \\ return expected == lhs +% rhs; - \\} - \\fn add_i3(lhs: i3, rhs: i3, expected: i3) bool { - \\ return expected == lhs +% rhs; - \\} - \\fn add_c_int(lhs: c_int, rhs: c_int, expected: c_int) bool { - \\ return expected == lhs +% rhs; - \\} - \\fn sub_u3(lhs: u3, rhs: u3, expected: u3) bool { - \\ return expected == lhs -% rhs; - \\} - \\fn sub_i3(lhs: i3, rhs: i3, expected: i3) bool { - \\ return expected == lhs -% rhs; - \\} - \\fn sub_c_int(lhs: c_int, rhs: c_int, expected: c_int) bool { - \\ return expected == lhs -% rhs; - \\} - , ""); - } - - { - var case = ctx.exeFromCompiledC("rem", linux_x64, b); - case.addCompareOutput( - \\fn assert(ok: bool) void { - \\ if (!ok) unreachable; - \\} - \\fn rem(lhs: i32, rhs: i32, expected: i32) bool { - \\ return @rem(lhs, rhs) == expected; - \\} - \\pub export fn main() c_int { - \\ assert(rem(-5, 3, -2)); - \\ assert(rem(5, 3, 2)); - \\ return 0; - \\} - , ""); - } -} diff --git a/test/translate_c.zig b/test/translate_c.zig index a390810830..3b201e2c11 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -764,27 +764,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - // Test case temporarily disabled: - // https://github.com/ziglang/zig/issues/12055 - if (false) { - cases.add("align() attribute", - \\__attribute__ ((aligned(128))) - \\extern char my_array[16]; - \\__attribute__ ((aligned(128))) - \\void my_fn(void) { } - \\void other_fn(void) { - \\ char ARR[16] __attribute__ ((aligned (16))); - \\} - , &[_][]const u8{ - \\pub extern var my_array: [16]u8 align(128); - \\pub export fn my_fn() align(128) void {} - \\pub export fn other_fn() void { - \\ var ARR: [16]u8 align(16) = undefined; - \\ _ = &ARR; - \\} - }); - } - cases.add("linksection() attribute", \\// Use the "segment,section" format to make this test pass when \\// targeting the mach-o binary format |
