Merge pull request #14101 from Vexu/stage1

add tests for fixed stage1 bugs
This commit is contained in:
Andrew Kelley
2022-12-29 15:33:45 -05:00
committed by GitHub
20 changed files with 388 additions and 9 deletions

View File

@@ -12075,7 +12075,7 @@ ContainerDeclarations
/ doc_comment? KEYWORD_pub? Decl ContainerDeclarations
/
TestDecl <- KEYWORD_test STRINGLITERALSINGLE? Block
TestDecl <- KEYWORD_test (STRINGLITERALSINGLE / IDENTIFIER)? Block
ComptimeDecl <- KEYWORD_comptime Block
@@ -12089,7 +12089,7 @@ FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpa
VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? (EQUAL Expr)? SEMICOLON
ContainerField
<- doc_comment? KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
<- doc_comment? KEYWORD_comptime? IDENTIFIER (COLON TypeExpr)? ByteAlign? (EQUAL Expr)?
/ doc_comment? KEYWORD_comptime? (IDENTIFIER COLON)? !KEYWORD_fn TypeExpr ByteAlign? (EQUAL Expr)?
# *** Block Level ***
@@ -12360,7 +12360,7 @@ PrefixTypeOp
<- QUESTIONMARK
/ KEYWORD_anyframe MINUSRARROW
/ SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
/ PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
/ PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
/ ArrayTypeStart
SuffixOp

View File

@@ -1604,3 +1604,20 @@ test "std.ArrayList(u0)" {
}
try testing.expectEqual(count, 3);
}
test "std.ArrayList(?u32).popOrNull()" {
const a = testing.allocator;
var list = ArrayList(?u32).init(a);
defer list.deinit();
try list.append(null);
try list.append(1);
try list.append(2);
try testing.expectEqual(list.items.len, 3);
try testing.expect(list.popOrNull().? == @as(u32, 2));
try testing.expect(list.popOrNull().? == @as(u32, 1));
try testing.expect(list.popOrNull().? == null);
try testing.expect(list.popOrNull() == null);
}

View File

@@ -1595,7 +1595,7 @@ const Parser = struct {
/// <- QUESTIONMARK
/// / KEYWORD_anyframe MINUSRARROW
/// / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
/// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
/// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
/// / ArrayTypeStart
/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
/// PtrTypeStart

View File

@@ -3365,7 +3365,7 @@ fn ptrType(
var trailing_count: u32 = 0;
if (ptr_info.ast.sentinel != 0) {
sentinel_ref = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, ptr_info.ast.sentinel);
sentinel_ref = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, ptr_info.ast.sentinel);
trailing_count += 1;
}
if (ptr_info.ast.align_node != 0) {
@@ -3468,7 +3468,7 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.
}
const len = try reachableExpr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, len_node, node);
const elem_type = try typeExpr(gz, scope, extra.elem_type);
const sentinel = try reachableExpr(gz, scope, .{ .rl = .{ .coerced_ty = elem_type } }, extra.sentinel, node);
const sentinel = try reachableExprComptime(gz, scope, .{ .rl = .{ .coerced_ty = elem_type } }, extra.sentinel, node, true);
const result = try gz.addPlNode(.array_type_sentinel, node, Zir.Inst.ArrayTypeSentinel{
.len = len,

View File

@@ -2195,7 +2195,12 @@ pub const Type = extern union {
.Slice => try writer.writeAll("[]"),
}
if (info.@"align" != 0 or info.host_size != 0 or info.vector_index != .none) {
try writer.print("align({d}", .{info.@"align"});
if (info.@"align" != 0) {
try writer.print("align({d}", .{info.@"align"});
} else {
const alignment = info.pointee_type.abiAlignment(mod.getTarget());
try writer.print("align({d}", .{alignment});
}
if (info.bit_offset != 0 or info.host_size != 0) {
try writer.print(":{d}:{d}", .{ info.bit_offset, info.host_size });

View File

@@ -1518,3 +1518,13 @@ test "bitcast packed struct with u0" {
const i = @bitCast(u2, s);
try expect(i == 2);
}
test "optional pointer coerced to optional allowzero pointer" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
var p: ?*u32 = undefined;
var q: ?*allowzero u32 = undefined;
p = @intToPtr(*u32, 4);
q = p;
try expect(@ptrToInt(q.?) == 4);
}

View File

@@ -1547,3 +1547,77 @@ test "comptime function turns function value to function pointer" {
};
comptime try expect(S.foo[0] == &S.Nil);
}
test "container level const and var have unique addresses" {
const S = struct {
x: i32,
y: i32,
const c = @This(){ .x = 1, .y = 1 };
var v: @This() = c;
};
var p = &S.c;
try std.testing.expect(p.x == S.c.x);
S.v.x = 2;
try std.testing.expect(p.x == S.c.x);
}
test "break from block results in type" {
const S = struct {
fn NewType(comptime T: type) type {
const Padded = blk: {
if (@sizeOf(T) <= @sizeOf(usize)) break :blk void;
break :blk T;
};
return Padded;
}
};
const T = S.NewType(usize);
try expect(T == void);
}
test "struct in comptime false branch is not evaluated" {
const S = struct {
const comptime_const = 2;
fn some(comptime V: type) type {
return switch (comptime_const) {
3 => struct { a: V.foo },
2 => V,
else => unreachable,
};
}
};
try expect(S.some(u32) == u32);
}
test "result of nested switch assigned to variable" {
var zds: u32 = 0;
zds = switch (zds) {
0 => switch (zds) {
0...0 => 1234,
1...1 => zds,
2 => zds,
else => return,
},
else => zds,
};
try expect(zds == 1234);
}
test "inline for loop of functions returning error unions" {
const T1 = struct {
fn v() error{}!usize {
return 1;
}
};
const T2 = struct {
fn v() error{Error}!usize {
return 2;
}
};
var a: usize = 0;
inline for (.{ T1, T2 }) |T| {
a += try T.v();
}
try expect(a == 3);
}

View File

@@ -227,3 +227,25 @@ test "else continue outer for" {
} else continue;
}
}
test "for loop with else branch" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
{
var x = [_]u32{ 1, 2 };
const q = for (x) |y| {
if ((y & 1) != 0) continue;
break y * 2;
} else @as(u32, 1);
try expect(q == 4);
}
{
var x = [_]u32{ 1, 2 };
const q = for (x) |y| {
if ((y & 1) != 0) continue;
break y * 2;
} else @panic("");
try expect(q == 4);
}
}

