Sema: respect inline call semantics

If an argument is comptime-known but shouldn't be create an alloc
to store it in to get a runtime-known value.
This commit is contained in:
Veikka Tuominen 2022-10-17 14:52:18 +03:00
parent be9a4a1f97
commit 4e134f6dcb
5 changed files with 48 additions and 31 deletions

View File

@ -6413,9 +6413,9 @@ fn analyzeInlineCallArg(
};
}
const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);
try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
if (is_comptime_call) {
try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
if (err == error.AnalysisFail and sema.err != null) {
try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
@ -6440,6 +6440,20 @@ fn analyzeInlineCallArg(
.ty = param_ty,
.val = arg_val,
};
} else if ((try sema.resolveMaybeUndefVal(arg_block, arg_src, casted_arg) == null) or
try sema.typeRequiresComptime(param_ty) or zir_tags[inst] == .param_comptime)
{
try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
} else {
// We have a comptime value but we need a runtime value to preserve inlining semantics,
const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
.pointee_type = param_ty,
.@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
});
const alloc = try arg_block.addTy(.alloc, ptr_type);
_ = try arg_block.addBinOp(.store, alloc, casted_arg);
const loaded = try arg_block.addTyOp(.load, param_ty, alloc);
try sema.inst_map.putNoClobber(sema.gpa, inst, loaded);
}
arg_i.* += 1;
@ -6448,9 +6462,10 @@ fn analyzeInlineCallArg(
// No coercion needed.
const uncasted_arg = uncasted_args[arg_i.*];
new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg);
try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
const param_ty = sema.typeOf(uncasted_arg);
if (is_comptime_call) {
try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
if (err == error.AnalysisFail and sema.err != null) {
try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
@ -6475,6 +6490,20 @@ fn analyzeInlineCallArg(
.ty = sema.typeOf(uncasted_arg),
.val = arg_val,
};
} else if ((try sema.resolveMaybeUndefVal(arg_block, arg_src, uncasted_arg)) == null or
try sema.typeRequiresComptime(param_ty) or zir_tags[inst] == .param_anytype_comptime)
{
try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
} else {
// We have a comptime value but we need a runtime value to preserve inlining semantics,
const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
.pointee_type = param_ty,
.@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
});
const alloc = try arg_block.addTy(.alloc, ptr_type);
_ = try arg_block.addBinOp(.store, alloc, uncasted_arg);
const loaded = try arg_block.addTyOp(.load, param_ty, alloc);
try sema.inst_map.putNoClobber(sema.gpa, inst, loaded);
}
arg_i.* += 1;

View File

@ -105,6 +105,7 @@ test {
_ = @import("behavior/bugs/13068.zig");
_ = @import("behavior/bugs/13112.zig");
_ = @import("behavior/bugs/13128.zig");
_ = @import("behavior/bugs/13164.zig");
_ = @import("behavior/byteswap.zig");
_ = @import("behavior/byval_arg_var.zig");
_ = @import("behavior/call.zig");

View File

@ -0,0 +1,16 @@
const std = @import("std");
const builtin = @import("builtin");
inline fn setLimits(min: ?u32, max: ?u32) !void {
if (min != null and max != null) {
try std.testing.expect(min.? <= max.?);
}
}
test {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
var x: u32 = 42;
try setLimits(x, null);
}

View File

@ -1,16 +0,0 @@
pub fn main() void {
var x: usize = 3;
const y = add(10, 2, x);
if (y - 6 != 0) unreachable;
}
inline fn add(a: usize, b: usize, c: usize) usize {
if (a == 10) @compileError("bad");
return a + b + c;
}
// error
// output_mode=Exe
//
// :8:18: error: bad
// :3:18: note: called from here

View File

@ -1,13 +0,0 @@
pub fn main() void {
var x: usize = 3;
const y = add(1, 2, x);
if (y - 6 != 0) unreachable;
}
inline fn add(a: usize, b: usize, c: usize) usize {
if (a == 10) @compileError("bad");
return a + b + c;
}
// run
//