From 41e52bd5ccaccc0191c9f3434098d27ed07f62b7 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 27 Dec 2021 01:22:57 +0100 Subject: [PATCH 1/3] stage2: don't call comptime functions with generic poison arguments When calling a comptime or inline function, if the parameter is generic and is resolved to generic_poison or generic_poison_type, the invocation was part of another function's parameters or return type expression and is dependent on an as-of-yet type of another parameter. In this case, processing should stop, and we return error.GenericPoison to let the caller in funcCommon, zirParam or zirParamAnytype know that the function is generic. --- src/Sema.zig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Sema.zig b/src/Sema.zig index b65e88360f..9ef3d9d425 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3888,6 +3888,14 @@ fn analyzeCall( if (is_comptime_call) { const arg_val = try sema.resolveConstMaybeUndefVal(&child_block, arg_src, casted_arg); + switch (arg_val.tag()) { + .generic_poison, .generic_poison_type => { + // This function is currently evaluated as part of an as-of-yet unresolvable + // parameter or return type. + return error.GenericPoison; + }, + else => {}, + } memoized_call_key.args[arg_i] = .{ .ty = param_ty, .val = arg_val, @@ -3905,6 +3913,14 @@ fn analyzeCall( if (is_comptime_call) { const arg_src = call_src; // TODO: better source location const arg_val = try sema.resolveConstMaybeUndefVal(&child_block, arg_src, uncasted_arg); + switch (arg_val.tag()) { + .generic_poison, .generic_poison_type => { + // This function is currently evaluated as part of an as-of-yet unresolvable + // parameter or return type. + return error.GenericPoison; + }, + else => {}, + } memoized_call_key.args[arg_i] = .{ .ty = sema.typeOf(uncasted_arg), .val = arg_val, From 7f77d3d671dbfec11592d28cd51454aeefd07930 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 3 Jan 2022 01:56:59 +0100 Subject: [PATCH 2/3] stage2: pointer reify --- src/Sema.zig | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 9ef3d9d425..5ba1e555a7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -10269,11 +10269,41 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I var buffer: Value.ToTypeBuffer = undefined; const child_ty = child_val.toType(&buffer); - const ty = try Type.vector(sema.arena, len, child_ty); + const ty = try Type.vector(sema.arena, len, try child_ty.copy(sema.arena)); return sema.addType(ty); }, .Float => return sema.fail(block, src, "TODO: Sema.zirReify for Float", .{}), - .Pointer => return sema.fail(block, src, "TODO: Sema.zirReify for Pointer", .{}), + .Pointer => { + const struct_val = union_val.val.castTag(.@"struct").?.data; + // TODO use reflection instead of magic numbers here + const size_val = struct_val[0]; + const is_const_val = struct_val[1]; + const is_volatile_val = struct_val[2]; + const alignment_val = struct_val[3]; + const address_space_val = struct_val[4]; + const child_val = struct_val[5]; + const is_allowzero_val = struct_val[6]; + const sentinel_val = struct_val[7]; + + var buffer: Value.ToTypeBuffer = undefined; + const child_ty = child_val.toType(&buffer); + + if (!sentinel_val.isNull()) { + return sema.fail(block, src, "TODO: implement zirReify for pointer with non-null sentinel", .{}); + } + + const ty = try Type.ptr(sema.arena, .{ + .size = size_val.toEnum(std.builtin.TypeInfo.Pointer.Size), + .mutable = !is_const_val.toBool(), + .@"volatile" = is_volatile_val.toBool(), + .@"align" = @intCast(u8, alignment_val.toUnsignedInt()), // TODO: Validate this value. + .@"addrspace" = address_space_val.toEnum(std.builtin.AddressSpace), + .pointee_type = try child_ty.copy(sema.arena), + .@"allowzero" = is_allowzero_val.toBool(), + .sentinel = null, + }); + return sema.addType(ty); + }, .Array => return sema.fail(block, src, "TODO: Sema.zirReify for Array", .{}), .Struct => return sema.fail(block, src, "TODO: Sema.zirReify for Struct", .{}), .Optional => return sema.fail(block, src, "TODO: Sema.zirReify for Optional", .{}), From 67449b659dc752b6cc6d9359637af687a4618609 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 3 Jan 2022 02:04:20 +0100 Subject: [PATCH 3/3] stage2: move some more tests --- test/behavior/type.zig | 45 +++++++++++++++++++++++++++++ test/behavior/type_info.zig | 23 +++++++++++++++ test/behavior/type_info_stage1.zig | 25 +--------------- test/behavior/type_stage1.zig | 46 +----------------------------- 4 files changed, 70 insertions(+), 69 deletions(-) diff --git a/test/behavior/type.zig b/test/behavior/type.zig index 1430a153e9..cb72f86b8b 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -57,3 +57,48 @@ test "Type.EnumLiteral" { @TypeOf(.Dummy), }); } + +test "Type.Pointer" { + try testTypes(&[_]type{ + // One Value Pointer Types + *u8, *const u8, + *volatile u8, *const volatile u8, + *align(4) u8, *align(4) const u8, + *align(4) volatile u8, *align(4) const volatile u8, + *align(8) u8, *align(8) const u8, + *align(8) volatile u8, *align(8) const volatile u8, + *allowzero u8, *allowzero const u8, + *allowzero volatile u8, *allowzero const volatile u8, + *allowzero align(4) u8, *allowzero align(4) const u8, + *allowzero align(4) volatile u8, *allowzero align(4) const volatile u8, + // Many Values Pointer Types + [*]u8, [*]const u8, + [*]volatile u8, [*]const volatile u8, + [*]align(4) u8, [*]align(4) const u8, + [*]align(4) volatile u8, [*]align(4) const volatile u8, + [*]align(8) u8, [*]align(8) const u8, + [*]align(8) volatile u8, [*]align(8) const volatile u8, + [*]allowzero u8, [*]allowzero const u8, + [*]allowzero volatile u8, [*]allowzero const volatile u8, + [*]allowzero align(4) u8, [*]allowzero align(4) const u8, + [*]allowzero align(4) volatile u8, [*]allowzero align(4) const volatile u8, + // Slice Types + []u8, []const u8, + []volatile u8, []const volatile u8, + []align(4) u8, []align(4) const u8, + []align(4) volatile u8, []align(4) const volatile u8, + []align(8) u8, []align(8) const u8, + []align(8) volatile u8, []align(8) const volatile u8, + []allowzero u8, []allowzero const u8, + []allowzero volatile u8, []allowzero const volatile u8, + []allowzero align(4) u8, []allowzero align(4) const u8, + []allowzero align(4) volatile u8, []allowzero align(4) const volatile u8, + // C Pointer Types + [*c]u8, [*c]const u8, + [*c]volatile u8, [*c]const volatile u8, + [*c]align(4) u8, [*c]align(4) const u8, + [*c]align(4) volatile u8, [*c]align(4) const volatile u8, + [*c]align(8) u8, [*c]align(8) const u8, + [*c]align(8) volatile u8, [*c]align(8) const volatile u8, + }); +} diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig index 1c67edf34f..14d09ac6f5 100644 --- a/test/behavior/type_info.zig +++ b/test/behavior/type_info.zig @@ -34,3 +34,26 @@ fn testOptional() !void { try expect(null_info == .Optional); try expect(null_info.Optional.child == void); } + +test "type info: C pointer type info" { + try testCPtr(); + comptime try testCPtr(); +} + +fn testCPtr() !void { + const ptr_info = @typeInfo([*c]align(4) const i8); + try expect(ptr_info == .Pointer); + try expect(ptr_info.Pointer.size == .C); + try expect(ptr_info.Pointer.is_const); + try expect(!ptr_info.Pointer.is_volatile); + try expect(ptr_info.Pointer.alignment == 4); + try expect(ptr_info.Pointer.child == i8); +} + +test "type info: value is correctly copied" { + comptime { + var ptrInfo = @typeInfo([]u32); + ptrInfo.Pointer.size = .One; + try expect(@typeInfo([]u32).Pointer.size == .Slice); + } +} diff --git a/test/behavior/type_info_stage1.zig b/test/behavior/type_info_stage1.zig index 625536f1fa..90cbf10268 100644 --- a/test/behavior/type_info_stage1.zig +++ b/test/behavior/type_info_stage1.zig @@ -68,21 +68,6 @@ fn testNullTerminatedPtr() !void { try expect(@typeInfo([:0]u8).Pointer.sentinel != null); } -test "type info: C pointer type info" { - try testCPtr(); - comptime try testCPtr(); -} - -fn testCPtr() !void { - const ptr_info = @typeInfo([*c]align(4) const i8); - try expect(ptr_info == .Pointer); - try expect(ptr_info.Pointer.size == .C); - try expect(ptr_info.Pointer.is_const); - try expect(!ptr_info.Pointer.is_volatile); - try expect(ptr_info.Pointer.alignment == 4); - try expect(ptr_info.Pointer.child == i8); -} - test "type info: slice type info" { try testSlice(); comptime try testSlice(); @@ -395,7 +380,7 @@ test "@typeInfo does not force declarations into existence" { comptime try expect(@typeInfo(S).Struct.fields.len == 1); } -test "defaut value for a var-typed field" { +test "default value for a var-typed field" { const S = struct { x: anytype }; try expect(@typeInfo(S).Struct.fields[0].default_value == null); } @@ -413,14 +398,6 @@ test "type info for async frames" { } } -test "type info: value is correctly copied" { - comptime { - var ptrInfo = @typeInfo([]u32); - ptrInfo.Pointer.size = .One; - try expect(@typeInfo([]u32).Pointer.size == .Slice); - } -} - test "Declarations are returned in declaration order" { const S = struct { const a = 1; diff --git a/test/behavior/type_stage1.zig b/test/behavior/type_stage1.zig index 914bf166d6..a87cba08d4 100644 --- a/test/behavior/type_stage1.zig +++ b/test/behavior/type_stage1.zig @@ -17,51 +17,6 @@ test "Type.Float" { try testTypes(&[_]type{ f16, f32, f64, f128 }); } -test "Type.Pointer" { - try testTypes(&[_]type{ - // One Value Pointer Types - *u8, *const u8, - *volatile u8, *const volatile u8, - *align(4) u8, *align(4) const u8, - *align(4) volatile u8, *align(4) const volatile u8, - *align(8) u8, *align(8) const u8, - *align(8) volatile u8, *align(8) const volatile u8, - *allowzero u8, *allowzero const u8, - *allowzero volatile u8, *allowzero const volatile u8, - *allowzero align(4) u8, *allowzero align(4) const u8, - *allowzero align(4) volatile u8, *allowzero align(4) const volatile u8, - // Many Values Pointer Types - [*]u8, [*]const u8, - [*]volatile u8, [*]const volatile u8, - [*]align(4) u8, [*]align(4) const u8, - [*]align(4) volatile u8, [*]align(4) const volatile u8, - [*]align(8) u8, [*]align(8) const u8, - [*]align(8) volatile u8, [*]align(8) const volatile u8, - [*]allowzero u8, [*]allowzero const u8, - [*]allowzero volatile u8, [*]allowzero const volatile u8, - [*]allowzero align(4) u8, [*]allowzero align(4) const u8, - [*]allowzero align(4) volatile u8, [*]allowzero align(4) const volatile u8, - // Slice Types - []u8, []const u8, - []volatile u8, []const volatile u8, - []align(4) u8, []align(4) const u8, - []align(4) volatile u8, []align(4) const volatile u8, - []align(8) u8, []align(8) const u8, - []align(8) volatile u8, []align(8) const volatile u8, - []allowzero u8, []allowzero const u8, - []allowzero volatile u8, []allowzero const volatile u8, - []allowzero align(4) u8, []allowzero align(4) const u8, - []allowzero align(4) volatile u8, []allowzero align(4) const volatile u8, - // C Pointer Types - [*c]u8, [*c]const u8, - [*c]volatile u8, [*c]const volatile u8, - [*c]align(4) u8, [*c]align(4) const u8, - [*c]align(4) volatile u8, [*c]align(4) const volatile u8, - [*c]align(8) u8, [*c]align(8) const u8, - [*c]align(8) volatile u8, [*c]align(8) const volatile u8, - }); -} - test "Type.Array" { try testing.expect([123]u8 == @Type(TypeInfo{ .Array = TypeInfo.Array{ @@ -102,6 +57,7 @@ test "@Type create slice with null sentinel" { }); try testing.expect(Slice == []align(8) const *i32); } + test "@Type picks up the sentinel value from TypeInfo" { try testTypes(&[_]type{ [11:0]u8, [4:10]u8,