View File

@@ -448,3 +448,46 @@ test "Optional slice size is optimized" {
a = "hello";
try expectEqualStrings(a.?, "hello");
}
test "peer type resolution in nested if expressions" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const Thing = struct { n: i32 };
var a = false;
var b = false;
var result1 = if (a)
Thing{ .n = 1 }
else
null;
try expect(result1 == null);
try expect(@TypeOf(result1) == ?Thing);
var result2 = if (a)
Thing{ .n = 0 }
else if (b)
Thing{ .n = 1 }
else
null;
try expect(result2 == null);
try expect(@TypeOf(result2) == ?Thing);
}
test "cast slice to const slice nested in error union and optional" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
const S = struct {
fn inner() !?[]u8 {
return error.Foo;
}
fn outer() !?[]const u8 {
return inner();
}
};
try std.testing.expectError(error.Foo, S.outer());
}

View File

@@ -567,3 +567,24 @@ test "packed struct passed to callconv(.C) function" {
}, 5, 4, 3, 2, 1);
try expect(result);
}
test "overaligned pointer to packed struct" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const S = packed struct { a: u32, b: u32 };
var foo: S align(4) = .{ .a = 123, .b = 456 };
const ptr: *align(4) S = &foo;
switch (comptime builtin.cpu.arch.endian()) {
.Little => {
const ptr_to_b: *u32 = &ptr.b;
try expect(ptr_to_b.* == 456);
},
.Big => {
// Byte aligned packed struct field pointers have not been implemented yet.
const ptr_to_a: *align(4:0:8) u32 = &ptr.a;
try expect(ptr_to_a.* == 123);
},
}
}

View File

@@ -270,3 +270,15 @@ test "comptime @ptrCast a subset of an array, then write through it" {
std.mem.copy(u8, buff[4..], "abcdef");
}
}
test "@ptrCast undefined value at comptime" {
const S = struct {
fn transmute(comptime T: type, comptime U: type, value: T) U {
return @ptrCast(*const U, &value).*;
}
};
comptime {
var x = S.transmute([]u8, i32, undefined);
_ = x;
}
}

View File

@@ -706,3 +706,34 @@ test "global slice field access" {
S.slice.len -= 2;
try expectEqualStrings("trin", S.slice);
}
test "slice of void" {
var n: usize = 10;
var arr: [12]void = undefined;
const slice = @as([]void, &arr)[0..n];
try expect(slice.len == n);
}
test "slice with dereferenced value" {
var a: usize = 0;
var idx: *usize = &a;
_ = blk: {
var array = [_]u8{};
break :blk array[idx.*..];
};
const res = blk: {
var array = [_]u8{};
break :blk array[idx.*..];
};
try expect(res.len == 0);
}
test "empty slice ptr is non null" {
if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64 and (builtin.os.tag == .macos or builtin.os.tag == .windows)) return error.SkipZigTest; // TODO
const empty_slice: []u8 = &[_]u8{};
const p: [*]u8 = empty_slice.ptr + 0;
const t = @ptrCast([*]i8, p);
try expect(@ptrToInt(t) == @ptrToInt(empty_slice.ptr));
}

View File

