authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-17 14:52:18+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-19 01:38:18+03:00
log4e134f6dcb02000151c395718eb2c24977100013
tree4cbc97fd0082e201e1422db751b303ea6d777135
parentbe9a4a1f976ea924f0cbe33f7bb869c450fd823a

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.

5 files changed, 48 insertions(+), 31 deletions(-)

src/Sema.zig+31-2
...@@ -6413,9 +6413,9 @@ fn analyzeInlineCallArg(...@@ -6413,9 +6413,9 @@ fn analyzeInlineCallArg(
6413 };6413 };
6414 }6414 }
6415 const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);6415 const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);
6416 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
64176416
6418 if (is_comptime_call) {6417 if (is_comptime_call) {
6418 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
6419 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {6419 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
6420 if (err == error.AnalysisFail and sema.err != null) {6420 if (err == error.AnalysisFail and sema.err != null) {
6421 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);6421 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
...@@ -6440,6 +6440,20 @@ fn analyzeInlineCallArg(...@@ -6440,6 +6440,20 @@ fn analyzeInlineCallArg(
6440 .ty = param_ty,6440 .ty = param_ty,
6441 .val = arg_val,6441 .val = arg_val,
6442 };6442 };
6443 } else if ((try sema.resolveMaybeUndefVal(arg_block, arg_src, casted_arg) == null) or
6444 try sema.typeRequiresComptime(param_ty) or zir_tags[inst] == .param_comptime)
6445 {
6446 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
6447 } else {
6448 // We have a comptime value but we need a runtime value to preserve inlining semantics,
6449 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
6450 .pointee_type = param_ty,
6451 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
6452 });
6453 const alloc = try arg_block.addTy(.alloc, ptr_type);
6454 _ = try arg_block.addBinOp(.store, alloc, casted_arg);
6455 const loaded = try arg_block.addTyOp(.load, param_ty, alloc);
6456 try sema.inst_map.putNoClobber(sema.gpa, inst, loaded);
6443 }6457 }
64446458
6445 arg_i.* += 1;6459 arg_i.* += 1;
...@@ -6448,9 +6462,10 @@ fn analyzeInlineCallArg(...@@ -6448,9 +6462,10 @@ fn analyzeInlineCallArg(
6448 // No coercion needed.6462 // No coercion needed.
6449 const uncasted_arg = uncasted_args[arg_i.*];6463 const uncasted_arg = uncasted_args[arg_i.*];
6450 new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg);6464 new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg);
6451 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);6465 const param_ty = sema.typeOf(uncasted_arg);
64526466
6453 if (is_comptime_call) {6467 if (is_comptime_call) {
6468 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
6454 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {6469 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
6455 if (err == error.AnalysisFail and sema.err != null) {6470 if (err == error.AnalysisFail and sema.err != null) {
6456 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);6471 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
...@@ -6475,6 +6490,20 @@ fn analyzeInlineCallArg(...@@ -6475,6 +6490,20 @@ fn analyzeInlineCallArg(
6475 .ty = sema.typeOf(uncasted_arg),6490 .ty = sema.typeOf(uncasted_arg),
6476 .val = arg_val,6491 .val = arg_val,
6477 };6492 };
6493 } else if ((try sema.resolveMaybeUndefVal(arg_block, arg_src, uncasted_arg)) == null or
6494 try sema.typeRequiresComptime(param_ty) or zir_tags[inst] == .param_anytype_comptime)
6495 {
6496 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
6497 } else {
6498 // We have a comptime value but we need a runtime value to preserve inlining semantics,
6499 const ptr_type = try Type.ptr(sema.arena, sema.mod, .{
6500 .pointee_type = param_ty,
6501 .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
6502 });
6503 const alloc = try arg_block.addTy(.alloc, ptr_type);
6504 _ = try arg_block.addBinOp(.store, alloc, uncasted_arg);
6505 const loaded = try arg_block.addTyOp(.load, param_ty, alloc);
6506 try sema.inst_map.putNoClobber(sema.gpa, inst, loaded);
6478 }6507 }
64796508
6480 arg_i.* += 1;6509 arg_i.* += 1;
test/behavior.zig+1
...@@ -105,6 +105,7 @@ test {...@@ -105,6 +105,7 @@ test {
105 _ = @import("behavior/bugs/13068.zig");105 _ = @import("behavior/bugs/13068.zig");
106 _ = @import("behavior/bugs/13112.zig");106 _ = @import("behavior/bugs/13112.zig");
107 _ = @import("behavior/bugs/13128.zig");107 _ = @import("behavior/bugs/13128.zig");
108 _ = @import("behavior/bugs/13164.zig");
108 _ = @import("behavior/byteswap.zig");109 _ = @import("behavior/byteswap.zig");
109 _ = @import("behavior/byval_arg_var.zig");110 _ = @import("behavior/byval_arg_var.zig");
110 _ = @import("behavior/call.zig");111 _ = @import("behavior/call.zig");
test/behavior/bugs/13164.zig created+16
...@@ -0,0 +1,16 @@
1const std = @import("std");
2const builtin = @import("builtin");
3
4inline fn setLimits(min: ?u32, max: ?u32) !void {
5 if (min != null and max != null) {
6 try std.testing.expect(min.? <= max.?);
7 }
8}
9
10test {
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13
14 var x: u32 = 42;
15 try setLimits(x, null);
16}
test/cases/compile_error_in_inline_fn_call_fixed.0.zig deleted-16
...@@ -1,16 +0,0 @@
1pub fn main() void {
2 var x: usize = 3;
3 const y = add(10, 2, x);
4 if (y - 6 != 0) unreachable;
5}
6
7inline fn add(a: usize, b: usize, c: usize) usize {
8 if (a == 10) @compileError("bad");
9 return a + b + c;
10}
11
12// error
13// output_mode=Exe
14//
15// :8:18: error: bad
16// :3:18: note: called from here
test/cases/compile_error_in_inline_fn_call_fixed.1.zig deleted-13
...@@ -1,13 +0,0 @@
1pub fn main() void {
2 var x: usize = 3;
3 const y = add(1, 2, x);
4 if (y - 6 != 0) unreachable;
5}
6
7inline fn add(a: usize, b: usize, c: usize) usize {
8 if (a == 10) @compileError("bad");
9 return a + b + c;
10}
11
12// run
13//