| author | |
| committer | |
| log | baed9626d075628887b7d5400fb03efcb9910050 |
| tree | 4336a378943bb93ba71157cb2c3bece03378cd21 |
| parent | 07ea1c97ee891ea259020fe28fba317c20c3b03a |
10 files changed, 176 insertions(+), 47 deletions(-)
src/Sema.zig+19-1| ... | ... | @@ -27920,7 +27920,25 @@ fn elemValSlice( |
| 27920 | 27920 | } |
| 27921 | 27921 | } |
| 27922 | 27922 | |
| 27923 | if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 27923 | switch (elem_ty.classify(zcu)) { | |
| 27924 | .no_possible_value => switch (elem_ty.zigTypeTag(zcu)) { | |
| 27925 | .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{elem_ty.fmt(zcu)}), | |
| 27926 | else => { | |
| 27927 | // Loading an uninstantiable type always invokes Illegal Behavior. | |
| 27928 | if (block.isComptime()) { | |
| 27929 | return sema.fail(block, src, "cannot load uninstantiable type '{f}'", .{elem_ty.fmt(zcu)}); | |
| 27930 | } else if (block.wantSafety()) { | |
| 27931 | try sema.safetyPanic(block, src, .load_uninstantiable_type); | |
| 27932 | return .unreachable_value; | |
| 27933 | } else { | |
| 27934 | _ = try block.addNoOp(.unreach); | |
| 27935 | return .unreachable_value; | |
| 27936 | } | |
| 27937 | }, | |
| 27938 | }, | |
| 27939 | .one_possible_value => return .fromValue((try elem_ty.onePossibleValue(pt)).?), | |
| 27940 | .runtime, .partially_comptime, .fully_comptime => {}, | |
| 27941 | } | |
| 27924 | 27942 | |
| 27925 | 27943 | try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_src); |
| 27926 | 27944 | try sema.validateRuntimeValue(block, slice_src, slice); |
test/behavior/slice.zig+18| ... | ... | @@ -1209,3 +1209,21 @@ test "modify slice through coerced array pointer" { |
| 1209 | 1209 | assert(slice[2] == 0); |
| 1210 | 1210 | } |
| 1211 | 1211 | } |
| 1212 | ||
| 1213 | test "iterate empty slice of uninstantiable types" { | |
| 1214 | const E = enum {}; | |
| 1215 | var slice_enum: []const E = undefined; | |
| 1216 | slice_enum = &.{}; | |
| 1217 | for (slice_enum) |elem| { | |
| 1218 | _ = elem; | |
| 1219 | return error.ReachedUnreachable; | |
| 1220 | } | |
| 1221 | ||
| 1222 | const U = union { foo: struct { a: u8, b: noreturn }, bar: E }; | |
| 1223 | var slice_union: []const U = undefined; | |
| 1224 | slice_union = &.{}; | |
| 1225 | for (slice_union) |elem| { | |
| 1226 | _ = elem; | |
| 1227 | return error.ReachedUnreachable; | |
| 1228 | } | |
| 1229 | } |
test/cases/compile_errors/load_uninstantiable_type.zig created+48| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | const E = enum {}; | |
| 2 | const U = union { | |
| 3 | foo: struct { a: u8, b: noreturn }, | |
| 4 | bar: E, | |
| 5 | }; | |
| 6 | export fn loadSliceUninstantiableEnum() void { | |
| 7 | const bytes: [32]u8 = @splat(0); | |
| 8 | const ptr: *const [1]E = @ptrCast(&bytes); | |
| 9 | const slice: []const E = ptr; | |
| 10 | _ = comptime slice[0]; | |
| 11 | comptime unreachable; | |
| 12 | } | |
| 13 | export fn iterateSliceUninstantiableEnum() void { | |
| 14 | const bytes: [32]u8 = @splat(0); | |
| 15 | const ptr: *const [1]E = @ptrCast(&bytes); | |
| 16 | const slice: []const E = ptr; | |
| 17 | comptime for (slice) |elem| { | |
| 18 | _ = elem; | |
| 19 | }; | |
| 20 | comptime unreachable; | |
| 21 | } | |
| 22 | export fn loadSliceUninstantiableUnion() void { | |
| 23 | const bytes: [32]u8 = @splat(0); | |
| 24 | const ptr: *const [1]U = @ptrCast(&bytes); | |
| 25 | const slice: []const U = ptr; | |
| 26 | _ = comptime slice[0]; | |
| 27 | comptime unreachable; | |
| 28 | } | |
| 29 | export fn iterateSliceUninstantiableUnion() void { | |
| 30 | const bytes: [32]u8 = @splat(0); | |
| 31 | const ptr: *const [1]U = @ptrCast(&bytes); | |
| 32 | const slice: []const U = ptr; | |
| 33 | comptime for (slice) |elem| { | |
| 34 | _ = elem; | |
| 35 | }; | |
| 36 | comptime unreachable; | |
| 37 | } | |
| 38 | ||
| 39 | // error | |
| 40 | // | |
| 41 | // :10:23: error: cannot load uninstantiable type 'tmp.E' | |
| 42 | // :1:11: note: enum declared here | |
| 43 | // :17:19: error: cannot load uninstantiable type 'tmp.E' | |
| 44 | // :1:11: note: enum declared here | |
| 45 | // :26:23: error: cannot load uninstantiable type 'tmp.U' | |
| 46 | // :2:11: note: union declared here | |
| 47 | // :33:19: error: cannot load uninstantiable type 'tmp.U' | |
| 48 | // :2:11: note: union declared here |
test/cases/safety/iterate_slice_uninstantiable_enum.zig created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { | |
| 4 | _ = stack_trace; | |
| 5 | if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { | |
| 6 | std.process.exit(0); | |
| 7 | } | |
| 8 | std.process.exit(1); | |
| 9 | } | |
| 10 | ||
| 11 | const E = enum {}; | |
| 12 | pub fn main() error{TestFailed}!void { | |
| 13 | const bytes: [32]u8 = @splat(0); | |
| 14 | const ptr: *const [1]E = @ptrCast(&bytes); | |
| 15 | const slice: []const E = ptr; | |
| 16 | for (slice) |elem| _ = elem; | |
| 17 | return error.TestFailed; | |
| 18 | } | |
| 19 | // run | |
| 20 | // backend=selfhosted,llvm | |
| 21 | // target=x86_64-linux,aarch64-linux,wasm32-wasi |
test/cases/safety/iterate_slice_uninstantiable_union.zig created+24| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { | |
| 4 | _ = stack_trace; | |
| 5 | if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { | |
| 6 | std.process.exit(0); | |
| 7 | } | |
| 8 | std.process.exit(1); | |
| 9 | } | |
| 10 | ||
| 11 | const U = union { | |
| 12 | foo: struct { a: u8, b: noreturn }, | |
| 13 | bar: enum {}, | |
| 14 | }; | |
| 15 | pub fn main() error{TestFailed}!void { | |
| 16 | const bytes: [32]u8 = @splat(0); | |
| 17 | const ptr: *const [1]U = @ptrCast(&bytes); | |
| 18 | const slice: []const U = ptr; | |
| 19 | for (slice) |elem| _ = elem; | |
| 20 | return error.TestFailed; | |
| 21 | } | |
| 22 | // run | |
| 23 | // backend=selfhosted,llvm | |
| 24 | // target=x86_64-linux,aarch64-linux,wasm32-wasi |
test/cases/safety/load_slice_uninstantiable_enum.zig created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { | |
| 4 | _ = stack_trace; | |
| 5 | if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { | |
| 6 | std.process.exit(0); | |
| 7 | } | |
| 8 | std.process.exit(1); | |
| 9 | } | |
| 10 | ||
| 11 | const E = enum {}; | |
| 12 | pub fn main() error{TestFailed}!void { | |
| 13 | const bytes: [32]u8 = @splat(0); | |
| 14 | const ptr: *const [1]E = @ptrCast(&bytes); | |
| 15 | const slice: []const E = ptr; | |
| 16 | _ = slice[0]; | |
| 17 | return error.TestFailed; | |
| 18 | } | |
| 19 | // run | |
| 20 | // backend=selfhosted,llvm | |
| 21 | // target=x86_64-linux,aarch64-linux,wasm32-wasi |
test/cases/safety/load_slice_uninstantiable_union.zig created+24| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { | |
| 4 | _ = stack_trace; | |
| 5 | if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { | |
| 6 | std.process.exit(0); | |
| 7 | } | |
| 8 | std.process.exit(1); | |
| 9 | } | |
| 10 | ||
| 11 | const U = union { | |
| 12 | foo: struct { a: u8, b: noreturn }, | |
| 13 | bar: enum {}, | |
| 14 | }; | |
| 15 | pub fn main() error{TestFailed}!void { | |
| 16 | const bytes: [32]u8 = @splat(0); | |
| 17 | const ptr: *const [1]U = @ptrCast(&bytes); | |
| 18 | const slice: []const U = ptr; | |
| 19 | _ = slice[0]; | |
| 20 | return error.TestFailed; | |
| 21 | } | |
| 22 | // run | |
| 23 | // backend=selfhosted,llvm | |
| 24 | // target=x86_64-linux,aarch64-linux,wasm32-wasi |
test/cases/safety/load_uninstantiable_enum_from_slice.zig deleted-21| ... | ... | @@ -1,21 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { | |
| 4 | _ = stack_trace; | |
| 5 | if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { | |
| 6 | std.process.exit(0); | |
| 7 | } | |
| 8 | std.process.exit(1); | |
| 9 | } | |
| 10 | ||
| 11 | const E = enum {}; | |
| 12 | pub fn main() error{TestFailed}!void { | |
| 13 | const bytes: [32]u8 = @splat(0); | |
| 14 | const ptr: *const [1]E = @ptrCast(&bytes); | |
| 15 | const slice: []const E = ptr; | |
| 16 | _ = slice[0]; | |
| 17 | return error.TestFailed; | |
| 18 | } | |
| 19 | // run | |
| 20 | // backend=selfhosted,llvm | |
| 21 | // target=x86_64-linux,aarch64-linux,wasm32-wasi |
test/cases/safety/load_uninstantiable_union.zig+1-1| ... | ... | @@ -9,7 +9,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usi |
| 9 | 9 | } |
| 10 | 10 | |
| 11 | 11 | const U = union { |
| 12 | foo: struct { a: u8, b: noreturn, }, | |
| 12 | foo: struct { a: u8, b: noreturn }, | |
| 13 | 13 | bar: enum {}, |
| 14 | 14 | }; |
| 15 | 15 | pub fn main() error{TestFailed}!void { |
test/cases/safety/load_uninstantiable_union_from_slice.zig deleted-24| ... | ... | @@ -1,24 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { | |
| 4 | _ = stack_trace; | |
| 5 | if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { | |
| 6 | std.process.exit(0); | |
| 7 | } | |
| 8 | std.process.exit(1); | |
| 9 | } | |
| 10 | ||
| 11 | const U = union { | |
| 12 | foo: struct { a: u8, b: noreturn, }, | |
| 13 | bar: enum {}, | |
| 14 | }; | |
| 15 | pub fn main() error{TestFailed}!void { | |
| 16 | const bytes: [32]u8 = @splat(0); | |
| 17 | const ptr: *const [1]U = @ptrCast(&bytes); | |
| 18 | const slice: []const U = ptr; | |
| 19 | _ = slice[0]; | |
| 20 | return error.TestFailed; | |
| 21 | } | |
| 22 | // run | |
| 23 | // backend=selfhosted,llvm | |
| 24 | // target=x86_64-linux,aarch64-linux,wasm32-wasi |