From ebfe723f3cdbb40d2f2280e223b710418abde777 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 12:20:24 +0300 Subject: [PATCH 1/8] stage2: implement rest of simple pointer types --- src-self-hosted/Module.zig | 26 +++-- src-self-hosted/astgen.zig | 27 +++++- src-self-hosted/codegen.zig | 2 +- src-self-hosted/type.zig | 181 ++++++++++++++++++++++++++++++----- src-self-hosted/zir.zig | 19 +++- src-self-hosted/zir_sema.zig | 26 +++-- 6 files changed, 230 insertions(+), 51 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index d08e7f5746..9b27f38fbe 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -2429,7 +2429,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn if (decl_tv.val.tag() == .variable) { return self.analyzeVarRef(scope, src, decl_tv); } - const ty = try self.singlePtrType(scope, src, false, decl_tv.ty); + const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One); const val_payload = try scope.arena().create(Value.Payload.DeclRef); val_payload.* = .{ .decl = decl }; @@ -2442,7 +2442,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { const variable = tv.val.cast(Value.Payload.Variable).?.variable; - const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); + const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty, .One); if (!variable.is_mutable and !variable.is_extern) { const val_payload = try scope.arena().create(Value.Payload.RefVal); val_payload.* = .{ .val = variable.init }; @@ -2766,7 +2766,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst // T to ?T if (dest_type.zigTypeTag() == .Optional) { - var buf: Type.Payload.Pointer = undefined; + var buf: Type.Payload.PointerSimple = undefined; const child_type = dest_type.optionalChild(&buf); if (child_type.eql(inst.ty)) { return self.wrapOptional(scope, dest_type, inst); @@ -3145,10 +3145,20 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: return Value.initPayload(val_payload); } -pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) Allocator.Error!Type { - const type_payload = try scope.arena().create(Type.Payload.Pointer); +pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { + // TODO stage1 type inference bug + const T = Type.Tag; + + const type_payload = try scope.arena().create(Type.Payload.PointerSimple); type_payload.* = .{ - .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer }, + .base = .{ + .tag = switch (size) { + .One => if (mutable) .single_mut_pointer else T.many_const_pointer, + .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, + .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, + else => unreachable, + }, + }, .pointee_type = elem_ty, }; return Type.initPayload(&type_payload.base); @@ -3157,7 +3167,7 @@ pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, el pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type { return Type.initPayload(switch (child_type.tag()) { .single_const_pointer => blk: { - const payload = try scope.arena().create(Type.Payload.Pointer); + const payload = try scope.arena().create(Type.Payload.PointerSimple); payload.* = .{ .base = .{ .tag = .optional_single_const_pointer }, .pointee_type = child_type.elemType(), @@ -3165,7 +3175,7 @@ pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Er break :blk &payload.base; }, .single_mut_pointer => blk: { - const payload = try scope.arena().create(Type.Payload.Pointer); + const payload = try scope.arena().create(Type.Payload.PointerSimple); payload.* = .{ .base = .{ .tag = .optional_single_mut_pointer }, .pointee_type = child_type.elemType(), diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index 9f8afa6225..bb42b746ad 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -577,6 +577,17 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir .val = Value.initTag(.type_type), }); + const size: std.builtin.TypeInfo.Pointer.Size = switch (tree.token_ids[node.op_token]) { + .Asterisk, .AsteriskAsterisk => .One, + // TODO stage1 type inference bug + .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { + .Identifier => .C, + .RBracket => .Many, + else => unreachable, + }), + else => unreachable, + }; + const simple = node.ptr_info.allowzero_token == null and node.ptr_info.align_info == null and node.ptr_info.volatile_token == null and @@ -584,13 +595,19 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir if (simple) { const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); - return addZIRUnOp(mod, scope, src, if (node.ptr_info.const_token == null) - .single_mut_ptr_type - else - .single_const_ptr_type, child_type); + const mutable = node.ptr_info.const_token == null; + // TODO stage1 type inference bug + const T = zir.Inst.Tag; + return addZIRUnOp(mod, scope, src, switch (size) { + .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, + .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, + .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, + else => unreachable, + }, child_type); } var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{}; + kw_args.size = size; kw_args.@"allowzero" = node.ptr_info.allowzero_token != null; if (node.ptr_info.align_info) |some| { kw_args.@"align" = try expr(mod, scope, .none, some.node); @@ -1271,7 +1288,7 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr i += 1; } const slice = tree.tokenSlice(line); - mem.copy(u8, bytes[i..], slice[2..slice.len - 1]); + mem.copy(u8, bytes[i..], slice[2 .. slice.len - 1]); i += slice.len - 3; } diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 1bc76f6b05..cc5c51159c 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -2060,7 +2060,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { if (typed_value.val.isNull()) return MCValue{ .immediate = 0 }; - var buf: Type.Payload.Pointer = undefined; + var buf: Type.Payload.PointerSimple = undefined; return self.genTypedValue(src, .{ .ty = typed_value.ty.optionalChild(&buf), .val = typed_value.val, diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index c2762e1f8a..233e479297 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -66,10 +66,15 @@ pub const Type = extern union { .function => return .Fn, .array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array, - .single_const_pointer => return .Pointer, - .single_mut_pointer => return .Pointer, - .single_const_pointer_to_comptime_int => return .Pointer, - .const_slice_u8 => return .Pointer, + .single_const_pointer_to_comptime_int, + .const_slice_u8, + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + => return .Pointer, .optional, .optional_single_const_pointer, @@ -108,13 +113,17 @@ pub const Type = extern union { return @fieldParentPtr(T, "base", self.ptr_otherwise); } - pub fn castPointer(self: Type) ?*Payload.Pointer { + pub fn castPointer(self: Type) ?*Payload.PointerSimple { return switch (self.tag()) { .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_const_pointer, .optional_single_mut_pointer, - => @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise), + => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise), else => null, }; } @@ -198,8 +207,8 @@ pub const Type = extern union { return true; }, .Optional => { - var buf_a: Payload.Pointer = undefined; - var buf_b: Payload.Pointer = undefined; + var buf_a: Payload.PointerSimple = undefined; + var buf_b: Payload.PointerSimple = undefined; return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b)); }, .Float, @@ -263,7 +272,7 @@ pub const Type = extern union { } }, .Optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; std.hash.autoHash(&hasher, self.optionalChild(&buf).hash()); }, .Float, @@ -374,9 +383,13 @@ pub const Type = extern union { .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"), .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_mut_pointer, .optional_single_const_pointer, - => return self.copyPayloadSingleField(allocator, Payload.Pointer, "pointee_type"), + => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), } } @@ -482,17 +495,41 @@ pub const Type = extern union { continue; }, .single_const_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("*const "); ty = payload.pointee_type; continue; }, .single_mut_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("*"); ty = payload.pointee_type; continue; }, + .many_const_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*]const "); + ty = payload.pointee_type; + continue; + }, + .many_mut_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*]"); + ty = payload.pointee_type; + continue; + }, + .c_const_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*c]const "); + ty = payload.pointee_type; + continue; + }, + .c_mut_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*c]"); + ty = payload.pointee_type; + continue; + }, .int_signed => { const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise); return out_stream.print("i{}", .{payload.bits}); @@ -508,13 +545,13 @@ pub const Type = extern union { continue; }, .optional_single_const_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("?*const "); ty = payload.pointee_type; continue; }, .optional_single_mut_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("?*"); ty = payload.pointee_type; continue; @@ -619,6 +656,10 @@ pub const Type = extern union { .array_sentinel => self.elemType().hasCodeGenBits(), .single_const_pointer => self.elemType().hasCodeGenBits(), .single_mut_pointer => self.elemType().hasCodeGenBits(), + .many_const_pointer => self.elemType().hasCodeGenBits(), + .many_mut_pointer => self.elemType().hasCodeGenBits(), + .c_const_pointer => self.elemType().hasCodeGenBits(), + .c_mut_pointer => self.elemType().hasCodeGenBits(), .int_signed => self.cast(Payload.IntSigned).?.bits == 0, .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, @@ -669,6 +710,10 @@ pub const Type = extern union { .const_slice_u8, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_const_pointer, .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), @@ -704,7 +749,7 @@ pub const Type = extern union { }, .optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; const child_type = self.optionalChild(&buf); if (!child_type.hasCodeGenBits()) return 1; @@ -772,6 +817,10 @@ pub const Type = extern union { .const_slice_u8, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_const_pointer, .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), @@ -805,7 +854,7 @@ pub const Type = extern union { }, .optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; const child_type = self.optionalChild(&buf); if (!child_type.hasCodeGenBits()) return 1; @@ -872,6 +921,10 @@ pub const Type = extern union { .optional_single_mut_pointer, .optional_single_const_pointer, .enum_literal, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, => false, .single_const_pointer, @@ -922,6 +975,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .fn_noreturn_no_args, .fn_void_no_args, @@ -987,6 +1044,8 @@ pub const Type = extern union { .int_unsigned, .int_signed, .single_mut_pointer, + .many_mut_pointer, + .c_mut_pointer, .optional, .optional_single_mut_pointer, .optional_single_const_pointer, @@ -994,6 +1053,8 @@ pub const Type = extern union { => false, .single_const_pointer, + .many_const_pointer, + .c_const_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, => true, @@ -1048,6 +1109,10 @@ pub const Type = extern union { .int_signed, .single_mut_pointer, .single_const_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1063,7 +1128,7 @@ pub const Type = extern union { switch (self.tag()) { .optional_single_const_pointer, .optional_single_mut_pointer => return true, .optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; const child_type = self.optionalChild(&buf); // optionals of zero sized pointers behave like bools if (!child_type.hasCodeGenBits()) return false; @@ -1101,7 +1166,7 @@ pub const Type = extern union { => return false, .Optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; return ty.optionalChild(&buf).isValidVarType(is_extern); }, .Pointer, .Array => ty = ty.elemType(), @@ -1166,13 +1231,17 @@ pub const Type = extern union { .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type, .single_const_pointer => self.castPointer().?.pointee_type, .single_mut_pointer => self.castPointer().?.pointee_type, + .many_const_pointer => self.castPointer().?.pointee_type, + .many_mut_pointer => self.castPointer().?.pointee_type, + .c_const_pointer => self.castPointer().?.pointee_type, + .c_mut_pointer => self.castPointer().?.pointee_type, .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), }; } /// Asserts that the type is an optional. - pub fn optionalChild(self: Type, buf: *Payload.Pointer) Type { + pub fn optionalChild(self: Type, buf: *Payload.PointerSimple) Type { return switch (self.tag()) { .optional => self.cast(Payload.Optional).?.child_type, .optional_single_mut_pointer => { @@ -1199,7 +1268,7 @@ pub const Type = extern union { return switch (self.tag()) { .optional => self.cast(Payload.Optional).?.child_type, .optional_single_mut_pointer, .optional_single_const_pointer => { - const payload = try allocator.create(Payload.Pointer); + const payload = try allocator.create(Payload.PointerSimple); payload.* = .{ .base = .{ .tag = if (self.tag() == .optional_single_const_pointer) @@ -1258,6 +1327,10 @@ pub const Type = extern union { .function, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1318,6 +1391,10 @@ pub const Type = extern union { .function, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1368,6 +1445,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1429,6 +1510,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_signed, @@ -1490,6 +1575,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1549,6 +1638,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1637,6 +1730,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1701,6 +1798,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1764,6 +1865,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1827,6 +1932,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1887,6 +1996,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1947,6 +2060,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2027,6 +2144,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -2109,7 +2230,13 @@ pub const Type = extern union { ty = ty.elemType(); continue; }, - .single_const_pointer, .single_mut_pointer => { + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .single_const_pointer, + .single_mut_pointer, + => { const ptr = ty.castPointer().?; ty = ptr.pointee_type; continue; @@ -2167,11 +2294,17 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, .optional, .optional_single_mut_pointer, .optional_single_const_pointer, .enum_literal, => return false, + + .c_const_pointer, + .c_mut_pointer, + => return true, }; } @@ -2231,6 +2364,10 @@ pub const Type = extern union { array_sentinel, single_const_pointer, single_mut_pointer, + many_const_pointer, + many_mut_pointer, + c_const_pointer, + c_mut_pointer, int_signed, int_unsigned, function, @@ -2272,7 +2409,7 @@ pub const Type = extern union { elem_type: Type, }; - pub const Pointer = struct { + pub const PointerSimple = struct { base: Payload, pointee_type: Type, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 552e90956b..62c0c73f3f 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -198,6 +198,14 @@ pub const Inst = struct { single_const_ptr_type, /// Create a mutable pointer type based on the element type. `*T` single_mut_ptr_type, + /// Create a const pointer type based on the element type. `[*]const T` + many_const_ptr_type, + /// Create a mutable pointer type based on the element type. `[*]T` + many_mut_ptr_type, + /// Create a const pointer type based on the element type. `[*c]const T` + c_const_ptr_type, + /// Create a mutable pointer type based on the element type. `[*c]T` + c_mut_ptr_type, /// Create a pointer type with attributes ptr_type, /// Write a value to a pointer. For loading, see `deref`. @@ -262,6 +270,10 @@ pub const Inst = struct { .typeof, .single_const_ptr_type, .single_mut_ptr_type, + .many_const_ptr_type, + .many_mut_ptr_type, + .c_const_ptr_type, + .c_mut_ptr_type, .optional_type, .unwrap_optional_safe, .unwrap_optional_unsafe, @@ -400,6 +412,10 @@ pub const Inst = struct { .shr, .single_const_ptr_type, .single_mut_ptr_type, + .many_const_ptr_type, + .many_mut_ptr_type, + .c_const_ptr_type, + .c_mut_ptr_type, .store, .str, .sub, @@ -859,6 +875,7 @@ pub const Inst = struct { @"const": bool = true, @"volatile": bool = false, sentinel: ?*Inst = null, + size: std.builtin.TypeInfo.Pointer.Size = .One, }, }; @@ -2443,7 +2460,7 @@ const EmitZIR = struct { } }, .Optional => { - var buf: Type.Payload.Pointer = undefined; + var buf: Type.Payload.PointerSimple = undefined; const inst = try self.arena.allocator.create(Inst.UnOp); inst.* = .{ .base = .{ diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index cb1ed08d6d..0e331d1979 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -51,8 +51,12 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?), .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?), .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?), - .single_const_ptr_type => return analyzeInstSingleConstPtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?), - .single_mut_ptr_type => return analyzeInstSingleMutPtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?), + .single_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One), + .single_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One), + .many_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many), + .many_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many), + .c_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C), + .c_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C), .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?), .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?), .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?), @@ -324,7 +328,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { const operand = try resolveInst(mod, scope, inst.positionals.operand); - const ptr_type = try mod.singlePtrType(scope, inst.base.src, false, operand.ty); + const ptr_type = try mod.simplePtrType(scope, inst.base.src, operand.ty, false, .One); if (operand.value()) |val| { const ref_payload = try scope.arena().create(Value.Payload.RefVal); @@ -369,7 +373,7 @@ fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerErro if (!var_type.isValidVarType(false)) { return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); } - const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type); + const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One); const b = try mod.requireRuntimeBlock(scope, inst.base.src); return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); } @@ -723,7 +727,7 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp } const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena()); - const child_pointer = try mod.singlePtrType(scope, unwrap.base.src, operand.ty.isConstPtr(), child_type); + const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One); if (operand.value()) |val| { if (val.isNull()) { @@ -940,7 +944,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne // required a larger index. const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64)); - const type_payload = try scope.arena().create(Type.Payload.Pointer); + const type_payload = try scope.arena().create(Type.Payload.PointerSimple); type_payload.* = .{ .base = .{ .tag = .single_const_pointer }, .pointee_type = array_ptr.ty.elemType().elemType(), @@ -1311,15 +1315,9 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr return decl; } -fn analyzeInstSingleConstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { +fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst { const elem_type = try resolveType(mod, scope, inst.positionals.operand); - const ty = try mod.singlePtrType(scope, inst.base.src, false, elem_type); - return mod.constType(scope, inst.base.src, ty); -} - -fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { - const elem_type = try resolveType(mod, scope, inst.positionals.operand); - const ty = try mod.singlePtrType(scope, inst.base.src, true, elem_type); + const ty = try mod.simplePtrType(scope, inst.base.src, elem_type, mutable, size); return mod.constType(scope, inst.base.src, ty); } From 95682484503f031efefb2c085cdd4d0b64cf8795 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 13:52:18 +0300 Subject: [PATCH 2/8] stage2: complex pointer types --- src-self-hosted/Module.zig | 34 +++++++++- src-self-hosted/astgen.zig | 5 +- src-self-hosted/type.zig | 126 +++++++++++++++++++++++++++++++++-- src-self-hosted/zir.zig | 2 +- src-self-hosted/zir_sema.zig | 47 ++++++++++++- 5 files changed, 202 insertions(+), 12 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 9b27f38fbe..2dd64c64bc 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -3153,7 +3153,7 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu type_payload.* = .{ .base = .{ .tag = switch (size) { - .One => if (mutable) .single_mut_pointer else T.many_const_pointer, + .One => if (mutable) T.single_mut_pointer else T.single_const_pointer, .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, else => unreachable, @@ -3164,6 +3164,38 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu return Type.initPayload(&type_payload.base); } +pub fn ptrType( + self: *Module, + scope: *Scope, + src: usize, + elem_ty: Type, + sentinel: ?Value, + @"align": u32, + bit_offset: u16, + host_size: u16, + mutable: bool, + @"allowzero": bool, + @"volatile": bool, + size: std.builtin.TypeInfo.Pointer.Size, +) Allocator.Error!Type { + assert(host_size == 0 or bit_offset < host_size * 8); + + // TODO check if type can be represented by simplePtrType + const type_payload = try scope.arena().create(Type.Payload.Pointer); + type_payload.* = .{ + .pointee_type = elem_ty, + .sentinel = sentinel, + .@"align" = @"align", + .bit_offset = bit_offset, + .host_size = host_size, + .@"allowzero" = @"allowzero", + .mutable = mutable, + .@"volatile" = @"volatile", + .size = size, + }; + return Type.initPayload(&type_payload.base); +} + pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type { return Type.initPayload(switch (child_type.tag()) { .single_const_pointer => blk: { diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index bb42b746ad..832e6848b3 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -582,8 +582,7 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir // TODO stage1 type inference bug .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { .Identifier => .C, - .RBracket => .Many, - else => unreachable, + else => .Many, }), else => unreachable, }; @@ -616,7 +615,7 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end); } } - kw_args.@"const" = node.ptr_info.const_token != null; + kw_args.mutable = node.ptr_info.const_token == null; kw_args.@"volatile" = node.ptr_info.volatile_token != null; if (node.ptr_info.sentinel) |some| { kw_args.sentinel = try expr(mod, scope, .none, some); diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 233e479297..2c326b9308 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -74,6 +74,7 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .pointer, => return .Pointer, .optional, @@ -390,6 +391,25 @@ pub const Type = extern union { .optional_single_mut_pointer, .optional_single_const_pointer, => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + const new_payload = try allocator.create(Payload.Pointer); + new_payload.* = .{ + .base = payload.base, + + .pointee_type = try payload.pointee_type.copy(allocator), + .sentinel = if (payload.sentinel) |some| try some.copy(allocator) else null, + .@"align" = payload.@"align", + .bit_offset = payload.bit_offset, + .host_size = payload.host_size, + .@"allowzero" = payload.@"allowzero", + .mutable = payload.mutable, + .@"volatile" = payload.@"volatile", + .size = payload.size, + }; + return Type{ .ptr_otherwise = &new_payload.base }; + }, } } @@ -556,6 +576,34 @@ pub const Type = extern union { ty = payload.pointee_type; continue; }, + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + if (payload.sentinel) |some| switch (payload.size) { + .One, .C => unreachable, + .Many => try out_stream.writeAll("[*:{}]"), + .Slice => try out_stream.writeAll("[:{}]"), + } else switch (payload.size) { + .One => try out_stream.writeAll("*"), + .Many => try out_stream.writeAll("[*]"), + .C => try out_stream.writeAll("[*c]"), + .Slice => try out_stream.writeAll("[]"), + } + if (payload.@"align" != 0) { + try out_stream.print("align({}", .{payload.@"align"}); + + if (payload.bit_offset != 0) { + try out_stream.print(":{}:{}", .{ payload.bit_offset, payload.host_size }); + } + try out_stream.writeAll(") "); + } + if (!payload.mutable) try out_stream.writeAll("const "); + if (payload.@"volatile") try out_stream.writeAll("volatile "); + if (payload.@"allowzero") try out_stream.writeAll("allowzero "); + + ty = payload.pointee_type; + continue; + }, } unreachable; } @@ -660,6 +708,7 @@ pub const Type = extern union { .many_mut_pointer => self.elemType().hasCodeGenBits(), .c_const_pointer => self.elemType().hasCodeGenBits(), .c_mut_pointer => self.elemType().hasCodeGenBits(), + .pointer => self.elemType().hasCodeGenBits(), .int_signed => self.cast(Payload.IntSigned).?.bits == 0, .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, @@ -718,6 +767,13 @@ pub const Type = extern union { .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + + if (payload.@"align" != 0) return payload.@"align"; + return @divExact(target.cpu.arch.ptrBitWidth(), 8); + }, + .c_short => return @divExact(CType.short.sizeInBits(target), 8), .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), .c_int => return @divExact(CType.int.sizeInBits(target), 8), @@ -789,6 +845,7 @@ pub const Type = extern union { .@"null" => unreachable, .@"undefined" => unreachable, .enum_literal => unreachable, + .single_const_pointer_to_comptime_int => unreachable, .u8, .i8, @@ -812,18 +869,28 @@ pub const Type = extern union { .i64, .u64 => return 8, .isize, - .usize, - .single_const_pointer_to_comptime_int, - .const_slice_u8, + .usize + => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .const_slice_u8 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, + + .optional_single_const_pointer, + .optional_single_mut_pointer, + => { + if (self.elemType().hasCodeGenBits()) return 1; + return @divExact(target.cpu.arch.ptrBitWidth(), 8); + }, + .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, - .optional_single_const_pointer, - .optional_single_mut_pointer, - => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .pointer, + => { + if (self.elemType().hasCodeGenBits()) return 0; + return @divExact(target.cpu.arch.ptrBitWidth(), 8); + }, .c_short => return @divExact(CType.short.sizeInBits(target), 8), .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), @@ -931,6 +998,8 @@ pub const Type = extern union { .single_mut_pointer, .single_const_pointer_to_comptime_int, => true, + + .pointer => self.cast(Payload.Pointer).?.size == .One, }; } @@ -994,6 +1063,8 @@ pub const Type = extern union { => false, .const_slice_u8 => true, + + .pointer => self.cast(Payload.Pointer).?.size == .Slice, }; } @@ -1058,6 +1129,8 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int, .const_slice_u8, => true, + + .pointer => !self.cast(Payload.Pointer).?.mutable, }; } @@ -1120,6 +1193,11 @@ pub const Type = extern union { .optional_single_const_pointer, .enum_literal, => false, + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + return payload.@"volatile"; + }, }; } @@ -1237,6 +1315,7 @@ pub const Type = extern union { .c_mut_pointer => self.castPointer().?.pointee_type, .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), + .pointer => self.cast(Payload.Pointer).?.pointee_type, }; } @@ -1325,6 +1404,7 @@ pub const Type = extern union { .fn_naked_noreturn_no_args, .fn_ccc_void_no_args, .function, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1389,6 +1469,7 @@ pub const Type = extern union { .fn_naked_noreturn_no_args, .fn_ccc_void_no_args, .function, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1443,6 +1524,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1508,6 +1590,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1573,6 +1656,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1636,6 +1720,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1728,6 +1813,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1796,6 +1882,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1863,6 +1950,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1930,6 +2018,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1994,6 +2083,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2058,6 +2148,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2142,6 +2233,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2241,6 +2333,10 @@ pub const Type = extern union { ty = ptr.pointee_type; continue; }, + .pointer => { + ty = ty.cast(Payload.Pointer).?.pointee_type; + continue; + }, }; } @@ -2305,6 +2401,8 @@ pub const Type = extern union { .c_const_pointer, .c_mut_pointer, => return true, + + .pointer => self.cast(Payload.Pointer).?.size == .C, }; } @@ -2362,6 +2460,7 @@ pub const Type = extern union { array_u8_sentinel_0, array, array_sentinel, + pointer, single_const_pointer, single_mut_pointer, many_const_pointer, @@ -2440,6 +2539,21 @@ pub const Type = extern union { child_type: Type, }; + + pub const Pointer = struct { + base: Payload = .{ .tag = .pointer }, + + pointee_type: Type, + sentinel: ?Value, + /// If zero use pointee_type.AbiAlign() + @"align": u32, + bit_offset: u16, + host_size: u16, + @"allowzero": bool, + mutable: bool, + @"volatile": bool, + size: std.builtin.TypeInfo.Pointer.Size, + }; }; }; diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 62c0c73f3f..db0ec242cc 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -872,7 +872,7 @@ pub const Inst = struct { @"align": ?*Inst = null, align_bit_start: ?*Inst = null, align_bit_end: ?*Inst = null, - @"const": bool = true, + mutable: bool = true, @"volatile": bool = false, sentinel: ?*Inst = null, size: std.builtin.TypeInfo.Pointer.Size = .One, diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 0e331d1979..ea3b85b29a 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -271,6 +271,14 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type { return val.toType(); } +fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 { + const new_inst = try resolveInst(mod, scope, old_inst); + const coerced = try mod.coerce(scope, dest_type, new_inst); + const val = try mod.resolveConstValue(scope, coerced); + + return val.toUnsignedInt(); +} + pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue { const new_inst = try resolveInst(mod, scope, old_inst); const val = try mod.resolveConstValue(scope, new_inst); @@ -1322,5 +1330,42 @@ fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, m } fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst { - return mod.fail(scope, inst.base.src, "TODO implement ptr_type", .{}); + // TODO lazy values + const @"align" = if (inst.kw_args.@"align") |some| + @truncate(u32, try resolveInt(mod, scope, some, Type.initTag(.u32))) + else + 0; + const bit_offset = if (inst.kw_args.align_bit_start) |some| + @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16))) + else + 0; + const host_size = if (inst.kw_args.align_bit_end) |some| + @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16))) + else + 0; + + if (host_size != 0 and bit_offset >= host_size * 8) + return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{}); + + const sentinel = if (inst.kw_args.sentinel) |some| + (try resolveInstConst(mod, scope, some)).val + else + null; + + const elem_type = try resolveType(mod, scope, inst.positionals.child_type); + + const ty = try mod.ptrType( + scope, + inst.base.src, + elem_type, + sentinel, + @"align", + bit_offset, + host_size, + inst.kw_args.mutable, + inst.kw_args.@"allowzero", + inst.kw_args.@"volatile", + inst.kw_args.size, + ); + return mod.constType(scope, inst.base.src, ty); } From d312d64c9aa058293d69b2bf97c51f4caa7a2d9d Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 16:37:28 +0300 Subject: [PATCH 3/8] stage2: slice types --- src-self-hosted/Module.zig | 5 +- src-self-hosted/astgen.zig | 50 +++++++++++-------- src-self-hosted/type.zig | 97 +++++++++++++++++++++++++++++------- src-self-hosted/zir.zig | 20 +++++--- src-self-hosted/zir_sema.zig | 2 + 5 files changed, 127 insertions(+), 47 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 2dd64c64bc..4893aaba7a 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -3146,6 +3146,9 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: } pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { + if (size == .Slice and elem_ty.eql(Type.initTag(.u8))) { + return Type.initTag(.const_slice_u8); + } // TODO stage1 type inference bug const T = Type.Tag; @@ -3156,7 +3159,7 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu .One => if (mutable) T.single_mut_pointer else T.single_const_pointer, .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, - else => unreachable, + .Slice => if (mutable) T.mut_slice else T.const_slice, }, }, .pointee_type = elem_ty, diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index 832e6848b3..8276b191cb 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -262,6 +262,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)), .MultilineStringLiteral => return rlWrap(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)), .CharLiteral => return rlWrap(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)), + .SliceType => return rlWrap(mod, scope, rl, try sliceType(mod, scope, node.castTag(.SliceType).?)), .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), @@ -275,7 +276,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}), .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), - .SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}), .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}), .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}), .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}), @@ -569,15 +569,16 @@ fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) Inn return addZIRUnOp(mod, scope, src, .optional_type, operand); } +fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.SliceType) InnerError!*zir.Inst { + const tree = scope.tree(); + const src = tree.token_locs[node.op_token].start; + return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, .Slice); +} + fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.op_token].start; - const meta_type = try addZIRInstConst(mod, scope, src, .{ - .ty = Type.initTag(.type), - .val = Value.initTag(.type_type), - }); - - const size: std.builtin.TypeInfo.Pointer.Size = switch (tree.token_ids[node.op_token]) { + return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, switch (tree.token_ids[node.op_token]) { .Asterisk, .AsteriskAsterisk => .One, // TODO stage1 type inference bug .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { @@ -585,43 +586,50 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir else => .Many, }), else => unreachable, - }; + }); +} - const simple = node.ptr_info.allowzero_token == null and - node.ptr_info.align_info == null and - node.ptr_info.volatile_token == null and - node.ptr_info.sentinel == null; +fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst { + const meta_type = try addZIRInstConst(mod, scope, src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.type_type), + }); + + const simple = ptr_info.allowzero_token == null and + ptr_info.align_info == null and + ptr_info.volatile_token == null and + ptr_info.sentinel == null; if (simple) { - const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); - const mutable = node.ptr_info.const_token == null; + const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs); + const mutable = ptr_info.const_token == null; // TODO stage1 type inference bug const T = zir.Inst.Tag; return addZIRUnOp(mod, scope, src, switch (size) { .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, - else => unreachable, + .Slice => if (mutable) T.mut_slice_type else T.mut_slice_type, }, child_type); } var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{}; kw_args.size = size; - kw_args.@"allowzero" = node.ptr_info.allowzero_token != null; - if (node.ptr_info.align_info) |some| { + kw_args.@"allowzero" = ptr_info.allowzero_token != null; + if (ptr_info.align_info) |some| { kw_args.@"align" = try expr(mod, scope, .none, some.node); if (some.bit_range) |bit_range| { kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start); kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end); } } - kw_args.mutable = node.ptr_info.const_token == null; - kw_args.@"volatile" = node.ptr_info.volatile_token != null; - if (node.ptr_info.sentinel) |some| { + kw_args.mutable = ptr_info.const_token == null; + kw_args.@"volatile" = ptr_info.volatile_token != null; + if (ptr_info.sentinel) |some| { kw_args.sentinel = try expr(mod, scope, .none, some); } - const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); + const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs); if (kw_args.sentinel) |some| { kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some); } diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 2c326b9308..2218c49200 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -74,6 +74,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .pointer, => return .Pointer, @@ -122,6 +124,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .optional_single_const_pointer, .optional_single_mut_pointer, => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise), @@ -388,6 +392,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .optional_single_mut_pointer, .optional_single_const_pointer, => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), @@ -550,6 +556,18 @@ pub const Type = extern union { ty = payload.pointee_type; continue; }, + .const_slice => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[]const "); + ty = payload.pointee_type; + continue; + }, + .mut_slice => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[]"); + ty = payload.pointee_type; + continue; + }, .int_signed => { const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise); return out_stream.print("i{}", .{payload.bits}); @@ -701,14 +719,7 @@ pub const Type = extern union { // TODO lazy types .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, .array_u8 => self.arrayLen() != 0, - .array_sentinel => self.elemType().hasCodeGenBits(), - .single_const_pointer => self.elemType().hasCodeGenBits(), - .single_mut_pointer => self.elemType().hasCodeGenBits(), - .many_const_pointer => self.elemType().hasCodeGenBits(), - .many_mut_pointer => self.elemType().hasCodeGenBits(), - .c_const_pointer => self.elemType().hasCodeGenBits(), - .c_mut_pointer => self.elemType().hasCodeGenBits(), - .pointer => self.elemType().hasCodeGenBits(), + .array_sentinel, .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, .const_slice, .mut_slice, .pointer => self.elemType().hasCodeGenBits(), .int_signed => self.cast(Payload.IntSigned).?.bits == 0, .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, @@ -763,6 +774,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .optional_single_const_pointer, .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), @@ -868,10 +881,12 @@ pub const Type = extern union { .i32, .u32 => return 4, .i64, .u64 => return 8, - .isize, - .usize - => return @divExact(target.cpu.arch.ptrBitWidth(), 8), - .const_slice_u8 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, + .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + + .const_slice, + .mut_slice, + .const_slice_u8, + => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, .optional_single_const_pointer, .optional_single_mut_pointer, @@ -992,6 +1007,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, => false, .single_const_pointer, @@ -1062,7 +1079,10 @@ pub const Type = extern union { .enum_literal, => false, - .const_slice_u8 => true, + .const_slice, + .mut_slice, + .const_slice_u8, + => true, .pointer => self.cast(Payload.Pointer).?.size == .Slice, }; @@ -1121,6 +1141,7 @@ pub const Type = extern union { .optional_single_mut_pointer, .optional_single_const_pointer, .enum_literal, + .mut_slice, => false, .single_const_pointer, @@ -1128,6 +1149,7 @@ pub const Type = extern union { .c_const_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, + .const_slice, => true, .pointer => !self.cast(Payload.Pointer).?.mutable, @@ -1186,6 +1208,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1307,12 +1331,15 @@ pub const Type = extern union { .array => self.cast(Payload.Array).?.elem_type, .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type, - .single_const_pointer => self.castPointer().?.pointee_type, - .single_mut_pointer => self.castPointer().?.pointee_type, - .many_const_pointer => self.castPointer().?.pointee_type, - .many_mut_pointer => self.castPointer().?.pointee_type, - .c_const_pointer => self.castPointer().?.pointee_type, - .c_mut_pointer => self.castPointer().?.pointee_type, + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .const_slice, + .mut_slice, + => self.castPointer().?.pointee_type, .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), .pointer => self.cast(Payload.Pointer).?.pointee_type, @@ -1411,6 +1438,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1476,6 +1505,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1531,6 +1562,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1597,6 +1630,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_signed, @@ -1663,6 +1698,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1727,6 +1764,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1820,6 +1859,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1889,6 +1930,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1957,6 +2000,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2025,6 +2070,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2090,6 +2137,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2155,6 +2204,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2240,6 +2291,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -2290,6 +2343,8 @@ pub const Type = extern union { .array_sentinel, .array_u8_sentinel_0, .const_slice_u8, + .const_slice, + .mut_slice, .c_void, .optional, .optional_single_mut_pointer, @@ -2392,6 +2447,8 @@ pub const Type = extern union { .single_mut_pointer, .many_const_pointer, .many_mut_pointer, + .const_slice, + .mut_slice, .optional, .optional_single_mut_pointer, .optional_single_const_pointer, @@ -2467,6 +2524,8 @@ pub const Type = extern union { many_mut_pointer, c_const_pointer, c_mut_pointer, + const_slice, + mut_slice, int_signed, int_unsigned, function, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index db0ec242cc..a3ea1f11ab 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -194,18 +194,22 @@ pub const Inst = struct { shl, /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type. shr, - /// Create a const pointer type based on the element type. `*const T` + /// Create a const pointer type with element type T. `*const T` single_const_ptr_type, - /// Create a mutable pointer type based on the element type. `*T` + /// Create a mutable pointer type with element type T. `*T` single_mut_ptr_type, - /// Create a const pointer type based on the element type. `[*]const T` + /// Create a const pointer type with element type T. `[*]const T` many_const_ptr_type, - /// Create a mutable pointer type based on the element type. `[*]T` + /// Create a mutable pointer type with element type T. `[*]T` many_mut_ptr_type, - /// Create a const pointer type based on the element type. `[*c]const T` + /// Create a const pointer type with element type T. `[*c]const T` c_const_ptr_type, - /// Create a mutable pointer type based on the element type. `[*c]T` + /// Create a mutable pointer type with element type T. `[*c]T` c_mut_ptr_type, + /// Create a mutable slice type with element type T. `[]T` + mut_slice_type, + /// Create a const slice type with element type T. `[]T` + const_slice_type, /// Create a pointer type with attributes ptr_type, /// Write a value to a pointer. For loading, see `deref`. @@ -274,6 +278,8 @@ pub const Inst = struct { .many_mut_ptr_type, .c_const_ptr_type, .c_mut_ptr_type, + .mut_slice_type, + .const_slice_type, .optional_type, .unwrap_optional_safe, .unwrap_optional_unsafe, @@ -416,6 +422,8 @@ pub const Inst = struct { .many_mut_ptr_type, .c_const_ptr_type, .c_mut_ptr_type, + .mut_slice_type, + .const_slice_type, .store, .str, .sub, diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index ea3b85b29a..75ec7f6306 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -57,6 +57,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .many_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many), .c_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C), .c_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C), + .const_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.const_slice_type).?, false, .Slice), + .mut_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.mut_slice_type).?, true, .Slice), .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?), .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?), .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?), From 6a053ffcc85ce3f2b598be08e5d0587c930b4358 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 18:50:13 +0300 Subject: [PATCH 4/8] stage2: comptime decl --- src-self-hosted/Module.zig | 51 ++++++++++++++++++++++++++++++++-- test/stage2/compare_output.zig | 5 ---- test/stage2/compile_errors.zig | 36 ++++++++---------------- 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 4893aaba7a..ba39aa8f38 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -1485,6 +1485,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { const type_node = var_decl.getTrailer("type_node") orelse break :blk null; + // Temporary arena for the zir instructions. var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); defer type_scope_arena.deinit(); var type_scope: Scope.GenZIR = .{ @@ -1539,7 +1540,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { try self.coerce(&inner_block.base, some, ret.operand) else ret.operand; - const val = try self.resolveConstValue(&inner_block.base, coerced); + const val = coerced.value() orelse + return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena); break :blk try val.copy(block_scope.arena); @@ -1603,7 +1605,41 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { } return type_changed; }, - .Comptime => @panic("TODO comptime decl"), + .Comptime => { + const comptime_decl = @fieldParentPtr(ast.Node.Comptime, "base", ast_node); + + decl.analysis = .in_progress; + + // A comptime decl does not store any value so we can just deinit this arena after analysis is done. + var analysis_arena = std.heap.ArenaAllocator.init(self.gpa); + defer analysis_arena.deinit(); + var gen_scope: Scope.GenZIR = .{ + .decl = decl, + .arena = &analysis_arena.allocator, + .parent = decl.scope, + }; + defer gen_scope.instructions.deinit(self.gpa); + + // TODO comptime scope here + _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr); + + var block_scope: Scope.Block = .{ + .parent = null, + .func = null, + .decl = decl, + .instructions = .{}, + .arena = &analysis_arena.allocator, + }; + defer block_scope.instructions.deinit(self.gpa); + + _ = try zir_sema.analyzeBody(self, &block_scope.base, .{ + .instructions = gen_scope.instructions.items, + }); + + decl.analysis = .complete; + decl.generation = self.generation; + return true; + }, .Use => @panic("TODO usingnamespace decl"), else => unreachable, } @@ -1794,7 +1830,16 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { } } } else if (src_decl.castTag(.Comptime)) |comptime_node| { - log.err("TODO: analyze comptime decl", .{}); + const name_index = self.getNextAnonNameIndex(); + const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index}); + defer self.gpa.free(name); + + const name_hash = root_scope.fullyQualifiedNameHash(name); + const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl)); + + const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); + root_scope.decls.appendAssumeCapacity(new_decl); + self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); } else if (src_decl.castTag(.ContainerField)) |container_field| { log.err("TODO: analyze container field", .{}); } else if (src_decl.castTag(.TestDecl)) |test_decl| { diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index 6fbc760f26..6c4b9c47e0 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -23,11 +23,6 @@ pub fn addCases(ctx: *TestContext) !void { case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); - case.addError( - \\export fn _start() noreturn { - \\} - , &[_][]const u8{":2:1: error: expected noreturn, found void"}); - // Regular old hello world case.addCompareOutput( \\export fn _start() noreturn { diff --git a/test/stage2/compile_errors.zig b/test/stage2/compile_errors.zig index 45e60c0741..d90c0c7fae 100644 --- a/test/stage2/compile_errors.zig +++ b/test/stage2/compile_errors.zig @@ -67,6 +67,18 @@ pub fn addCases(ctx: *TestContext) !void { \\fn entry() void {} , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); + ctx.compileError("incorrect return type", linux_x64, + \\export fn _start() noreturn { + \\} + , &[_][]const u8{":2:1: error: expected noreturn, found void"}); + + ctx.compileError("extern variable has no type", linux_x64, + \\comptime { + \\ _ = foo; + \\} + \\extern var foo; + , &[_][]const u8{":4:1: error: unable to infer variable type"}); + //ctx.incrementalFailure("function redefinition", linux_x64, // \\fn entry() void {} // \\fn entry() void {} @@ -108,28 +120,4 @@ pub fn addCases(ctx: *TestContext) !void { // \\ return 36893488147419103232; // \\} //, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'"); - - //ctx.testCompileError( - // \\comptime { - // \\ var a: *align(4) align(4) i32 = 0; - // \\} - //, "1.zig", 2, 22, "Extra align qualifier"); - - //ctx.testCompileError( - // \\comptime { - // \\ var b: *const const i32 = 0; - // \\} - //, "1.zig", 2, 19, "Extra align qualifier"); - - //ctx.testCompileError( - // \\comptime { - // \\ var c: *volatile volatile i32 = 0; - // \\} - //, "1.zig", 2, 22, "Extra align qualifier"); - - //ctx.testCompileError( - // \\comptime { - // \\ var d: *allowzero allowzero i32 = 0; - // \\} - //, "1.zig", 2, 23, "Extra align qualifier"); } From f54b2e2da6a9ef72a37fae064dc04d951c686298 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Aug 2020 17:08:01 -0700 Subject: [PATCH 5/8] add missing mutability check in simplePtrType --- src-self-hosted/Module.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index ba39aa8f38..c0d1d0d654 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -2487,7 +2487,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { const variable = tv.val.cast(Value.Payload.Variable).?.variable; - const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty, .One); + const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One); if (!variable.is_mutable and !variable.is_extern) { const val_payload = try scope.arena().create(Value.Payload.RefVal); val_payload.* = .{ .val = variable.init }; @@ -3191,7 +3191,7 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: } pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { - if (size == .Slice and elem_ty.eql(Type.initTag(.u8))) { + if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) { return Type.initTag(.const_slice_u8); } // TODO stage1 type inference bug From 7d6d4b1473e7c0c8bc6ee29a3e0ecd03e850e5ee Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Aug 2020 17:15:01 -0700 Subject: [PATCH 6/8] stage2: move all tests to compare_output.zig --- test/stage2/compare_output.zig | 18 +++++++++++ test/stage2/compile_errors.zig | 59 ---------------------------------- 2 files changed, 18 insertions(+), 59 deletions(-) diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index 6c4b9c47e0..3e08394b2e 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -23,6 +23,12 @@ pub fn addCases(ctx: *TestContext) !void { case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); + // Incorrect return type + case.addError( + \\export fn _start() noreturn { + \\} + , &[_][]const u8{":2:1: error: expected noreturn, found void"}); + // Regular old hello world case.addCompareOutput( \\export fn _start() noreturn { @@ -702,4 +708,16 @@ pub fn addCases(ctx: *TestContext) !void { "1109917696\n", ); } + + ctx.compileError("function redefinition", linux_x64, + \\fn entry() void {} + \\fn entry() void {} + , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); + + ctx.compileError("extern variable has no type", linux_x64, + \\comptime { + \\ _ = foo; + \\} + \\extern var foo; + , &[_][]const u8{":4:1: error: unable to infer variable type"}); } diff --git a/test/stage2/compile_errors.zig b/test/stage2/compile_errors.zig index d90c0c7fae..ce53884aca 100644 --- a/test/stage2/compile_errors.zig +++ b/test/stage2/compile_errors.zig @@ -61,63 +61,4 @@ pub fn addCases(ctx: *TestContext) !void { \\@0 = str("_start") \\@1 = export(@0, "start") ); - - ctx.compileError("function redefinition", linux_x64, - \\fn entry() void {} - \\fn entry() void {} - , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); - - ctx.compileError("incorrect return type", linux_x64, - \\export fn _start() noreturn { - \\} - , &[_][]const u8{":2:1: error: expected noreturn, found void"}); - - ctx.compileError("extern variable has no type", linux_x64, - \\comptime { - \\ _ = foo; - \\} - \\extern var foo; - , &[_][]const u8{":4:1: error: unable to infer variable type"}); - - //ctx.incrementalFailure("function redefinition", linux_x64, - // \\fn entry() void {} - // \\fn entry() void {} - //, &[_][]const u8{":2:4: error: redefinition of 'entry'"}, - // \\fn entry() void {} - //); - - //// TODO: need to make sure this works with other variants of export. - //ctx.incrementalFailure("exported symbol collision", linux_x64, - // \\export fn entry() void {} - // \\export fn entry() void {} - //, &[_][]const u8{":2:11: error: redefinition of 'entry'"}, - // \\export fn entry() void {} - //); - - // ctx.incrementalFailure("missing function name", linux_x64, - // \\fn() void {} - // , &[_][]const u8{":1:3: error: missing function name"}, - // \\fn a() void {} - // ); - - // TODO: re-enable these tests. - // https://github.com/ziglang/zig/issues/1364 - - //ctx.testCompileError( - // \\comptime { - // \\ return; - // \\} - //, "1.zig", 2, 5, "return expression outside function definition"); - - //ctx.testCompileError( - // \\export fn entry() void { - // \\ defer return; - // \\} - //, "1.zig", 2, 11, "cannot return from defer expression"); - - //ctx.testCompileError( - // \\export fn entry() c_int { - // \\ return 36893488147419103232; - // \\} - //, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'"); } From 56ea04cb6d1b2b87e2a2dbde6de8279e035bec73 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Aug 2020 17:19:26 -0700 Subject: [PATCH 7/8] stage2: don't test compile errors of ZIR --- test/stage2/compile_errors.zig | 64 ---------------------------------- test/stage2/test.zig | 1 - 2 files changed, 65 deletions(-) delete mode 100644 test/stage2/compile_errors.zig diff --git a/test/stage2/compile_errors.zig b/test/stage2/compile_errors.zig deleted file mode 100644 index ce53884aca..0000000000 --- a/test/stage2/compile_errors.zig +++ /dev/null @@ -1,64 +0,0 @@ -const TestContext = @import("../../src-self-hosted/test.zig").TestContext; -const std = @import("std"); - -const ErrorMsg = @import("../../src-self-hosted/Module.zig").ErrorMsg; - -const linux_x64 = std.zig.CrossTarget{ - .cpu_arch = .x86_64, - .os_tag = .linux, -}; - -pub fn addCases(ctx: *TestContext) !void { - ctx.compileErrorZIR("call undefined local", linux_x64, - \\@noreturn = primitive(noreturn) - \\ - \\@start_fnty = fntype([], @noreturn, cc=Naked) - \\@start = fn(@start_fnty, { - \\ %0 = call(%test, []) - \\}) - // TODO: address inconsistency in this message and the one in the next test - , &[_][]const u8{":5:13: error: unrecognized identifier: %test"}); - - ctx.compileErrorZIR("call with non-existent target", linux_x64, - \\@noreturn = primitive(noreturn) - \\ - \\@start_fnty = fntype([], @noreturn, cc=Naked) - \\@start = fn(@start_fnty, { - \\ %0 = call(@notafunc, []) - \\}) - \\@0 = str("_start") - \\@1 = export(@0, "start") - , &[_][]const u8{":5:13: error: decl 'notafunc' not found"}); - - // TODO: this error should occur at the call site, not the fntype decl - ctx.compileErrorZIR("call naked function", linux_x64, - \\@noreturn = primitive(noreturn) - \\ - \\@start_fnty = fntype([], @noreturn, cc=Naked) - \\@s = fn(@start_fnty, {}) - \\@start = fn(@start_fnty, { - \\ %0 = call(@s, []) - \\}) - \\@0 = str("_start") - \\@1 = export(@0, "start") - , &[_][]const u8{":4:9: error: unable to call function with naked calling convention"}); - - ctx.incrementalFailureZIR("exported symbol collision", linux_x64, - \\@noreturn = primitive(noreturn) - \\ - \\@start_fnty = fntype([], @noreturn) - \\@start = fn(@start_fnty, {}) - \\ - \\@0 = str("_start") - \\@1 = export(@0, "start") - \\@2 = export(@0, "start") - , &[_][]const u8{":8:13: error: exported symbol collision: _start"}, - \\@noreturn = primitive(noreturn) - \\ - \\@start_fnty = fntype([], @noreturn) - \\@start = fn(@start_fnty, {}) - \\ - \\@0 = str("_start") - \\@1 = export(@0, "start") - ); -} diff --git a/test/stage2/test.zig b/test/stage2/test.zig index f5acc72f93..182bd116e0 100644 --- a/test/stage2/test.zig +++ b/test/stage2/test.zig @@ -1,7 +1,6 @@ const TestContext = @import("../../src-self-hosted/test.zig").TestContext; pub fn addCases(ctx: *TestContext) !void { - try @import("compile_errors.zig").addCases(ctx); try @import("compare_output.zig").addCases(ctx); try @import("zir.zig").addCases(ctx); try @import("cbe.zig").addCases(ctx); From 73d16d015e09c05aecba8a58881cbc429e8126fa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Aug 2020 17:25:09 -0700 Subject: [PATCH 8/8] stage2: reorganize tests The main test cases are now in `test/stage2/test.zig` which can then call addCases on other files if it wants to organize things differently. --- test/stage2/compare_output.zig | 723 --------------------------------- test/stage2/test.zig | 721 +++++++++++++++++++++++++++++++- 2 files changed, 720 insertions(+), 724 deletions(-) delete mode 100644 test/stage2/compare_output.zig diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig deleted file mode 100644 index 3e08394b2e..0000000000 --- a/test/stage2/compare_output.zig +++ /dev/null @@ -1,723 +0,0 @@ -const std = @import("std"); -const TestContext = @import("../../src-self-hosted/test.zig").TestContext; -// self-hosted does not yet support PE executable files / COFF object files -// or mach-o files. So we do these test cases cross compiling for x86_64-linux. -const linux_x64 = std.zig.CrossTarget{ - .cpu_arch = .x86_64, - .os_tag = .linux, -}; - -const linux_riscv64 = std.zig.CrossTarget{ - .cpu_arch = .riscv64, - .os_tag = .linux, -}; - -const wasi = std.zig.CrossTarget{ - .cpu_arch = .wasm32, - .os_tag = .wasi, -}; - -pub fn addCases(ctx: *TestContext) !void { - { - var case = ctx.exe("hello world with updates", linux_x64); - - case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); - - // Incorrect return type - case.addError( - \\export fn _start() noreturn { - \\} - , &[_][]const u8{":2:1: error: expected noreturn, found void"}); - - // Regular old hello world - case.addCompareOutput( - \\export fn _start() noreturn { - \\ print(); - \\ - \\ exit(); - \\} - \\ - \\fn print() void { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (1), - \\ [arg1] "{rdi}" (1), - \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), - \\ [arg3] "{rdx}" (14) - \\ : "rcx", "r11", "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "Hello, World!\n", - ); - // Now change the message only - case.addCompareOutput( - \\export fn _start() noreturn { - \\ print(); - \\ - \\ exit(); - \\} - \\ - \\fn print() void { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (1), - \\ [arg1] "{rdi}" (1), - \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), - \\ [arg3] "{rdx}" (104) - \\ : "rcx", "r11", "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n", - ); - // Now we print it twice. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ print(); - \\ print(); - \\ - \\ exit(); - \\} - \\ - \\fn print() void { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (1), - \\ [arg1] "{rdi}" (1), - \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), - \\ [arg3] "{rdx}" (104) - \\ : "rcx", "r11", "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - \\What is up? This is a longer message that will force the data to be relocated in virtual address space. - \\What is up? This is a longer message that will force the data to be relocated in virtual address space. - \\ - ); - } - - { - var case = ctx.exe("hello world", linux_riscv64); - // Regular old hello world - case.addCompareOutput( - \\export fn _start() noreturn { - \\ print(); - \\ - \\ exit(); - \\} - \\ - \\fn print() void { - \\ asm volatile ("ecall" - \\ : - \\ : [number] "{a7}" (64), - \\ [arg1] "{a0}" (1), - \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), - \\ [arg3] "{a2}" ("Hello, World!\n".len) - \\ : "rcx", "r11", "memory" - \\ ); - \\ return; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("ecall" - \\ : - \\ : [number] "{a7}" (94), - \\ [arg1] "{a0}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "Hello, World!\n", - ); - } - - { - var case = ctx.exe("adding numbers at comptime", linux_x64); - case.addCompareOutput( - \\export fn _start() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (1), - \\ [arg1] "{rdi}" (1), - \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), - \\ [arg3] "{rdx}" (10 + 4) - \\ : "rcx", "r11", "memory" - \\ ); - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "Hello, World!\n", - ); - } - - { - var case = ctx.exe("adding numbers at runtime", linux_x64); - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(3, 4); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ if (a + b != 7) unreachable; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - } - - { - var case = ctx.exe("substracting numbers at runtime", linux_x64); - case.addCompareOutput( - \\export fn _start() noreturn { - \\ sub(7, 4); - \\ - \\ exit(); - \\} - \\ - \\fn sub(a: u32, b: u32) void { - \\ if (a - b != 3) unreachable; - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - } - - { - var case = ctx.exe("assert function", linux_x64); - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(3, 4); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ assert(a + b == 7); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Tests copying a register. For the `c = a + b`, it has to - // preserve both a and b, because they are both used later. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(3, 4); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ const c = a + b; // 7 - \\ const d = a + c; // 10 - \\ const e = d + b; // 14 - \\ assert(e == 14); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // More stress on the liveness detection. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(3, 4); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ const c = a + b; // 7 - \\ const d = a + c; // 10 - \\ const e = d + b; // 14 - \\ const f = d + e; // 24 - \\ const g = e + f; // 38 - \\ const h = f + g; // 62 - \\ const i = g + h; // 100 - \\ assert(i == 100); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Requires a second move. The register allocator should figure out to re-use rax. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(3, 4); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ const c = a + b; // 7 - \\ const d = a + c; // 10 - \\ const e = d + b; // 14 - \\ const f = d + e; // 24 - \\ const g = e + f; // 38 - \\ const h = f + g; // 62 - \\ const i = g + h; // 100 - \\ const j = i + d; // 110 - \\ assert(j == 110); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Now we test integer return values. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ assert(add(3, 4) == 7); - \\ assert(add(20, 10) == 30); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) u32 { - \\ return a + b; - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Local mutable variables. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ assert(add(3, 4) == 7); - \\ assert(add(20, 10) == 30); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) u32 { - \\ var x: u32 = undefined; - \\ x = 0; - \\ x += a; - \\ x += b; - \\ return x; - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Optionals - case.addCompareOutput( - \\export fn _start() noreturn { - \\ const a: u32 = 2; - \\ const b: ?u32 = a; - \\ const c = b.?; - \\ if (c != 2) unreachable; - \\ - \\ exit(); - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // While loops - case.addCompareOutput( - \\export fn _start() noreturn { - \\ var i: u32 = 0; - \\ while (i < 4) : (i += 1) print(); - \\ assert(i == 4); - \\ - \\ exit(); - \\} - \\ - \\fn print() void { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (1), - \\ [arg1] "{rdi}" (1), - \\ [arg2] "{rsi}" (@ptrToInt("hello\n")), - \\ [arg3] "{rdx}" (6) - \\ : "rcx", "r11", "memory" - \\ ); - \\ return; - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "hello\nhello\nhello\nhello\n", - ); - - // Labeled blocks (no conditional branch) - case.addCompareOutput( - \\export fn _start() noreturn { - \\ assert(add(3, 4) == 20); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) u32 { - \\ const x: u32 = blk: { - \\ const c = a + b; // 7 - \\ const d = a + c; // 10 - \\ const e = d + b; // 14 - \\ break :blk e; - \\ }; - \\ const y = x + a; // 17 - \\ const z = y + a; // 20 - \\ return z; - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // This catches a possible bug in the logic for re-using dying operands. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ assert(add(3, 4) == 116); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) u32 { - \\ const x: u32 = blk: { - \\ const c = a + b; // 7 - \\ const d = a + c; // 10 - \\ const e = d + b; // 14 - \\ const f = d + e; // 24 - \\ const g = e + f; // 38 - \\ const h = f + g; // 62 - \\ const i = g + h; // 100 - \\ const j = i + d; // 110 - \\ break :blk j; - \\ }; - \\ const y = x + a; // 113 - \\ const z = y + a; // 116 - \\ return z; - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Character literals and multiline strings. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ const ignore = - \\ \\ cool thx - \\ \\ - \\ ; - \\ add('ぁ', '\x03'); - \\ - \\ exit(); - \\} - \\ - \\fn add(a: u32, b: u32) void { - \\ assert(a + b == 12356); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - - // Global const. - case.addCompareOutput( - \\export fn _start() noreturn { - \\ add(aa, bb); - \\ - \\ exit(); - \\} - \\ - \\const aa = 'ぁ'; - \\const bb = '\x03'; - \\ - \\fn add(a: u32, b: u32) void { - \\ assert(a + b == 12356); - \\} - \\ - \\pub fn assert(ok: bool) void { - \\ if (!ok) unreachable; // assertion failure - \\} - \\ - \\fn exit() noreturn { - \\ asm volatile ("syscall" - \\ : - \\ : [number] "{rax}" (231), - \\ [arg1] "{rdi}" (0) - \\ : "rcx", "r11", "memory" - \\ ); - \\ unreachable; - \\} - , - "", - ); - } - - { - var case = ctx.exe("wasm function calls", wasi); - - case.addCompareOutput( - \\export fn _start() u32 { - \\ foo(); - \\ bar(); - \\ return 42; - \\} - \\fn foo() void { - \\ bar(); - \\ bar(); - \\} - \\fn bar() void {} - , - "42\n", - ); - - case.addCompareOutput( - \\export fn _start() i64 { - \\ bar(); - \\ foo(); - \\ foo(); - \\ bar(); - \\ foo(); - \\ bar(); - \\ return 42; - \\} - \\fn foo() void { - \\ bar(); - \\} - \\fn bar() void {} - , - "42\n", - ); - - case.addCompareOutput( - \\export fn _start() f32 { - \\ bar(); - \\ foo(); - \\ return 42.0; - \\} - \\fn foo() void { - \\ bar(); - \\ bar(); - \\ bar(); - \\} - \\fn bar() void {} - , - // This is what you get when you take the bits of the IEE-754 - // representation of 42.0 and reinterpret them as an unsigned - // integer. Guess that's a bug in wasmtime. - "1109917696\n", - ); - } - - ctx.compileError("function redefinition", linux_x64, - \\fn entry() void {} - \\fn entry() void {} - , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); - - ctx.compileError("extern variable has no type", linux_x64, - \\comptime { - \\ _ = foo; - \\} - \\extern var foo; - , &[_][]const u8{":4:1: error: unable to infer variable type"}); -} diff --git a/test/stage2/test.zig b/test/stage2/test.zig index 182bd116e0..91257526dd 100644 --- a/test/stage2/test.zig +++ b/test/stage2/test.zig @@ -1,7 +1,726 @@ +const std = @import("std"); const TestContext = @import("../../src-self-hosted/test.zig").TestContext; +// self-hosted does not yet support PE executable files / COFF object files +// or mach-o files. So we do these test cases cross compiling for x86_64-linux. +const linux_x64 = std.zig.CrossTarget{ + .cpu_arch = .x86_64, + .os_tag = .linux, +}; + +const linux_riscv64 = std.zig.CrossTarget{ + .cpu_arch = .riscv64, + .os_tag = .linux, +}; + +const wasi = std.zig.CrossTarget{ + .cpu_arch = .wasm32, + .os_tag = .wasi, +}; + pub fn addCases(ctx: *TestContext) !void { - try @import("compare_output.zig").addCases(ctx); try @import("zir.zig").addCases(ctx); try @import("cbe.zig").addCases(ctx); + { + var case = ctx.exe("hello world with updates", linux_x64); + + case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); + + // Incorrect return type + case.addError( + \\export fn _start() noreturn { + \\} + , &[_][]const u8{":2:1: error: expected noreturn, found void"}); + + // Regular old hello world + case.addCompareOutput( + \\export fn _start() noreturn { + \\ print(); + \\ + \\ exit(); + \\} + \\ + \\fn print() void { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (1), + \\ [arg1] "{rdi}" (1), + \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), + \\ [arg3] "{rdx}" (14) + \\ : "rcx", "r11", "memory" + \\ ); + \\ return; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "Hello, World!\n", + ); + // Now change the message only + case.addCompareOutput( + \\export fn _start() noreturn { + \\ print(); + \\ + \\ exit(); + \\} + \\ + \\fn print() void { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (1), + \\ [arg1] "{rdi}" (1), + \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), + \\ [arg3] "{rdx}" (104) + \\ : "rcx", "r11", "memory" + \\ ); + \\ return; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n", + ); + // Now we print it twice. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ print(); + \\ print(); + \\ + \\ exit(); + \\} + \\ + \\fn print() void { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (1), + \\ [arg1] "{rdi}" (1), + \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")), + \\ [arg3] "{rdx}" (104) + \\ : "rcx", "r11", "memory" + \\ ); + \\ return; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + \\What is up? This is a longer message that will force the data to be relocated in virtual address space. + \\What is up? This is a longer message that will force the data to be relocated in virtual address space. + \\ + ); + } + + { + var case = ctx.exe("hello world", linux_riscv64); + // Regular old hello world + case.addCompareOutput( + \\export fn _start() noreturn { + \\ print(); + \\ + \\ exit(); + \\} + \\ + \\fn print() void { + \\ asm volatile ("ecall" + \\ : + \\ : [number] "{a7}" (64), + \\ [arg1] "{a0}" (1), + \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), + \\ [arg3] "{a2}" ("Hello, World!\n".len) + \\ : "rcx", "r11", "memory" + \\ ); + \\ return; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("ecall" + \\ : + \\ : [number] "{a7}" (94), + \\ [arg1] "{a0}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "Hello, World!\n", + ); + } + + { + var case = ctx.exe("adding numbers at comptime", linux_x64); + case.addCompareOutput( + \\export fn _start() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (1), + \\ [arg1] "{rdi}" (1), + \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")), + \\ [arg3] "{rdx}" (10 + 4) + \\ : "rcx", "r11", "memory" + \\ ); + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "Hello, World!\n", + ); + } + + { + var case = ctx.exe("adding numbers at runtime", linux_x64); + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(3, 4); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ if (a + b != 7) unreachable; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + } + + { + var case = ctx.exe("substracting numbers at runtime", linux_x64); + case.addCompareOutput( + \\export fn _start() noreturn { + \\ sub(7, 4); + \\ + \\ exit(); + \\} + \\ + \\fn sub(a: u32, b: u32) void { + \\ if (a - b != 3) unreachable; + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + } + + { + var case = ctx.exe("assert function", linux_x64); + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(3, 4); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ assert(a + b == 7); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Tests copying a register. For the `c = a + b`, it has to + // preserve both a and b, because they are both used later. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(3, 4); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ const c = a + b; // 7 + \\ const d = a + c; // 10 + \\ const e = d + b; // 14 + \\ assert(e == 14); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // More stress on the liveness detection. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(3, 4); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ const c = a + b; // 7 + \\ const d = a + c; // 10 + \\ const e = d + b; // 14 + \\ const f = d + e; // 24 + \\ const g = e + f; // 38 + \\ const h = f + g; // 62 + \\ const i = g + h; // 100 + \\ assert(i == 100); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Requires a second move. The register allocator should figure out to re-use rax. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(3, 4); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ const c = a + b; // 7 + \\ const d = a + c; // 10 + \\ const e = d + b; // 14 + \\ const f = d + e; // 24 + \\ const g = e + f; // 38 + \\ const h = f + g; // 62 + \\ const i = g + h; // 100 + \\ const j = i + d; // 110 + \\ assert(j == 110); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Now we test integer return values. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ assert(add(3, 4) == 7); + \\ assert(add(20, 10) == 30); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) u32 { + \\ return a + b; + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Local mutable variables. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ assert(add(3, 4) == 7); + \\ assert(add(20, 10) == 30); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) u32 { + \\ var x: u32 = undefined; + \\ x = 0; + \\ x += a; + \\ x += b; + \\ return x; + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Optionals + case.addCompareOutput( + \\export fn _start() noreturn { + \\ const a: u32 = 2; + \\ const b: ?u32 = a; + \\ const c = b.?; + \\ if (c != 2) unreachable; + \\ + \\ exit(); + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // While loops + case.addCompareOutput( + \\export fn _start() noreturn { + \\ var i: u32 = 0; + \\ while (i < 4) : (i += 1) print(); + \\ assert(i == 4); + \\ + \\ exit(); + \\} + \\ + \\fn print() void { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (1), + \\ [arg1] "{rdi}" (1), + \\ [arg2] "{rsi}" (@ptrToInt("hello\n")), + \\ [arg3] "{rdx}" (6) + \\ : "rcx", "r11", "memory" + \\ ); + \\ return; + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "hello\nhello\nhello\nhello\n", + ); + + // Labeled blocks (no conditional branch) + case.addCompareOutput( + \\export fn _start() noreturn { + \\ assert(add(3, 4) == 20); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) u32 { + \\ const x: u32 = blk: { + \\ const c = a + b; // 7 + \\ const d = a + c; // 10 + \\ const e = d + b; // 14 + \\ break :blk e; + \\ }; + \\ const y = x + a; // 17 + \\ const z = y + a; // 20 + \\ return z; + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // This catches a possible bug in the logic for re-using dying operands. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ assert(add(3, 4) == 116); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) u32 { + \\ const x: u32 = blk: { + \\ const c = a + b; // 7 + \\ const d = a + c; // 10 + \\ const e = d + b; // 14 + \\ const f = d + e; // 24 + \\ const g = e + f; // 38 + \\ const h = f + g; // 62 + \\ const i = g + h; // 100 + \\ const j = i + d; // 110 + \\ break :blk j; + \\ }; + \\ const y = x + a; // 113 + \\ const z = y + a; // 116 + \\ return z; + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Character literals and multiline strings. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ const ignore = + \\ \\ cool thx + \\ \\ + \\ ; + \\ add('ぁ', '\x03'); + \\ + \\ exit(); + \\} + \\ + \\fn add(a: u32, b: u32) void { + \\ assert(a + b == 12356); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + + // Global const. + case.addCompareOutput( + \\export fn _start() noreturn { + \\ add(aa, bb); + \\ + \\ exit(); + \\} + \\ + \\const aa = 'ぁ'; + \\const bb = '\x03'; + \\ + \\fn add(a: u32, b: u32) void { + \\ assert(a + b == 12356); + \\} + \\ + \\pub fn assert(ok: bool) void { + \\ if (!ok) unreachable; // assertion failure + \\} + \\ + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , + "", + ); + } + + { + var case = ctx.exe("wasm function calls", wasi); + + case.addCompareOutput( + \\export fn _start() u32 { + \\ foo(); + \\ bar(); + \\ return 42; + \\} + \\fn foo() void { + \\ bar(); + \\ bar(); + \\} + \\fn bar() void {} + , + "42\n", + ); + + case.addCompareOutput( + \\export fn _start() i64 { + \\ bar(); + \\ foo(); + \\ foo(); + \\ bar(); + \\ foo(); + \\ bar(); + \\ return 42; + \\} + \\fn foo() void { + \\ bar(); + \\} + \\fn bar() void {} + , + "42\n", + ); + + case.addCompareOutput( + \\export fn _start() f32 { + \\ bar(); + \\ foo(); + \\ return 42.0; + \\} + \\fn foo() void { + \\ bar(); + \\ bar(); + \\ bar(); + \\} + \\fn bar() void {} + , + // This is what you get when you take the bits of the IEE-754 + // representation of 42.0 and reinterpret them as an unsigned + // integer. Guess that's a bug in wasmtime. + "1109917696\n", + ); + } + + ctx.compileError("function redefinition", linux_x64, + \\fn entry() void {} + \\fn entry() void {} + , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); + + ctx.compileError("extern variable has no type", linux_x64, + \\comptime { + \\ _ = foo; + \\} + \\extern var foo; + , &[_][]const u8{":4:1: error: unable to infer variable type"}); }