Sema: improve new error messages related to naked functions

* pass a source location to all safety checks
 * add notes about what is disallowed in naked functions

Closes #16651
This commit is contained in:
Jacob Young 2023-08-02 15:17:51 -04:00 committed by Andrew Kelley
parent 9e19969e09
commit 89d660c3eb
4 changed files with 219 additions and 106 deletions

View File

@ -745,9 +745,9 @@ pub const Block = struct {
return result_index;
}
fn addUnreachable(block: *Block, safety_check: bool) !void {
fn addUnreachable(block: *Block, src: LazySrcLoc, safety_check: bool) !void {
if (safety_check and block.wantSafety()) {
try block.sema.safetyPanic(block, .unreach);
try block.sema.safetyPanic(block, src, .unreach);
} else {
_ = try block.addNoOp(.unreach);
}
@ -4304,7 +4304,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
if (arg_len == .none) continue;
if (i == len_idx) continue;
const ok = try block.addBinOp(.cmp_eq, len, arg_len);
try sema.addSafetyCheck(block, ok, .for_len_mismatch);
try sema.addSafetyCheck(block, src, ok, .for_len_mismatch);
}
}
@ -5442,7 +5442,7 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.I
if (block.is_comptime) {
return sema.fail(block, src, "encountered @panic at comptime", .{});
}
try sema.panicWithMsg(block, msg_inst);
try sema.panicWithMsg(block, src, msg_inst, .@"@panic");
return always_noreturn;
}
@ -6605,7 +6605,7 @@ fn zirCall(
!block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))
{
const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {
break :b try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
break :b try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node, .call);
};
const return_ty = sema.typeOf(call_inst);
@ -6635,11 +6635,11 @@ fn zirCall(
}
if (modifier == .always_tail) // Perform the call *after* the restore, so that a tail call is possible.
return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node, .call);
return call_inst;
} else {
return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node, .call);
}
}
@ -6719,9 +6719,11 @@ fn checkCallArgumentCount(
fn callBuiltin(
sema: *Sema,
block: *Block,
call_src: LazySrcLoc,
builtin_fn: Air.Inst.Ref,
modifier: std.builtin.CallModifier,
args: []const Air.Inst.Ref,
operation: CallOperation,
) !void {
const mod = sema.mod;
const callee_ty = sema.typeOf(builtin_fn);
@ -6744,9 +6746,17 @@ fn callBuiltin(
if (args.len != fn_params_len or (func_ty_info.is_var_args and args.len < fn_params_len)) {
std.debug.panic("parameter count mismatch calling builtin fn, expected {d}, found {d}", .{ fn_params_len, args.len });
}
_ = try sema.analyzeCall(block, builtin_fn, func_ty, sema.src, sema.src, modifier, false, args, null, null);
_ = try sema.analyzeCall(block, builtin_fn, func_ty, call_src, call_src, modifier, false, args, null, null, operation);
}
const CallOperation = enum {
call,
@"@call",
@"@panic",
@"safety check",
@"error return",
};
fn analyzeCall(
sema: *Sema,
block: *Block,
@ -6759,6 +6769,7 @@ fn analyzeCall(
uncasted_args: []const Air.Inst.Ref,
bound_arg_src: ?LazySrcLoc,
call_dbg_node: ?Zir.Inst.Index,
operation: CallOperation,
) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const ip = &mod.intern_pool;
@ -6830,7 +6841,17 @@ fn analyzeCall(
func_ty_info.cc == .Inline;
if (sema.func_is_naked and !is_inline_call and !is_comptime_call) {
return sema.fail(block, call_src, "runtime call not allowed in naked function", .{});
const msg = msg: {
const msg = try sema.errMsg(block, call_src, "runtime {s} not allowed in naked function", .{@tagName(operation)});
errdefer msg.destroy(sema.gpa);
switch (operation) {
.call, .@"@call", .@"@panic", .@"error return" => {},
.@"safety check" => try sema.errNote(block, call_src, msg, "use @setRuntimeSafety to disable runtime safety", .{}),
}
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
if (!is_inline_call and is_generic_call) {
@ -7281,7 +7302,7 @@ fn analyzeCall(
else => {},
}
}
try sema.safetyPanic(block, .noreturn_returned);
try sema.safetyPanic(block, call_src, .noreturn_returned);
return Air.Inst.Ref.unreachable_value;
}
if (func_ty_info.return_type == .noreturn_type) {
@ -7939,7 +7960,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
const zero_val = try sema.addConstant(try mod.intValue(Type.err_int, 0));
const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val);
const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero);
try sema.addSafetyCheck(block, ok, .invalid_error_code);
try sema.addSafetyCheck(block, src, ok, .invalid_error_code);
}
return block.addInst(.{
.tag = .bitcast,
@ -8131,7 +8152,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
mod.backendSupportsFeature(.is_named_enum_value))
{
const ok = try block.addUnOp(.is_named_enum_value, result);
try sema.addSafetyCheck(block, ok, .invalid_enum_value);
try sema.addSafetyCheck(block, src, ok, .invalid_enum_value);
}
return result;
}
@ -8207,7 +8228,7 @@ fn analyzeOptionalPayloadPtr(
try sema.requireRuntimeBlock(block, src, null);
if (safety_check and block.wantSafety()) {
const is_non_null = try block.addUnOp(.is_non_null_ptr, optional_ptr);
try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null);
}
const air_tag: Air.Inst.Tag = if (initializing)
.optional_payload_ptr_set
@ -8264,7 +8285,7 @@ fn zirOptionalPayload(
try sema.requireRuntimeBlock(block, src, null);
if (safety_check and block.wantSafety()) {
const is_non_null = try block.addUnOp(.is_non_null, operand);
try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null);
}
return block.addTyOp(.optional_payload, result_ty, operand);
}
@ -8318,7 +8339,7 @@ fn analyzeErrUnionPayload(
if (safety_check and block.wantSafety() and
!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod))
{
try sema.panicUnwrapError(block, operand, .unwrap_errunion_err, .is_non_err);
try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err);
}
return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand);
@ -8399,7 +8420,7 @@ fn analyzeErrUnionPayloadPtr(
if (safety_check and block.wantSafety() and
!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod))
{
try sema.panicUnwrapError(block, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
}
const air_tag: Air.Inst.Tag = if (initializing)
@ -9637,7 +9658,7 @@ fn intCast(
const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst);
break :ok is_in_range;
};
try sema.addSafetyCheck(block, ok, .cast_truncated_data);
try sema.addSafetyCheck(block, src, ok, .cast_truncated_data);
}
}
@ -9691,7 +9712,7 @@ fn intCast(
break :ok is_in_range;
};
// TODO negative_to_unsigned?
try sema.addSafetyCheck(block, ok, .cast_truncated_data);
try sema.addSafetyCheck(block, src, ok, .cast_truncated_data);
} else {
const ok = if (is_vector) ok: {
const is_in_range = try block.addCmpVector(diff, dest_max, .lte);
@ -9707,7 +9728,7 @@ fn intCast(
const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max);
break :ok is_in_range;
};
try sema.addSafetyCheck(block, ok, .cast_truncated_data);
try sema.addSafetyCheck(block, src, ok, .cast_truncated_data);
}
} else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) {
// no shrinkage, yes sign loss
@ -9730,7 +9751,7 @@ fn intCast(
const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);
break :ok is_in_range;
};
try sema.addSafetyCheck(block, ok, .negative_to_unsigned);
try sema.addSafetyCheck(block, src, ok, .negative_to_unsigned);
}
}
return block.addTyOp(.intcast, dest_ty, operand);
@ -10319,7 +10340,7 @@ const SwitchProngAnalysis = struct {
.ErrorSet => if (spa.else_error_ty) |ty| {
return sema.bitCast(block, ty, spa.operand, operand_src, null);
} else {
try block.addUnreachable(false);
try block.addUnreachable(operand_src, false);
return Air.Inst.Ref.unreachable_value;
},
else => return spa.operand,
@ -11475,7 +11496,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
if (special_prong == .none) {
return sema.fail(block, src, "switch must handle all possibilities", .{});
}
if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) {
if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand, operand_src)) {
return Air.Inst.Ref.unreachable_value;
}
if (mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag(mod) == .Enum and
@ -11483,7 +11504,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
{
try sema.zirDbgStmt(block, cond_dbg_node_index);
const ok = try block.addUnOp(.is_named_enum_value, operand);
try sema.addSafetyCheck(block, ok, .corrupt_switch);
try sema.addSafetyCheck(block, src, ok, .corrupt_switch);
}
return spa.resolveProngComptime(
@ -11543,7 +11564,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
break :blk field_ty.zigTypeTag(mod) != .NoReturn;
} else true;
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand, operand_src)) {
// nothing to do here
} else if (analyze_body) {
try spa.analyzeProngRuntime(
@ -11725,7 +11746,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
const body = sema.code.extra[extra_index..][0..info.body_len];
extra_index += info.body_len;
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand, operand_src)) {
// nothing to do here
} else if (analyze_body) {
try spa.analyzeProngRuntime(
@ -11812,7 +11833,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
const body = sema.code.extra[extra_index..][0..info.body_len];
extra_index += info.body_len;
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand, operand_src)) {
// nothing to do here
} else {
try spa.analyzeProngRuntime(
@ -12045,7 +12066,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
{
try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
const ok = try case_block.addUnOp(.is_named_enum_value, operand);
try sema.addSafetyCheck(&case_block, ok, .corrupt_switch);
try sema.addSafetyCheck(&case_block, src, ok, .corrupt_switch);
}
const analyze_body = if (union_originally and !special.is_inline)
@ -12058,7 +12079,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
else
true;
if (special.body.len != 0 and err_set and
try sema.maybeErrorUnwrap(&case_block, special.body, operand))
try sema.maybeErrorUnwrap(&case_block, special.body, operand, operand_src))
{
// nothing to do here
} else if (special.body.len != 0 and analyze_body and !special.is_inline) {
@ -12077,7 +12098,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
// that it is unreachable.
if (case_block.wantSafety()) {
try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
try sema.safetyPanic(&case_block, .corrupt_switch);
try sema.safetyPanic(&case_block, src, .corrupt_switch);
} else {
_ = try case_block.addNoOp(.unreach);
}
@ -12420,7 +12441,7 @@ fn validateSwitchNoRange(
return sema.failWithOwnedErrorMsg(msg);
}
fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool {
fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref, operand_src: LazySrcLoc) !bool {
const mod = sema.mod;
if (!mod.backendSupportsFeature(.panic_unwrap_error)) return false;
@ -12459,14 +12480,14 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op
.field_val => try sema.zirFieldVal(block, inst),
.@"unreachable" => {
if (!mod.comp.formatted_panics) {
try sema.safetyPanic(block, .unwrap_error);
try sema.safetyPanic(block, operand_src, .unwrap_error);
return true;
}
const panic_fn = try sema.getBuiltin("panicUnwrapError");
const err_return_trace = try sema.getErrorReturnTrace(block);
const args: [2]Air.Inst.Ref = .{ err_return_trace, operand };
try sema.callBuiltin(block, panic_fn, .auto, &args);
try sema.callBuiltin(block, operand_src, panic_fn, .auto, &args, .@"safety check");
return true;
},
.panic => {
@ -12476,7 +12497,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op
const panic_fn = try sema.getBuiltin("panic");
const err_return_trace = try sema.getErrorReturnTrace(block);
const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value };
try sema.callBuiltin(block, panic_fn, .auto, &args);
try sema.callBuiltin(block, operand_src, panic_fn, .auto, &args, .@"safety check");
return true;
},
else => unreachable,
@ -12851,7 +12872,7 @@ fn zirShl(
const bit_count_inst = try sema.addConstant(bit_count_val);
break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst);
};
try sema.addSafetyCheck(block, ok, .shift_rhs_too_big);
try sema.addSafetyCheck(block, src, ok, .shift_rhs_too_big);
}
if (air_tag == .shl_exact) {
@ -12880,7 +12901,7 @@ fn zirShl(
const zero_ov = try sema.addConstant(try mod.intValue(Type.u1, 0));
const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
try sema.addSafetyCheck(block, no_ov, .shl_overflow);
try sema.addSafetyCheck(block, src, no_ov, .shl_overflow);
return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
}
}
@ -13001,7 +13022,7 @@ fn zirShr(
const bit_count_inst = try sema.addConstant(bit_count_val);
break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst);
};
try sema.addSafetyCheck(block, ok, .shift_rhs_too_big);
try sema.addSafetyCheck(block, src, ok, .shift_rhs_too_big);
}
if (air_tag == .shr_exact) {
@ -13017,7 +13038,7 @@ fn zirShr(
} },
});
} else try block.addBinOp(.cmp_eq, lhs, back);
try sema.addSafetyCheck(block, ok, .shr_overflow);
try sema.addSafetyCheck(block, src, ok, .shr_overflow);
}
}
return result;
@ -13894,8 +13915,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
try sema.requireRuntimeBlock(block, src, runtime_src);
if (block.wantSafety()) {
try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
try sema.addDivIntOverflowSafety(block, src, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
try sema.addDivByZeroSafety(block, src, resolved_type, maybe_rhs_val, casted_rhs, is_int);
}
const air_tag = if (is_int) blk: {
@ -14025,8 +14046,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// div_trunc and check for remainder.
if (block.wantSafety()) {
try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
try sema.addDivIntOverflowSafety(block, src, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
try sema.addDivByZeroSafety(block, src, resolved_type, maybe_rhs_val, casted_rhs, is_int);
const result = try block.addBinOp(.div_trunc, casted_lhs, casted_rhs);
const ok = if (!is_int) ok: {
@ -14076,7 +14097,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
break :ok is_in_range;
}
};
try sema.addSafetyCheck(block, ok, .exact_division_remainder);
try sema.addSafetyCheck(block, src, ok, .exact_division_remainder);
return result;
}
@ -14191,8 +14212,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
try sema.requireRuntimeBlock(block, src, runtime_src);
if (block.wantSafety()) {
try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
try sema.addDivIntOverflowSafety(block, src, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
try sema.addDivByZeroSafety(block, src, resolved_type, maybe_rhs_val, casted_rhs, is_int);
}
return block.addBinOp(airTag(block, is_int, .div_floor, .div_floor_optimized), casted_lhs, casted_rhs);
@ -14308,8 +14329,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
try sema.requireRuntimeBlock(block, src, runtime_src);
if (block.wantSafety()) {
try sema.addDivIntOverflowSafety(block, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
try sema.addDivIntOverflowSafety(block, src, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int);
try sema.addDivByZeroSafety(block, src, resolved_type, maybe_rhs_val, casted_rhs, is_int);
}
return block.addBinOp(airTag(block, is_int, .div_trunc, .div_trunc_optimized), casted_lhs, casted_rhs);
@ -14318,6 +14339,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
fn addDivIntOverflowSafety(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
resolved_type: Type,
lhs_scalar_ty: Type,
maybe_lhs_val: ?Value,
@ -14391,12 +14413,13 @@ fn addDivIntOverflowSafety(
}
assert(ok != .none);
}
try sema.addSafetyCheck(block, ok, .integer_overflow);
try sema.addSafetyCheck(block, src, ok, .integer_overflow);
}
fn addDivByZeroSafety(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
resolved_type: Type,
maybe_rhs_val: ?Value,
casted_rhs: Air.Inst.Ref,
@ -14429,7 +14452,7 @@ fn addDivByZeroSafety(
const zero = try sema.addConstant(scalar_zero);
break :ok try block.addBinOp(if (is_int) .cmp_neq else .cmp_neq_optimized, casted_rhs, zero);
};
try sema.addSafetyCheck(block, ok, .divide_by_zero);
try sema.addSafetyCheck(block, src, ok, .divide_by_zero);
}
fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst.Tag) Air.Inst.Tag {
@ -14569,7 +14592,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
try sema.requireRuntimeBlock(block, src, runtime_src);
if (block.wantSafety()) {
try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
try sema.addDivByZeroSafety(block, src, resolved_type, maybe_rhs_val, casted_rhs, is_int);
}
const air_tag = airTag(block, is_int, .rem, .rem_optimized);
@ -14720,7 +14743,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
try sema.requireRuntimeBlock(block, src, runtime_src);
if (block.wantSafety()) {
try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
try sema.addDivByZeroSafety(block, src, resolved_type, maybe_rhs_val, casted_rhs, is_int);
}
const air_tag = airTag(block, is_int, .mod, .mod_optimized);
@ -14820,7 +14843,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
try sema.requireRuntimeBlock(block, src, runtime_src);
if (block.wantSafety()) {
try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
try sema.addDivByZeroSafety(block, src, resolved_type, maybe_rhs_val, casted_rhs, is_int);
}
const air_tag = airTag(block, is_int, .rem, .rem_optimized);
@ -15558,7 +15581,7 @@ fn analyzeArithmetic(
const zero_ov = try sema.addConstant(try mod.intValue(Type.u1, 0));
const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
try sema.addSafetyCheck(block, no_ov, .integer_overflow);
try sema.addSafetyCheck(block, src, no_ov, .integer_overflow);
return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
}
}
@ -17979,7 +18002,7 @@ fn zirCondbr(
break :blk try sub_block.addTyOp(.unwrap_errunion_err, result_ty, err_operand);
};
if (err_cond != null and try sema.maybeErrorUnwrap(&sub_block, else_body, err_cond.?)) {
if (err_cond != null and try sema.maybeErrorUnwrap(&sub_block, else_body, err_cond.?, cond_src)) {
// nothing to do
} else {
try sema.analyzeBodyRuntimeBreak(&sub_block, else_body);
@ -18171,7 +18194,15 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
return sema.fail(block, src, "reached unreachable code", .{});
}
// TODO Add compile error for @optimizeFor occurring too late in a scope.
try block.addUnreachable(true);
block.addUnreachable(src, true) catch |err| switch (err) {
error.AnalysisFail => {
const msg = sema.err orelse return err;
if (!mem.eql(u8, msg.msg, "runtime safety check not allowed in naked function")) return err;
try sema.errNote(block, src, msg, "the end of a naked function is implicitly unreachable", .{});
return err;
},
else => |e| return e,
};
return always_noreturn;
}
@ -18202,21 +18233,21 @@ fn zirRetImplicit(
const tracy = trace(@src());
defer tracy.end();
const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
const r_brace_src = inst_data.src();
if (block.inlining == null and sema.func_is_naked) {
assert(!block.is_comptime);
if (block.wantSafety()) {
// Calling a safety function from a naked function would not be legal.
_ = try block.addNoOp(.trap);
} else {
try block.addUnreachable(false);
try block.addUnreachable(r_brace_src, false);
}
return always_noreturn;
}
const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
const operand = try sema.resolveInst(inst_data.operand);
const r_brace_src = inst_data.src();
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
const base_tag = sema.fn_ret_ty.baseZigTypeTag(mod);
if (base_tag == .NoReturn) {
@ -18270,7 +18301,7 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir
if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) {
const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr);
return sema.retWithErrTracing(block, is_non_err, .ret_load, ret_ptr);
return sema.retWithErrTracing(block, src, is_non_err, .ret_load, ret_ptr);
}
_ = try block.addUnOp(.ret_load, ret_ptr);
@ -18280,6 +18311,7 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir
fn retWithErrTracing(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
is_non_err: Air.Inst.Ref,
ret_tag: Air.Inst.Tag,
operand: Air.Inst.Ref,
@ -18302,7 +18334,7 @@ fn retWithErrTracing(
const args: [1]Air.Inst.Ref = .{err_return_trace};
if (!need_check) {
try sema.callBuiltin(block, return_err_fn, .never_inline, &args);
try sema.callBuiltin(block, src, return_err_fn, .never_inline, &args, .@"error return");
_ = try block.addUnOp(ret_tag, operand);
return always_noreturn;
}
@ -18313,7 +18345,7 @@ fn retWithErrTracing(
var else_block = block.makeSubBlock();
defer else_block.instructions.deinit(gpa);
try sema.callBuiltin(&else_block, return_err_fn, .never_inline, &args);
try sema.callBuiltin(&else_block, src, return_err_fn, .never_inline, &args, .@"error return");
_ = try else_block.addUnOp(ret_tag, operand);
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
@ -18470,7 +18502,14 @@ fn analyzeRet(
} else if (block.is_comptime) {
return sema.fail(block, src, "function called at runtime cannot return value at comptime", .{});
} else if (sema.func_is_naked) {
return sema.fail(block, src, "cannot return from naked function", .{});
const msg = msg: {
const msg = try sema.errMsg(block, src, "cannot return from naked function", .{});
errdefer msg.destroy(sema.gpa);
try sema.errNote(block, src, msg, "can only return using assembly", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
try sema.resolveTypeLayout(sema.fn_ret_ty);
@ -18479,7 +18518,7 @@ fn analyzeRet(
// Avoid adding a frame to the error return trace in case the value is comptime-known
// to be not an error.
const is_non_err = try sema.analyzeIsNonErr(block, src, operand);
return sema.retWithErrTracing(block, is_non_err, .ret, operand);
return sema.retWithErrTracing(block, src, is_non_err, .ret, operand);
}
_ = try block.addUnOp(.ret, operand);
@ -19624,7 +19663,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
try sema.requireRuntimeBlock(block, src, operand_src);
if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) {
const ok = try block.addUnOp(.is_named_enum_value, casted_operand);
try sema.addSafetyCheck(block, ok, .invalid_enum_value);
try sema.addSafetyCheck(block, src, ok, .invalid_enum_value);
}
// In case the value is runtime-known, we have an AIR instruction for this instead
// of trying to lower it in Sema because an optimization pass may result in the operand
@ -20769,7 +20808,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
if (dest_ty.intInfo(mod).bits == 0) {
if (block.wantSafety()) {
const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, try sema.addConstant(try mod.floatValue(operand_ty, 0.0)));
try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds);
try sema.addSafetyCheck(block, src, ok, .integer_part_out_of_bounds);
}
return sema.addConstant(try mod.intValue(dest_ty, 0));
}
@ -20780,7 +20819,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, try sema.addConstant(try mod.floatValue(operand_ty, 1.0)));
const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, try sema.addConstant(try mod.floatValue(operand_ty, -1.0)));
const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg);
try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds);
try sema.addSafetyCheck(block, src, ok, .integer_part_out_of_bounds);
}
return result;
}
@ -20857,7 +20896,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag(mod) == .Fn)) {
if (!ptr_ty.isAllowzeroPtr(mod)) {
const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
try sema.addSafetyCheck(block, is_non_zero, .cast_to_null);
try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
}
if (ptr_align > 1) {
@ -20866,7 +20905,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
);
const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
try sema.addSafetyCheck(block, is_aligned, .incorrect_alignment);
try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
}
}
return block.addBitCast(ptr_ty, operand_coerced);
@ -20954,7 +20993,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
if (block.wantSafety() and !dest_ty.isAnyError(mod) and sema.mod.backendSupportsFeature(.error_set_has_value)) {
const err_int_inst = try block.addBitCast(Type.err_int, operand);
const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst);
try sema.addSafetyCheck(block, ok, .invalid_error_code);
try sema.addSafetyCheck(block, src, ok, .invalid_error_code);
}
return block.addBitCast(dest_ty, operand);
}
@ -21300,7 +21339,7 @@ fn ptrCastFull(
const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
} else is_non_zero;
try sema.addSafetyCheck(block, ok, .cast_to_null);
try sema.addSafetyCheck(block, src, ok, .cast_to_null);
}
if (block.wantSafety() and dest_align > src_align and try sema.typeHasRuntimeBits(dest_info.child.toType())) {
@ -21315,7 +21354,7 @@ fn ptrCastFull(
const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);
} else is_aligned;
try sema.addSafetyCheck(block, ok, .incorrect_alignment);
try sema.addSafetyCheck(block, src, ok, .incorrect_alignment);
}
// If we're going from an array pointer to a slice, this will only be the pointer part!
@ -22992,7 +23031,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const callee_ty = sema.typeOf(func);
const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false);
const ensure_result_used = extra.flags.ensure_result_used;
return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null);
return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null, .@"@call");
}
fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@ -23477,7 +23516,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
if (block.wantSafety()) {
const ok = try block.addBinOp(.cmp_eq, dest_len, src_len);
try sema.addSafetyCheck(block, ok, .memcpy_len_mismatch);
try sema.addSafetyCheck(block, src, ok, .memcpy_len_mismatch);
}
} else if (dest_len != .none) {
if (try sema.resolveDefinedValue(block, dest_src, dest_len)) |dest_len_val| {
@ -23619,7 +23658,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len);
const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len);
const ok = try block.addBinOp(.bit_or, ok1, ok2);
try sema.addSafetyCheck(block, ok, .memcpy_alias);
try sema.addSafetyCheck(block, src, ok, .memcpy_alias);
}
_ = try block.addInst(.{
@ -24862,6 +24901,7 @@ fn preparePanicId(sema: *Sema, block: *Block, panic_id: Module.PanicId) !Module.
fn addSafetyCheck(
sema: *Sema,
parent_block: *Block,
src: LazySrcLoc,
ok: Air.Inst.Ref,
panic_id: Module.PanicId,
) !void {
@ -24881,7 +24921,7 @@ fn addSafetyCheck(
defer fail_block.instructions.deinit(gpa);
try sema.safetyPanic(&fail_block, panic_id);
try sema.safetyPanic(&fail_block, src, panic_id);
try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
}
@ -24940,7 +24980,7 @@ fn addSafetyCheckExtra(
parent_block.instructions.appendAssumeCapacity(block_inst);
}
fn panicWithMsg(sema: *Sema, block: *Block, msg_inst: Air.Inst.Ref) !void {
fn panicWithMsg(sema: *Sema, block: *Block, src: LazySrcLoc, msg_inst: Air.Inst.Ref, operation: CallOperation) !void {
const mod = sema.mod;
if (!mod.backendSupportsFeature(.panic_fn)) {
@ -24959,12 +24999,13 @@ fn panicWithMsg(sema: *Sema, block: *Block, msg_inst: Air.Inst.Ref) !void {
.ty = opt_usize_ty.toIntern(),
.val = .none,
} })).toValue());
try sema.callBuiltin(block, panic_fn, .auto, &.{ msg_inst, null_stack_trace, null_ret_addr });
try sema.callBuiltin(block, src, panic_fn, .auto, &.{ msg_inst, null_stack_trace, null_ret_addr }, operation);
}
fn panicUnwrapError(
sema: *Sema,
parent_block: *Block,
src: LazySrcLoc,
operand: Air.Inst.Ref,
unwrap_err_tag: Air.Inst.Tag,
is_non_err_tag: Air.Inst.Tag,
@ -24972,7 +25013,7 @@ fn panicUnwrapError(
assert(!parent_block.is_comptime);
const ok = try parent_block.addUnOp(is_non_err_tag, operand);
if (!sema.mod.comp.formatted_panics) {
return sema.addSafetyCheck(parent_block, ok, .unwrap_error);
return sema.addSafetyCheck(parent_block, src, ok, .unwrap_error);
}
const gpa = sema.gpa;
@ -24997,7 +25038,7 @@ fn panicUnwrapError(
const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand);
const err_return_trace = try sema.getErrorReturnTrace(&fail_block);
const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
try sema.callBuiltin(&fail_block, panic_fn, .auto, &args);
try sema.callBuiltin(&fail_block, src, panic_fn, .auto, &args, .@"safety check");
}
}
try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
@ -25006,6 +25047,7 @@ fn panicUnwrapError(
fn panicIndexOutOfBounds(
sema: *Sema,
parent_block: *Block,
src: LazySrcLoc,
index: Air.Inst.Ref,
len: Air.Inst.Ref,
cmp_op: Air.Inst.Tag,
@ -25013,28 +25055,30 @@ fn panicIndexOutOfBounds(
assert(!parent_block.is_comptime);
const ok = try parent_block.addBinOp(cmp_op, index, len);
if (!sema.mod.comp.formatted_panics) {
return sema.addSafetyCheck(parent_block, ok, .index_out_of_bounds);
return sema.addSafetyCheck(parent_block, src, ok, .index_out_of_bounds);
}
try sema.safetyCheckFormatted(parent_block, ok, "panicOutOfBounds", &.{ index, len });
try sema.safetyCheckFormatted(parent_block, src, ok, "panicOutOfBounds", &.{ index, len });
}
fn panicInactiveUnionField(
sema: *Sema,
parent_block: *Block,
src: LazySrcLoc,
active_tag: Air.Inst.Ref,
wanted_tag: Air.Inst.Ref,
) !void {
assert(!parent_block.is_comptime);
const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag);
if (!sema.mod.comp.formatted_panics) {
return sema.addSafetyCheck(parent_block, ok, .inactive_union_field);
return sema.addSafetyCheck(parent_block, src, ok, .inactive_union_field);
}
try sema.safetyCheckFormatted(parent_block, ok, "panicInactiveUnionField", &.{ active_tag, wanted_tag });
try sema.safetyCheckFormatted(parent_block, src, ok, "panicInactiveUnionField", &.{ active_tag, wanted_tag });
}
fn panicSentinelMismatch(
sema: *Sema,
parent_block: *Block,
src: LazySrcLoc,
maybe_sentinel: ?Value,
sentinel_ty: Type,
ptr: Air.Inst.Ref,
@ -25069,19 +25113,20 @@ fn panicSentinelMismatch(
else {
const panic_fn = try sema.getBuiltin("checkNonScalarSentinel");
const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };
try sema.callBuiltin(parent_block, panic_fn, .auto, &args);
try sema.callBuiltin(parent_block, src, panic_fn, .auto, &args, .@"safety check");
return;
};
if (!sema.mod.comp.formatted_panics) {
return sema.addSafetyCheck(parent_block, ok, .sentinel_mismatch);
return sema.addSafetyCheck(parent_block, src, ok, .sentinel_mismatch);
}
try sema.safetyCheckFormatted(parent_block, ok, "panicSentinelMismatch", &.{ expected_sentinel, actual_sentinel });
try sema.safetyCheckFormatted(parent_block, src, ok, "panicSentinelMismatch", &.{ expected_sentinel, actual_sentinel });
}
fn safetyCheckFormatted(
sema: *Sema,
parent_block: *Block,
src: LazySrcLoc,
ok: Air.Inst.Ref,
func: []const u8,
args: []const Air.Inst.Ref,
@ -25106,15 +25151,15 @@ fn safetyCheckFormatted(
_ = try fail_block.addNoOp(.trap);
} else {
const panic_fn = try sema.getBuiltin(func);
try sema.callBuiltin(&fail_block, panic_fn, .auto, args);
try sema.callBuiltin(&fail_block, src, panic_fn, .auto, args, .@"safety check");
}
try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
}
fn safetyPanic(sema: *Sema, block: *Block, panic_id: Module.PanicId) CompileError!void {
fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Module.PanicId) CompileError!void {
const msg_decl_index = try sema.preparePanicId(block, panic_id);
const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index);
try sema.panicWithMsg(block, msg_inst);
const msg_inst = try sema.analyzeDeclVal(block, src, msg_decl_index);
try sema.panicWithMsg(block, src, msg_inst, .@"safety check");
}
fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
@ -26199,7 +26244,7 @@ fn unionFieldPtr(
// TODO would it be better if get_union_tag supported pointers to unions?
const union_val = try block.addTyOp(.load, union_ty, union_ptr);
const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val);
try sema.panicInactiveUnionField(block, active_tag, wanted_tag);
try sema.panicInactiveUnionField(block, src, active_tag, wanted_tag);
}
if (field.ty.zigTypeTag(mod) == .NoReturn) {
_ = try block.addNoOp(.unreach);
@ -26271,7 +26316,7 @@ fn unionFieldVal(
const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);
const wanted_tag = try sema.addConstant(wanted_tag_val);
const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);
try sema.panicInactiveUnionField(block, active_tag, wanted_tag);
try sema.panicInactiveUnionField(block, src, active_tag, wanted_tag);
}
if (field.ty.zigTypeTag(mod) == .NoReturn) {
_ = try block.addNoOp(.unreach);
@ -26626,7 +26671,7 @@ fn elemValArray(
if (maybe_index_val == null) {
const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
const cmp_op: Air.Inst.Tag = if (array_sent != null) .cmp_lte else .cmp_lt;
try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
try sema.panicIndexOutOfBounds(block, src, elem_index, len_inst, cmp_op);
}
}
return block.addBinOp(.array_elem_val, array, elem_index);
@ -26688,7 +26733,7 @@ fn elemPtrArray(
if (oob_safety and block.wantSafety() and offset == null) {
const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;
try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
try sema.panicIndexOutOfBounds(block, src, elem_index, len_inst, cmp_op);
}
return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty);
@ -26746,7 +26791,7 @@ fn elemValSlice(
else
try block.addTyOp(.slice_len, Type.usize, slice);
const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
try sema.panicIndexOutOfBounds(block, src, elem_index, len_inst, cmp_op);
}
try sema.queueFullTypeResolution(sema.typeOf(slice));
return block.addBinOp(.slice_elem_val, slice, elem_index);
@ -26806,7 +26851,7 @@ fn elemPtrSlice(
break :len try block.addTyOp(.slice_len, Type.usize, slice);
};
const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
try sema.panicIndexOutOfBounds(block, src, elem_index, len_inst, cmp_op);
}
return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty);
}
@ -29705,7 +29750,7 @@ fn coerceCompatiblePtrs(
const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
} else is_non_zero;
try sema.addSafetyCheck(block, ok, .cast_to_null);
try sema.addSafetyCheck(block, inst_src, ok, .cast_to_null);
}
return sema.bitCast(block, dest_ty, inst, inst_src, null);
}
@ -31134,9 +31179,9 @@ fn analyzeSlice(
try sema.requireRuntimeBlock(block, src, runtime_src.?);
const ok = try block.addBinOp(.cmp_lte, start, end);
if (!sema.mod.comp.formatted_panics) {
try sema.addSafetyCheck(block, ok, .start_index_greater_than_end);
try sema.addSafetyCheck(block, src, ok, .start_index_greater_than_end);
} else {
try sema.safetyCheckFormatted(block, ok, "panicStartGreaterThanEnd", &.{ start, end });
try sema.safetyCheckFormatted(block, src, ok, "panicStartGreaterThanEnd", &.{ start, end });
}
}
const new_len = if (by_length)
@ -31173,7 +31218,7 @@ fn analyzeSlice(
// requirement: slicing C ptr is non-null
if (ptr_ptr_child_ty.isCPtr(mod)) {
const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null);
}
if (slice_ty.isSlice(mod)) {
@ -31188,11 +31233,11 @@ fn analyzeSlice(
else
end;
try sema.panicIndexOutOfBounds(block, actual_end, actual_len, .cmp_lte);
try sema.panicIndexOutOfBounds(block, src, actual_end, actual_len, .cmp_lte);
}
// requirement: result[new_len] == slice_sentinel
try sema.panicSentinelMismatch(block, slice_sentinel, elem_ty, result, new_len);
try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);
}
return result;
};
@ -31230,7 +31275,7 @@ fn analyzeSlice(
// requirement: slicing C ptr is non-null
if (ptr_ptr_child_ty.isCPtr(mod)) {
const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null);
}
// requirement: end <= len
@ -31254,11 +31299,11 @@ fn analyzeSlice(
try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true)
else
end;
try sema.panicIndexOutOfBounds(block, actual_end, len_inst, .cmp_lte);
try sema.panicIndexOutOfBounds(block, src, actual_end, len_inst, .cmp_lte);
}
// requirement: start <= end
try sema.panicIndexOutOfBounds(block, start, end, .cmp_lte);
try sema.panicIndexOutOfBounds(block, src, start, end, .cmp_lte);
}
const result = try block.addInst(.{
.tag = .slice,
@ -31272,7 +31317,7 @@ fn analyzeSlice(
});
if (block.wantSafety()) {
// requirement: result[new_len] == slice_sentinel
try sema.panicSentinelMismatch(block, slice_sentinel, elem_ty, result, new_len);
try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);
}
return result;
}