@@ -1458,3 +1458,40 @@ test "struct has only one reference" {
try expectEqual(@sizeOf(struct { x: u16 }), S.optionalComptimeIntParam(@sizeOf(struct { x: u16 })));
try expectEqual(@sizeOf(struct { x: u32 }), S.errorUnionComptimeIntParam(@sizeOf(struct { x: u32 })));
}
test "no dependency loop on pointer to optional struct" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
const S = struct {
const A = struct { b: B };
const B = struct { a: *?A };
};
var a1: ?S.A = null;
var a2: ?S.A = .{ .b = .{ .a = &a1 } };
a1 = .{ .b = .{ .a = &a2 } };
try expect(a1.?.b.a == &a2);
try expect(a2.?.b.a == &a1);
}
test "discarded struct initialization works as expected" {
const S = struct { a: u32 };
_ = S{ .a = 1 };
}
test "function pointer in struct returns the struct" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const A = struct {
const A = @This();
f: *const fn () A,
fn f() A {
return .{ .f = f };
}
};
var a = A.f();
try expect(a.f == A.f);
}

View File

@@ -2,6 +2,7 @@ const builtin = @import("builtin");
const std = @import("std");
const testing = std.testing;
const expect = testing.expect;
const expectEqualStrings = std.testing.expectEqualStrings;
test "tuple concatenation" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
@@ -340,3 +341,28 @@ test "tuple type with void field and a runtime field" {
var t: T = .{ 5, {} };
try expect(t[0] == 5);
}
test "branching inside tuple literal" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const S = struct {
fn foo(a: anytype) !void {
try expect(a[0] == 1234);
}
};
var a = false;
try S.foo(.{if (a) @as(u32, 5678) else @as(u32, 1234)});
}
test "tuple initialized with a runtime known value" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const E = union(enum) { e: []const u8 };
const W = union(enum) { w: E };
var e = E{ .e = "test" };
const w = .{W{ .w = e }};
try expectEqualStrings(w[0].w.e, "test");
}

View File

@@ -1471,3 +1471,34 @@ test "union int tag type is properly managed" {
};
try expect(@sizeOf(Bar) + 1 == 3);
}
test "no dependency loop when function pointer in union returns the union" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const U = union(enum) {
const U = @This();
a: u8,
b: *const fn (x: U) void,
c: *const fn (x: U) U,
d: *const fn (x: u8) U,
fn foo(x: u8) U {
return .{ .a = x };
}
};
var b: U = .{ .d = U.foo };
try expect(b.d(2).a == 2);
}
test "union reassignment can use previous value" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const U = union {
a: u32,
b: u32,
};
var a = U{ .a = 32 };
a = U{ .b = a.a };
try expect(a.b == 32);
}

View File

@@ -18,7 +18,7 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); }
// backend=stage2
// target=native
//
// :8:16: error: expected type '*const u3', found '*align(0:3:1) const u3'
// :8:16: error: expected type '*const u3', found '*align(1:3:1) const u3'
// :8:16: note: pointer host size '1' cannot cast into pointer host size '0'
// :8:16: note: pointer bit offset '3' cannot cast into pointer bit offset '0'
// :11:11: note: parameter type declared here

View File

@@ -6,6 +6,27 @@ export fn foo() void {
}
fn bar() void { }
export fn baz() void {
comptime var idx: u32 = 0;
while (idx < 1) {
const not_null: ?u32 = 1;
_ = not_null orelse return;
idx += 1;
}
}
export fn qux() void {
comptime var i = 0;
while (i < 3) : (i += 1) {
const T = switch (i) {
0 => f32,
1 => i8,
2 => bool,
else => unreachable,
};
_ = T;
}
}
// error
// backend=stage2
@@ -13,3 +34,7 @@ fn bar() void { }
//
// :3:24: error: cannot store to comptime variable in non-inline loop
// :3:5: note: non-inline loop here
// :14:13: error: cannot store to comptime variable in non-inline loop
// :11:5: note: non-inline loop here
// :20:24: error: cannot store to comptime variable in non-inline loop
// :20:5: note: non-inline loop here

View File

@@ -24,4 +24,4 @@ export fn entry() void {
// backend=stage2
// target=native
//
// :14:17: error: incompatible types: '*align(0:0:1) u2' and '*align(2:8:2) u2'
// :14:17: error: incompatible types: '*align(1:0:1) u2' and '*align(2:8:2) u2'

View File

@@ -18,6 +18,10 @@ export fn qux() void {
var ptr = &S{.x=1,.y=2};
ptr.x = 2;
}
export fn quux() void {
var x = &@returnAddress();
x.* = 6;
}
// error
// backend=stage2
@@ -27,3 +31,4 @@ export fn qux() void {
// :7:8: error: cannot assign to constant
// :11:8: error: cannot assign to constant
// :19:8: error: cannot assign to constant
// :23:6: error: cannot assign to constant

View File

@@ -0,0 +1,20 @@
fn A(comptime T: type) type {
return struct { a: T };
}
fn B(comptime T: type) type {
return struct { b: T };
}
fn foo() A(u32) {
return B(u32){ .b = 1 };
}
export fn entry() void {
_ = foo();
}
// error
// backend=stage2
// target=native
//
// :8:18: error: expected type 'tmp.A(u32)', found 'tmp.B(u32)'
// :5:12: note: struct declared here
// :2:12: note: struct declared here