diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 898ae314d9084e35fed670b03854959ec06beead..faeed5f667c9a8dc4ec0f38ef2a829b5f42dff3c 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -207,6 +207,10 @@ pub fn FullPanic(comptime panicFn: fn ([]const u8, ?usize) noreturn) type { @branchHint(.cold); call("'noreturn' function returned", @returnAddress()); } + pub fn loadUninstantiableType() noreturn { + @branchHint(.cold); + call("attempt to load uninstantiable type", @returnAddress()); + } }; } diff --git a/lib/std/debug/no_panic.zig b/lib/std/debug/no_panic.zig index f24317b9b7d66ae9076df3d4790cfa88d47e1a26..d47c9799a990e0d53cdf61e735b008deb355fd44 100644 --- a/lib/std/debug/no_panic.zig +++ b/lib/std/debug/no_panic.zig @@ -134,3 +134,8 @@ pub fn noreturnReturned() noreturn { @branchHint(.cold); @trap(); } + +pub fn loadUninstantiableType() noreturn { + @branchHint(.cold); + @trap(); +} diff --git a/lib/std/debug/simple_panic.zig b/lib/std/debug/simple_panic.zig index a5a09fa1162e75cf9aad5a69a1bfcd3a3e1845d9..af7231251aa0e9bd94ef1eef36280d110b4d2019 100644 --- a/lib/std/debug/simple_panic.zig +++ b/lib/std/debug/simple_panic.zig @@ -126,3 +126,7 @@ pub fn memcpyAlias() noreturn { pub fn noreturnReturned() noreturn { call("'noreturn' function returned", null); } + +pub fn loadUninstantiableType() noreturn { + call("attempt to load uninstantiable type", null); +} diff --git a/src/Sema.zig b/src/Sema.zig index 1b81e7653ea9d8586e8c887978078c9a97ba6925..96bb93f02bcd78185e14c04f40ab832fc09868b4 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -31040,7 +31040,18 @@ fn analyzeLoad( const comptime_only = switch (elem_ty.classify(zcu)) { .no_possible_value => switch (elem_ty.zigTypeTag(zcu)) { .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}), - else => return sema.fail(block, src, "cannot load uninstantiable type '{f}'", .{elem_ty.fmt(pt)}), + else => { + // Loading an uninstantiable type always invokes Illegal Behavior. + if (block.isComptime()) { + return sema.fail(block, src, "cannot load uninstantiable type '{f}'", .{elem_ty.fmt(pt)}); + } else if (block.wantSafety()) { + try sema.safetyPanic(block, src, .load_uninstantiable_type); + return .unreachable_value; + } else { + _ = try block.addNoOp(.unreach); + return .unreachable_value; + } + }, }, .one_possible_value => return .fromValue((try elem_ty.onePossibleValue(pt)).?), .runtime => false, @@ -35059,12 +35070,60 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.StdLangDecl) CompileError!Typ .@"panic.copyLenMismatch", .@"panic.memcpyAlias", .@"panic.noreturnReturned", + .@"panic.loadUninstantiableType", => try pt.funcType(.{ .param_types = &.{}, .return_type = .noreturn_type, }), - else => unreachable, + .StackTrace, + .CallingConvention, + .SourceLocation, + .Signedness, + .AddressSpace, + .VaList, + .CallModifier, + .AtomicOrder, + .AtomicRmwOp, + .ReduceOp, + .FloatMode, + .PrefetchOptions, + .ExportOptions, + .ExternOptions, + .BranchHint, + .assembly, + .@"assembly.Clobbers", + .Type, + .@"Type.Fn", + .@"Type.Fn.ParamAttributes", + .@"Type.Fn.Attributes", + .@"Type.Int", + .@"Type.Float", + .@"Type.Pointer", + .@"Type.Pointer.Size", + .@"Type.Pointer.Attributes", + .@"Type.Array", + .@"Type.Vector", + .@"Type.Optional", + .@"Type.ErrorUnion", + .@"Type.ErrorSet", + .@"Type.Enum", + .@"Type.Enum.Mode", + .@"Type.Union", + .@"Type.Union.FieldAttributes", + .@"Type.Struct", + .@"Type.Struct.FieldAttributes", + .@"Type.ContainerLayout", + .@"Type.Opaque", + .@"Type.Spirv", + .@"Type.Spirv.Image", + .@"Type.Spirv.Image.Usage", + .@"Type.Spirv.Image.Format", + .@"Type.Spirv.Image.Dimensionality", + .@"Type.Spirv.Image.Depth", + .@"Type.Spirv.Image.Access", + .panic, + => unreachable, // not a function (`decl.kind() != .func`) }; } diff --git a/src/Zcu.zig b/src/Zcu.zig index 465506eb7b41dcbcb16620c7ef84dc8b5f406ea4..0c231862cb0720fec4419115e08b712eacbdcf6f 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -517,6 +517,7 @@ pub const StdLangDecl = enum { @"panic.copyLenMismatch", @"panic.memcpyAlias", @"panic.noreturnReturned", + @"panic.loadUninstantiableType", VaList, @@ -606,6 +607,7 @@ pub const StdLangDecl = enum { .@"panic.copyLenMismatch", .@"panic.memcpyAlias", .@"panic.noreturnReturned", + .@"panic.loadUninstantiableType", => .func, }; } @@ -679,6 +681,7 @@ pub const SimplePanicId = enum { copy_len_mismatch, memcpy_alias, noreturn_returned, + load_uninstantiable_type, pub fn toStdLangDecl(id: SimplePanicId) StdLangDecl { return switch (id) { @@ -702,6 +705,7 @@ pub const SimplePanicId = enum { .copy_len_mismatch => .@"panic.copyLenMismatch", .memcpy_alias => .@"panic.memcpyAlias", .noreturn_returned => .@"panic.noreturnReturned", + .load_uninstantiable_type => .@"panic.loadUninstantiableType", // zig fmt: on }; } diff --git a/test/cases/compile_errors/initialize_empty_union.zig b/test/cases/compile_errors/initialize_empty_union.zig index a7945a105b6d973411f6d2e31810ae6e5f7e595e..fe8203c1ed1873c2c4634eae13ab177ea079474d 100644 --- a/test/cases/compile_errors/initialize_empty_union.zig +++ b/test/cases/compile_errors/initialize_empty_union.zig @@ -28,25 +28,6 @@ export fn init5() void { _ = @as(U5, undefined); } -export fn deref0(ptr: *const U0) void { - _ = ptr.*; -} -export fn deref1(ptr: *const U1) void { - _ = ptr.*; -} -export fn deref2(ptr: *const U2) void { - _ = ptr.*; -} -export fn deref3(ptr: *const U3) void { - _ = ptr.*; -} -export fn deref4(ptr: *const U4) void { - _ = ptr.*; -} -export fn deref5(ptr: *const U5) void { - _ = ptr.*; -} - // error // // :13:17: error: expected type 'tmp.U0', found '@TypeOf(undefined)' @@ -67,15 +48,3 @@ export fn deref5(ptr: *const U5) void { // :28:17: error: expected type 'tmp.U5', found '@TypeOf(undefined)' // :28:17: note: cannot coerce to uninstantiable type 'tmp.U5' // :10:12: note: union declared here -// :32:12: error: cannot load uninstantiable type 'tmp.U0' -// :5:12: note: union declared here -// :35:12: error: cannot load uninstantiable type 'tmp.U1' -// :6:12: note: union declared here -// :38:12: error: cannot load uninstantiable type 'tmp.U2' -// :7:12: note: union declared here -// :41:12: error: cannot load uninstantiable type 'tmp.U3' -// :8:12: note: union declared here -// :44:12: error: cannot load uninstantiable type 'tmp.U4' -// :9:12: note: union declared here -// :47:12: error: cannot load uninstantiable type 'tmp.U5' -// :10:12: note: union declared here diff --git a/test/cases/safety/load_uninstantiable_enum.zig b/test/cases/safety/load_uninstantiable_enum.zig new file mode 100644 index 0000000000000000000000000000000000000000..91a26417b689a0f06ae1ed1462bffdab5366cd30 --- /dev/null +++ b/test/cases/safety/load_uninstantiable_enum.zig @@ -0,0 +1,20 @@ +const std = @import("std"); + +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { + _ = stack_trace; + if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +const E = enum {}; +pub fn main() error{TestFailed}!void { + const bytes: [32]u8 = @splat(0); + const ptr: *const E = @ptrCast(&bytes); + _ = ptr.*; + return error.TestFailed; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux,wasm32-wasi diff --git a/test/cases/safety/load_uninstantiable_enum_from_slice.zig b/test/cases/safety/load_uninstantiable_enum_from_slice.zig new file mode 100644 index 0000000000000000000000000000000000000000..57c308f8f6b15ca4f61eb36a3da0c246b6831dd8 --- /dev/null +++ b/test/cases/safety/load_uninstantiable_enum_from_slice.zig @@ -0,0 +1,21 @@ +const std = @import("std"); + +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { + _ = stack_trace; + if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +const E = enum {}; +pub fn main() error{TestFailed}!void { + const bytes: [32]u8 = @splat(0); + const ptr: *const [1]E = @ptrCast(&bytes); + const slice: []const E = ptr; + _ = slice[0]; + return error.TestFailed; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux,wasm32-wasi diff --git a/test/cases/safety/load_uninstantiable_union.zig b/test/cases/safety/load_uninstantiable_union.zig new file mode 100644 index 0000000000000000000000000000000000000000..87f84e07c7f624104d797b94037fc6148491265b --- /dev/null +++ b/test/cases/safety/load_uninstantiable_union.zig @@ -0,0 +1,23 @@ +const std = @import("std"); + +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { + _ = stack_trace; + if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +const U = union { + foo: struct { a: u8, b: noreturn, }, + bar: enum {}, +}; +pub fn main() error{TestFailed}!void { + const bytes: [32]u8 = @splat(0); + const ptr: *const U = @ptrCast(&bytes); + _ = ptr.*; + return error.TestFailed; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux,wasm32-wasi diff --git a/test/cases/safety/load_uninstantiable_union_from_slice.zig b/test/cases/safety/load_uninstantiable_union_from_slice.zig new file mode 100644 index 0000000000000000000000000000000000000000..844bfd0b7d766bfb9e5eb0f911061eda7bace0d6 --- /dev/null +++ b/test/cases/safety/load_uninstantiable_union_from_slice.zig @@ -0,0 +1,24 @@ +const std = @import("std"); + +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { + _ = stack_trace; + if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +const U = union { + foo: struct { a: u8, b: noreturn, }, + bar: enum {}, +}; +pub fn main() error{TestFailed}!void { + const bytes: [32]u8 = @splat(0); + const ptr: *const [1]U = @ptrCast(&bytes); + const slice: []const U = ptr; + _ = slice[0]; + return error.TestFailed; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux,wasm32-wasi diff --git a/test/incremental/change_panic_handler_explicit b/test/incremental/change_panic_handler_explicit index 662d13847f9800553b41fca4e9545e3bc07dbb17..f748a57afc43e7d18e5458549a18c173d21dc56c 100644 --- a/test/incremental/change_panic_handler_explicit +++ b/test/incremental/change_panic_handler_explicit @@ -36,6 +36,7 @@ pub const panic = struct { pub const copyLenMismatch = no_panic.copyLenMismatch; pub const memcpyAlias = no_panic.memcpyAlias; pub const noreturnReturned = no_panic.noreturnReturned; + pub const loadUninstantiableType = no_panic.loadUninstantiableType; }; fn myPanic(msg: []const u8, _: ?usize) noreturn { var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); @@ -84,6 +85,7 @@ pub const panic = struct { pub const copyLenMismatch = no_panic.copyLenMismatch; pub const memcpyAlias = no_panic.memcpyAlias; pub const noreturnReturned = no_panic.noreturnReturned; + pub const loadUninstantiableType = no_panic.loadUninstantiableType; }; fn myPanic(msg: []const u8, _: ?usize) noreturn { var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{}); @@ -132,6 +134,7 @@ pub const panic = struct { pub const copyLenMismatch = no_panic.copyLenMismatch; pub const memcpyAlias = no_panic.memcpyAlias; pub const noreturnReturned = no_panic.noreturnReturned; + pub const loadUninstantiableType = no_panic.loadUninstantiableType; }; fn myPanicNew(msg: []const u8, _: ?usize) noreturn { var stdout_writer = std.Io.File.stdout().writerStreaming(io, &.{});