mirror of
https://github.com/ziglang/zig.git
synced 2026-02-16 06:18:32 +00:00
Merge pull request #19461 from Vexu/tests
add tests for stage1 bugs; remove cbe.zig
This commit is contained in:
commit
c808e546a7
@ -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);
|
||||
}
|
||||
|
||||
15
src/Sema.zig
15
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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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'
|
||||
|
||||
13
test/cases/compile_errors/error_union_field_default_init.zig
Normal file
13
test/cases/compile_errors/error_union_field_default_init.zig
Normal file
@ -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'
|
||||
16
test/cases/compile_errors/type_error_union_field_type.zig
Normal file
16
test/cases/compile_errors/type_error_union_field_type.zig
Normal file
@ -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'
|
||||
17
test/cases/translate_c/align() attribute.c
Normal file
17
test/cases/translate_c/align() attribute.c
Normal file
@ -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;
|
||||
// }
|
||||
953
test/cbe.zig
953
test/cbe.zig
@ -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;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user