diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 684432bd40..56fab05d88 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -1006,6 +1006,7 @@ pub const panic_messages = struct { pub const for_len_mismatch = "for loop over objects with non-equal lengths"; pub const memcpy_len_mismatch = "@memcpy arguments have non-equal lengths"; pub const memcpy_alias = "@memcpy arguments alias"; + pub const noreturn_returned = "'noreturn' function returned"; }; pub noinline fn returnError(st: *StackTrace) void { diff --git a/lib/std/crypto/aes/soft.zig b/lib/std/crypto/aes/soft.zig index 7a8e7ff0ec..4c2a8ff80d 100644 --- a/lib/std/crypto/aes/soft.zig +++ b/lib/std/crypto/aes/soft.zig @@ -739,9 +739,9 @@ inline fn table_lookup(table: *align(64) const [4][256]u32, idx0: u8, idx1: u8, std.mem.doNotOptimizeAway(t); return [4]u32{ t[0][idx0 / stride], - math.rotl(u32, t[1][idx1 / stride], 8), - math.rotl(u32, t[2][idx2 / stride], 16), - math.rotl(u32, t[3][idx3 / stride], 24), + math.rotl(u32, (&t[1])[idx1 / stride], 8), + math.rotl(u32, (&t[2])[idx2 / stride], 16), + math.rotl(u32, (&t[3])[idx3 / stride], 24), }; } } diff --git a/src/Sema.zig b/src/Sema.zig index 78f7a0bce6..138c19acf4 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7080,15 +7080,38 @@ fn analyzeCall( } }, }); sema.appendRefsAssumeCapacity(args); + + if (call_tag == .call_always_tail) { + if (ensure_result_used) { + try sema.ensureResultUsed(block, sema.typeOf(func_inst), call_src); + } + return sema.handleTailCall(block, call_src, func_ty, func_inst); + } else if (block.wantSafety() and func_ty_info.return_type.isNoReturn()) { + // Function pointers and extern functions aren't guaranteed to + // actually be noreturn so we add a safety check for them. + check: { + var func_val = (try sema.resolveMaybeUndefVal(func)) orelse break :check; + switch (func_val.tag()) { + .function, .decl_ref => { + _ = try block.addNoOp(.unreach); + return Air.Inst.Ref.unreachable_value; + }, + else => break :check, + } + } + + try sema.safetyPanic(block, .noreturn_returned); + return Air.Inst.Ref.unreachable_value; + } else if (func_ty_info.return_type.isNoReturn()) { + _ = try block.addNoOp(.unreach); + return Air.Inst.Ref.unreachable_value; + } break :res func_inst; }; if (ensure_result_used) { try sema.ensureResultUsed(block, sema.typeOf(result), call_src); } - if (call_tag == .call_always_tail) { - return sema.handleTailCall(block, call_src, func_ty, result); - } return result; } @@ -7581,6 +7604,10 @@ fn instantiateGenericCall( if (call_tag == .call_always_tail) { return sema.handleTailCall(block, call_src, func_ty, result); } + if (new_fn_info.return_type.isNoReturn()) { + _ = try block.addNoOp(.unreach); + return Air.Inst.Ref.unreachable_value; + } return result; } @@ -23440,6 +23467,7 @@ pub const PanicId = enum { for_len_mismatch, memcpy_len_mismatch, memcpy_alias, + noreturn_returned, }; fn addSafetyCheck( @@ -23607,7 +23635,7 @@ fn panicIndexOutOfBounds( try sema.safetyCheckFormatted(parent_block, ok, "panicOutOfBounds", &.{ index, len }); } -fn panicStartLargerThanEnd( +fn panicStartGreaterThanEnd( sema: *Sema, parent_block: *Block, start: Air.Inst.Ref, @@ -29464,8 +29492,10 @@ fn analyzeSlice( const slice_sentinel = if (sentinel_opt != .none) sentinel else null; // requirement: start <= end + var need_start_gt_end_check = true; if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { + need_start_gt_end_check = false; if (!by_length and !(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { return sema.fail( block, @@ -29519,9 +29549,9 @@ fn analyzeSlice( } } - if (!by_length and block.wantSafety() and !block.is_comptime) { + if (!by_length and block.wantSafety() and !block.is_comptime and need_start_gt_end_check) { // requirement: start <= end - try sema.panicStartLargerThanEnd(block, start, end); + try sema.panicStartGreaterThanEnd(block, start, end); } const new_len = if (by_length) try sema.coerce(block, Type.usize, uncasted_end_opt, end_src) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 0873da5d66..0c8539eff5 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -5030,7 +5030,6 @@ pub const FuncGen = struct { } if (return_type.isNoReturn() and attr != .AlwaysTail) { - _ = self.builder.buildUnreachable(); return null; } diff --git a/test/cases/safety/noreturn returned.zig b/test/cases/safety/noreturn returned.zig new file mode 100644 index 0000000000..c3c30af37e --- /dev/null +++ b/test/cases/safety/noreturn returned.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, "'noreturn' function returned")) { + std.process.exit(0); + } + std.process.exit(1); +} +const T = struct { + export fn bar() void { + // ... + } +}; + +extern fn bar() noreturn; +pub fn main() void { + _ = T.bar; + bar(); +} +// run +// backend=llvm +// target=native