View File

@ -0,0 +1,24 @@
export fn runtimeCall() callconv(.Naked) void {
f();
}
export fn runtimeBuiltinCall() callconv(.Naked) void {
@call(.auto, f, .{});
}
export fn comptimeCall() callconv(.Naked) void {
comptime f();
}
export fn comptimeBuiltinCall() callconv(.Naked) void {
@call(.compile_time, f, .{});
}
fn f() void {}
// error
// backend=llvm
// target=native
//
// :2:6: error: runtime call not allowed in naked function
// :6:5: error: runtime @call not allowed in naked function

View File

@ -0,0 +1,14 @@
fn foo() callconv(.Naked) void {
return;
}
comptime {
_ = &foo;
}
// error
// backend=llvm
// target=native
//
// :2:5: error: cannot return from naked function
// :2:5: note: can only return using assembly

View File

@ -0,0 +1,30 @@
fn runtimeSafetyDefault() callconv(.Naked) void {
unreachable;
}
fn runtimeSafetyOn() callconv(.Naked) void {
@setRuntimeSafety(true);
unreachable;
}
fn runtimeSafetyOff() callconv(.Naked) void {
@setRuntimeSafety(false);
unreachable;
}
comptime {
_ = &runtimeSafetyDefault;
_ = &runtimeSafetyOn;
_ = &runtimeSafetyOff;
}
// error
// backend=llvm
// target=native
//
// :2:5: error: runtime safety check not allowed in naked function
// :2:5: note: use @setRuntimeSafety to disable runtime safety
// :2:5: note: the end of a naked function is implicitly unreachable
// :7:5: error: runtime safety check not allowed in naked function
// :7:5: note: use @setRuntimeSafety to disable runtime safety
// :7:5: note: the end of a naked function is implicitly unreachable