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/Sema.zig b/src/Sema.zig index 001d841959..4541d02f66 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -22636,6 +22636,21 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData 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; diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 952d010a14..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 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 index b698203737..6fc42f79f3 100644 --- a/test/cases/compile_errors/@errorCast_with_bad_type.zig +++ b/test/cases/compile_errors/@errorCast_with_bad_type.zig @@ -13,6 +13,11 @@ export fn entry3() void { 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 @@ -21,3 +26,6 @@ export fn entry3() void { // :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