commit 6d7b0690a0e49819ffd92e330f0fd48a7abc0d16 (tree)
parent cae76d8293f6416ff698171c2ae10552fa014587
Author: Andrew Kelley <andrew@ziglang.org>
Date: Sun, 25 Sep 2022 03:31:57 -0400
Merge pull request #12942 from Vexu/stage2-fixes
misc stage2 fixes
Diffstat:
13 files changed, 277 insertions(+), 38 deletions(-)
diff --git a/src/AstGen.zig b/src/AstGen.zig
@@ -577,6 +577,12 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
+ const prev_anon_name_strategy = gz.anon_name_strategy;
+ defer gz.anon_name_strategy = prev_anon_name_strategy;
+ if (!nodeUsesAnonNameStrategy(tree, node)) {
+ gz.anon_name_strategy = .anon;
+ }
+
switch (node_tags[node]) {
.root => unreachable, // Top-level declaration.
.@"usingnamespace" => unreachable, // Top-level declaration.
@@ -9344,6 +9350,32 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
}
}
+/// Returns `true` if the node uses `gz.anon_name_strategy`.
+fn nodeUsesAnonNameStrategy(tree: *const Ast, node: Ast.Node.Index) bool {
+ const node_tags = tree.nodes.items(.tag);
+ switch (node_tags[node]) {
+ .container_decl,
+ .container_decl_trailing,
+ .container_decl_two,
+ .container_decl_two_trailing,
+ .container_decl_arg,
+ .container_decl_arg_trailing,
+ .tagged_union,
+ .tagged_union_trailing,
+ .tagged_union_two,
+ .tagged_union_two_trailing,
+ .tagged_union_enum_tag,
+ .tagged_union_enum_tag_trailing,
+ => return true,
+ .builtin_call_two, .builtin_call_two_comma, .builtin_call, .builtin_call_comma => {
+ const builtin_token = tree.nodes.items(.main_token)[node];
+ const builtin_name = tree.tokenSlice(builtin_token);
+ return std.mem.eql(u8, builtin_name, "@Type");
+ },
+ else => return false,
+ }
+}
+
/// Applies `rl` semantics to `result`. Expressions which do not do their own handling of
/// result locations must call this function on their result.
/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.
diff --git a/src/Sema.zig b/src/Sema.zig
@@ -8180,7 +8180,7 @@ fn analyzeParameter(
if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(cc)) {
return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
}
- if (this_generic and !Type.fnCallingConventionAllowsZigTypes(cc)) {
+ if (this_generic and !sema.no_partial_func_ty and !Type.fnCallingConventionAllowsZigTypes(cc)) {
return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
}
if (!param.ty.isValidParamType()) {
@@ -8196,7 +8196,7 @@ fn analyzeParameter(
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (!Type.fnCallingConventionAllowsZigTypes(cc) and !try sema.validateExternType(block, param_src, param.ty, .param_ty)) {
+ if (!this_generic and !Type.fnCallingConventionAllowsZigTypes(cc) and !try sema.validateExternType(block, param_src, param.ty, .param_ty)) {
const msg = msg: {
const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
param.ty.fmt(sema.mod), @tagName(cc),
@@ -8277,8 +8277,21 @@ fn zirParam(
else => |e| return e,
}
};
- const is_comptime = comptime_syntax or
- try sema.typeRequiresComptime(param_ty);
+ const is_comptime = sema.typeRequiresComptime(param_ty) catch |err| switch (err) {
+ error.GenericPoison => {
+ // The type is not available until the generic instantiation.
+ // We result the param instruction with a poison value and
+ // insert an anytype parameter.
+ try block.params.append(sema.gpa, .{
+ .ty = Type.initTag(.generic_poison),
+ .is_comptime = comptime_syntax,
+ .name = param_name,
+ });
+ try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);
+ return;
+ },
+ else => |e| return e,
+ } or comptime_syntax;
if (sema.inst_map.get(inst)) |arg| {
if (is_comptime) {
// We have a comptime value for this parameter so it should be elided from the
@@ -15966,8 +15979,8 @@ fn zirStructInit(
const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;
const first_field_type_data = zir_datas[first_item.field_type].pl_node;
const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;
- const unresolved_struct_type = try sema.resolveType(block, src, first_field_type_extra.container_type);
- const resolved_ty = try sema.resolveTypeFields(block, src, unresolved_struct_type);
+ const resolved_ty = try sema.resolveType(block, src, first_field_type_extra.container_type);
+ try sema.resolveTypeLayout(block, src, resolved_ty);
if (resolved_ty.zigTypeTag() == .Struct) {
// This logic must be synchronized with that in `zirStructInitEmpty`.
@@ -17017,14 +17030,14 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
const payload_val = union_val.val.optionalValue() orelse
return sema.addType(Type.initTag(.anyerror));
const slice_val = payload_val.castTag(.slice).?.data;
- const decl_index = slice_val.ptr.pointerDecl().?;
- try sema.ensureDeclAnalyzed(decl_index);
- const decl = mod.declPtr(decl_index);
- const array_val: []Value = if (decl.val.castTag(.aggregate)) |some| some.data else &.{};
+ const len = try sema.usizeCast(block, src, slice_val.len.toUnsignedInt(mod.getTarget()));
var names: Module.ErrorSet.NameMap = .{};
- try names.ensureUnusedCapacity(sema.arena, array_val.len);
- for (array_val) |elem_val| {
+ try names.ensureUnusedCapacity(sema.arena, len);
+ var i: usize = 0;
+ while (i < len) : (i += 1) {
+ var buf: Value.ElemValueBuffer = undefined;
+ const elem_val = slice_val.ptr.elemValueBuffer(mod, i, &buf);
const struct_val = elem_val.castTag(.aggregate).?.data;
// TODO use reflection instead of magic numbers here
// error_set: type,
@@ -17416,14 +17429,14 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
var buf: Value.ToTypeBuffer = undefined;
const args_slice_val = args_val.castTag(.slice).?.data;
- const args_decl_index = args_slice_val.ptr.pointerDecl().?;
- try sema.ensureDeclAnalyzed(args_decl_index);
- const args_decl = mod.declPtr(args_decl_index);
- const args: []Value = if (args_decl.val.castTag(.aggregate)) |some| some.data else &.{};
- var param_types = try sema.arena.alloc(Type, args.len);
- var comptime_params = try sema.arena.alloc(bool, args.len);
+ const args_len = try sema.usizeCast(block, src, args_slice_val.len.toUnsignedInt(mod.getTarget()));
+ var param_types = try sema.arena.alloc(Type, args_len);
+ var comptime_params = try sema.arena.alloc(bool, args_len);
var noalias_bits: u32 = 0;
- for (args) |arg, i| {
+ var i: usize = 0;
+ while (i < args_len) : (i += 1) {
+ var arg_buf: Value.ElemValueBuffer = undefined;
+ const arg = args_slice_val.ptr.elemValueBuffer(mod, i, &arg_buf);
const arg_val = arg.castTag(.aggregate).?.data;
// TODO use reflection instead of magic numbers here
// is_generic: bool,
@@ -20841,9 +20854,9 @@ fn validateExternType(
.Opaque,
.Bool,
.Float,
- .Pointer,
.AnyFrame,
=> return true,
+ .Pointer => return !ty.isSlice(),
.Int => switch (ty.intInfo(sema.mod.getTarget()).bits) {
8, 16, 32, 64, 128 => return true,
else => return false,
@@ -20886,7 +20899,6 @@ fn explainWhyTypeIsNotExtern(
.Opaque,
.Bool,
.Float,
- .Pointer,
.AnyFrame,
=> return,
@@ -20902,6 +20914,7 @@ fn explainWhyTypeIsNotExtern(
.Frame,
=> return,
+ .Pointer => try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}),
.Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
.NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
.Int => if (ty.intInfo(sema.mod.getTarget()).bits > 128) {
@@ -20960,11 +20973,11 @@ fn validatePackedType(ty: Type) bool {
.Void,
.Bool,
.Float,
- .Pointer,
.Int,
.Vector,
.Enum,
=> return true,
+ .Pointer => return !ty.isSlice(),
.Struct, .Union => return ty.containerLayout() == .Packed,
}
}
@@ -20980,7 +20993,6 @@ fn explainWhyTypeIsNotPacked(
.Void,
.Bool,
.Float,
- .Pointer,
.Int,
.Vector,
.Enum,
@@ -21001,6 +21013,7 @@ fn explainWhyTypeIsNotPacked(
.Optional,
.Array,
=> try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{}),
+ .Pointer => try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}),
.Fn => {
try mod.errNoteNonLazy(src_loc, msg, "type has no guaranteed in-memory representation", .{});
try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{});
@@ -22027,6 +22040,7 @@ fn structFieldPtrByIndex(
var ptr_ty_data: Type.Payload.Pointer.Data = .{
.pointee_type = field.ty,
.mutable = struct_ptr_ty_info.mutable,
+ .@"volatile" = struct_ptr_ty_info.@"volatile",
.@"addrspace" = struct_ptr_ty_info.@"addrspace",
};
@@ -22246,6 +22260,7 @@ fn unionFieldPtr(
const ptr_field_ty = try Type.ptr(arena, sema.mod, .{
.pointee_type = field.ty,
.mutable = union_ptr_ty.ptrIsMutable(),
+ .@"volatile" = union_ptr_ty.isVolatilePtr(),
.@"addrspace" = union_ptr_ty.ptrAddressSpace(),
});
const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
@@ -22568,6 +22583,7 @@ fn tupleFieldPtr(
const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{
.pointee_type = field_ty,
.mutable = tuple_ptr_ty.ptrIsMutable(),
+ .@"volatile" = tuple_ptr_ty.isVolatilePtr(),
.@"addrspace" = tuple_ptr_ty.ptrAddressSpace(),
});
@@ -23011,9 +23027,37 @@ fn coerceExtra(
const dest_is_mut = dest_info.mutable;
const dst_elem_type = dest_info.pointee_type;
- switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) {
+ const elem_res = try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src);
+ switch (elem_res) {
.ok => {},
- else => break :src_array_ptr,
+ else => {
+ in_memory_result = .{ .ptr_child = .{
+ .child = try elem_res.dupe(sema.arena),
+ .actual = array_elem_type,
+ .wanted = dst_elem_type,
+ } };
+ break :src_array_ptr;
+ },
+ }
+
+ if (dest_info.sentinel) |dest_sent| {
+ if (array_ty.sentinel()) |inst_sent| {
+ if (!dest_sent.eql(inst_sent, dst_elem_type, sema.mod)) {
+ in_memory_result = .{ .ptr_sentinel = .{
+ .actual = inst_sent,
+ .wanted = dest_sent,
+ .ty = dst_elem_type,
+ } };
+ break :src_array_ptr;
+ }
+ } else {
+ in_memory_result = .{ .ptr_sentinel = .{
+ .actual = Value.initTag(.unreachable_value),
+ .wanted = dest_sent,
+ .ty = dst_elem_type,
+ } };
+ break :src_array_ptr;
+ }
}
switch (dest_info.size) {
@@ -23027,17 +23071,7 @@ fn coerceExtra(
},
.Many => {
// *[N]T to [*]T
- // *[N:s]T to [*:s]T
- // *[N:s]T to [*]T
- if (dest_info.sentinel) |dst_sentinel| {
- if (array_ty.sentinel()) |src_sentinel| {
- if (src_sentinel.eql(dst_sentinel, dst_elem_type, sema.mod)) {
- return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
- }
- }
- } else {
- return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
- }
+ return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
},
.One => {},
}
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
@@ -5972,7 +5972,9 @@ pub const FuncGen = struct {
}
if (!std.mem.eql(u8, name, "_")) {
- name_map.putAssumeCapacityNoClobber(name, total_i);
+ const gop = name_map.getOrPutAssumeCapacity(name);
+ if (gop.found_existing) return self.todo("duplicate asm output name '{s}'", .{name});
+ gop.value_ptr.* = total_i;
}
total_i += 1;
}
@@ -6028,7 +6030,9 @@ pub const FuncGen = struct {
}
if (!std.mem.eql(u8, name, "_")) {
- name_map.putAssumeCapacityNoClobber(name, total_i);
+ const gop = name_map.getOrPutAssumeCapacity(name);
+ if (gop.found_existing) return self.todo("duplicate asm input name '{s}'", .{name});
+ gop.value_ptr.* = total_i;
}
// In the case of indirect inputs, LLVM requires the callsite to have
diff --git a/test/behavior.zig b/test/behavior.zig
@@ -93,6 +93,10 @@ test {
_ = @import("behavior/bugs/12794.zig");
_ = @import("behavior/bugs/12801-1.zig");
_ = @import("behavior/bugs/12801-2.zig");
+ _ = @import("behavior/bugs/12885.zig");
+ _ = @import("behavior/bugs/12911.zig");
+ _ = @import("behavior/bugs/12928.zig");
+ _ = @import("behavior/bugs/12945.zig");
_ = @import("behavior/byteswap.zig");
_ = @import("behavior/byval_arg_var.zig");
_ = @import("behavior/call.zig");
diff --git a/test/behavior/bugs/12885.zig b/test/behavior/bugs/12885.zig
@@ -0,0 +1,36 @@
+const std = @import("std");
+const builtin = std.builtin;
+const expect = std.testing.expect;
+
+const info = .{
+ .args = [_]builtin.Type.Error{
+ .{ .name = "bar" },
+ },
+};
+const Foo = @Type(.{
+ .ErrorSet = &info.args,
+});
+test "ErrorSet comptime_field_ptr" {
+ if (@import("builtin").zig_backend == .stage1) return error.SkipZigTest;
+
+ try expect(Foo == error{bar});
+}
+
+const fn_info = .{
+ .args = [_]builtin.Type.Fn.Param{
+ .{ .is_generic = false, .is_noalias = false, .arg_type = u8 },
+ },
+};
+const Bar = @Type(.{
+ .Fn = .{
+ .calling_convention = .Unspecified,
+ .alignment = 0,
+ .is_generic = false,
+ .is_var_args = false,
+ .return_type = void,
+ .args = &fn_info.args,
+ },
+});
+test "fn comptime_field_ptr" {
+ try expect(@typeInfo(Bar) == .Fn);
+}
diff --git a/test/behavior/bugs/12911.zig b/test/behavior/bugs/12911.zig
@@ -0,0 +1,11 @@
+const builtin = @import("builtin");
+
+const Item = struct { field: u8 };
+const Thing = struct {
+ array: [1]Item,
+};
+test {
+ if (builtin.zig_backend == .stage1) return error.SkipZigTest;
+
+ _ = Thing{ .array = undefined };
+}
diff --git a/test/behavior/bugs/12928.zig b/test/behavior/bugs/12928.zig
@@ -0,0 +1,26 @@
+const std = @import("std");
+const expect = std.testing.expect;
+const A = extern struct {
+ value: *volatile B,
+};
+const B = extern struct {
+ a: u32,
+ b: i32,
+};
+test {
+ var a: *A = undefined;
+ try expect(@TypeOf(&a.value.a) == *volatile u32);
+ try expect(@TypeOf(&a.value.b) == *volatile i32);
+}
+const C = extern struct {
+ value: *volatile D,
+};
+const D = extern union {
+ a: u32,
+ b: i32,
+};
+test {
+ var c: *C = undefined;
+ try expect(@TypeOf(&c.value.a) == *volatile u32);
+ try expect(@TypeOf(&c.value.b) == *volatile i32);
+}
diff --git a/test/behavior/bugs/12945.zig b/test/behavior/bugs/12945.zig
@@ -0,0 +1,13 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+fn A(
+ comptime T: type,
+ comptime destroycb: ?*const fn (?*T) callconv(.C) void,
+) !void {
+ try expect(destroycb == null);
+}
+
+test {
+ try A(u32, null);
+}
diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig
@@ -369,3 +369,16 @@ test "extern function used as generic parameter" {
};
try expect(S.baz(S.foo) != S.baz(S.bar));
}
+
+test "generic struct as parameter type" {
+ const S = struct {
+ fn doTheTest(comptime Int: type, thing: struct { int: Int }) !void {
+ try expect(thing.int == 123);
+ }
+ fn doTheTest2(comptime Int: type, comptime thing: struct { int: Int }) !void {
+ try expect(thing.int == 456);
+ }
+ };
+ try S.doTheTest(u32, .{ .int = 123 });
+ try S.doTheTest2(i32, .{ .int = 456 });
+}
diff --git a/test/behavior/typename.zig b/test/behavior/typename.zig
@@ -246,3 +246,28 @@ test "comptime parameters not converted to anytype in function type" {
const T = fn (fn (type) void, void) void;
try expectEqualStrings("fn(comptime fn(comptime type) void, void) void", @typeName(T));
}
+
+test "anon name strategy used in sub expression" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 uses line/column for the names but we're moving away from that for
+ // incremental compilation purposes.
+ return error.SkipZigTest;
+ }
+
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn getTheName() []const u8 {
+ return struct {
+ const name = @typeName(@This());
+ }.name;
+ }
+ };
+ try expectEqualStringsIgnoreDigits(
+ "behavior.typename.test.anon name strategy used in sub expression.S.getTheName__struct_0",
+ S.getTheName(),
+ );
+}
diff --git a/test/cases/compile_errors/implicit_array_ptr_cast_sentinel_mismatch.zig b/test/cases/compile_errors/implicit_array_ptr_cast_sentinel_mismatch.zig
@@ -0,0 +1,23 @@
+fn foo() [:0xff]const u8 {
+ return "bark";
+}
+fn bar() [:0]const u16 {
+ return "bark";
+}
+pub export fn entry() void {
+ _ = foo();
+}
+pub export fn entry1() void {
+ _ = bar();
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :2:12: error: expected type '[:255]const u8', found '*const [4:0]u8'
+// :2:12: note: pointer sentinel '0' cannot cast into pointer sentinel '255'
+// :1:10: note: function return type declared here
+// :5:12: error: expected type '[:0]const u16', found '*const [4:0]u8'
+// :5:12: note: pointer type child 'u8' cannot cast into pointer type child 'u16'
+// :4:10: note: function return type declared here
diff --git a/test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig b/test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig
@@ -60,6 +60,11 @@ const U = extern union {
A: i32,
B: u32,
};
+export fn entry12() void {
+ _ = @sizeOf(packed struct {
+ x: packed struct { a: []u8 },
+ });
+}
// error
// backend=llvm
@@ -82,3 +87,5 @@ const U = extern union {
// :38:9: error: packed structs cannot contain fields of type 'fn() void'
// :38:9: note: type has no guaranteed in-memory representation
// :38:9: note: use '*const ' to make a function pointer type
+// :65:28: error: packed structs cannot contain fields of type '[]u8'
+// :65:28: note: slices have no guaranteed in-memory representation
diff --git a/test/cases/compile_errors/slice_used_as_extern_fn_param.zig b/test/cases/compile_errors/slice_used_as_extern_fn_param.zig
@@ -0,0 +1,11 @@
+extern fn Text(str: []const u8, num: i32) callconv(.C) void;
+export fn entry() void {
+ _ = Text;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :1:16: error: parameter of type '[]const u8' not allowed in function with calling convention 'C'
+// :1:16: note: slices have no guaranteed in-memory representation