authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-13 11:48:54-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-01-13 11:48:54-05:00
log4d4852ad31aa373d85cc43eb8631474323300b57
treeec6878a86de3297c3e85c9b52adc9cc54c56de69
parentd08009556eea9cb6d5dea273340081e599d7741b
parent54b11f66a960ba8f91697ede36b31934f05acfee
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4162 from LemonBoy/fix-4020

Fix @call being too eager to resolve the fn argument

3 files changed, 61 insertions(+), 18 deletions(-)

src/ir.cpp+35-17
...@@ -18687,18 +18687,6 @@ static IrInstruction *ir_analyze_call_extra(IrAnalyze *ira, IrInstruction *sourc...@@ -18687,18 +18687,6 @@ static IrInstruction *ir_analyze_call_extra(IrAnalyze *ira, IrInstruction *sourc
18687 IrInstruction *fn_ref = pass1_fn_ref->child;18687 IrInstruction *fn_ref = pass1_fn_ref->child;
18688 if (type_is_invalid(fn_ref->value->type))18688 if (type_is_invalid(fn_ref->value->type))
18689 return ira->codegen->invalid_instruction;18689 return ira->codegen->invalid_instruction;
18690 IrInstruction *first_arg_ptr = nullptr;
18691 ZigFn *fn = nullptr;
18692 if (fn_ref->value->type->id == ZigTypeIdBoundFn) {
18693 assert(fn_ref->value->special == ConstValSpecialStatic);
18694 fn = fn_ref->value->data.x_bound_fn.fn;
18695 first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg;
18696 if (type_is_invalid(first_arg_ptr->value->type))
18697 return ira->codegen->invalid_instruction;
18698 } else {
18699 fn = ir_resolve_fn(ira, fn_ref);
18700 }
18701 ZigType *fn_type = (fn != nullptr) ? fn->type_entry : fn_ref->value->type;
1870218690
18703 TypeStructField *modifier_field = find_struct_type_field(options->value->type, buf_create_from_str("modifier"));18691 TypeStructField *modifier_field = find_struct_type_field(options->value->type, buf_create_from_str("modifier"));
18704 ir_assert(modifier_field != nullptr, source_instr);18692 ir_assert(modifier_field != nullptr, source_instr);
...@@ -18733,22 +18721,52 @@ static IrInstruction *ir_analyze_call_extra(IrAnalyze *ira, IrInstruction *sourc...@@ -18733,22 +18721,52 @@ static IrInstruction *ir_analyze_call_extra(IrAnalyze *ira, IrInstruction *sourc
18733 }18721 }
18734 }18722 }
1873518723
18724 IrInstruction *first_arg_ptr = nullptr;
18725 ZigFn *fn = nullptr;
18726 if (instr_is_comptime(fn_ref)) {
18727 if (fn_ref->value->type->id == ZigTypeIdBoundFn) {
18728 assert(fn_ref->value->special == ConstValSpecialStatic);
18729 fn = fn_ref->value->data.x_bound_fn.fn;
18730 first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg;
18731 if (type_is_invalid(first_arg_ptr->value->type))
18732 return ira->codegen->invalid_instruction;
18733 } else {
18734 fn = ir_resolve_fn(ira, fn_ref);
18735 }
18736 }
18737
18738 // Some modifiers require the callee to be comptime-known
18739 switch (modifier) {
18740 case CallModifierCompileTime:
18741 case CallModifierAlwaysInline:
18742 case CallModifierAsync:
18743 if (fn == nullptr) {
18744 ir_add_error(ira, modifier_inst,
18745 buf_sprintf("the specified modifier requires a comptime-known function"));
18746 return ira->codegen->invalid_instruction;
18747 }
18748 default:
18749 break;
18750 }
18751
18752 ZigType *fn_type = (fn != nullptr) ? fn->type_entry : fn_ref->value->type;
18753
18736 TypeStructField *stack_field = find_struct_type_field(options->value->type, buf_create_from_str("stack"));18754 TypeStructField *stack_field = find_struct_type_field(options->value->type, buf_create_from_str("stack"));
18737 ir_assert(stack_field != nullptr, source_instr);18755 ir_assert(stack_field != nullptr, source_instr);
18738 IrInstruction *opt_stack = ir_analyze_struct_value_field_value(ira, source_instr, options, stack_field);18756 IrInstruction *opt_stack = ir_analyze_struct_value_field_value(ira, source_instr, options, stack_field);
18739 if (type_is_invalid(opt_stack->value->type))18757 if (type_is_invalid(opt_stack->value->type))
18740 return ira->codegen->invalid_instruction;18758 return ira->codegen->invalid_instruction;
18759
18741 IrInstruction *stack_is_non_null_inst = ir_analyze_test_non_null(ira, source_instr, opt_stack);18760 IrInstruction *stack_is_non_null_inst = ir_analyze_test_non_null(ira, source_instr, opt_stack);
18742 bool stack_is_non_null;18761 bool stack_is_non_null;
18743 if (!ir_resolve_bool(ira, stack_is_non_null_inst, &stack_is_non_null))18762 if (!ir_resolve_bool(ira, stack_is_non_null_inst, &stack_is_non_null))
18744 return ira->codegen->invalid_instruction;18763 return ira->codegen->invalid_instruction;
18745 IrInstruction *stack;18764
18765 IrInstruction *stack = nullptr;
18746 if (stack_is_non_null) {18766 if (stack_is_non_null) {
18747 stack = ir_analyze_optional_value_payload_value(ira, source_instr, opt_stack, false);18767 stack = ir_analyze_optional_value_payload_value(ira, source_instr, opt_stack, false);
18748 if (type_is_invalid(stack->value->type))18768 if (type_is_invalid(stack->value->type))
18749 return ira->codegen->invalid_instruction;18769 return ira->codegen->invalid_instruction;
18750 } else {
18751 stack = nullptr;
18752 }18770 }
1875318771
18754 return ir_analyze_fn_call(ira, source_instr, fn, fn_type, fn_ref, first_arg_ptr,18772 return ir_analyze_fn_call(ira, source_instr, fn, fn_type, fn_ref, first_arg_ptr,
test/compile_errors.zig+19-1
...@@ -11,6 +11,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -11,6 +11,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
11 "tmp.zig:3:26: error: expected 2 arguments, found 1",11 "tmp.zig:3:26: error: expected 2 arguments, found 1",
12 });12 });
1313
14 cases.addTest("@call rejects non comptime-known fn - always_inline",
15 \\pub export fn entry() void {
16 \\ var call_me: fn () void = undefined;
17 \\ @call(.{ .modifier = .always_inline }, call_me, .{});
18 \\}
19 , &[_][]const u8{
20 "tmp.zig:3:5: error: the specified modifier requires a comptime-known function",
21 });
22
23 cases.addTest("@call rejects non comptime-known fn - compile_time",
24 \\pub export fn entry() void {
25 \\ var call_me: fn () void = undefined;
26 \\ @call(.{ .modifier = .compile_time }, call_me, .{});
27 \\}
28 , &[_][]const u8{
29 "tmp.zig:3:5: error: the specified modifier requires a comptime-known function",
30 });
31
14 cases.addTest("error in struct initializer doesn't crash the compiler",32 cases.addTest("error in struct initializer doesn't crash the compiler",
15 \\pub export fn entry() void {33 \\pub export fn entry() void {
16 \\ const bitfield = struct {34 \\ const bitfield = struct {
...@@ -175,7 +193,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -175,7 +193,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
175 "tmp.zig:5:14: error: unable to perform 'never_inline' call at compile-time",193 "tmp.zig:5:14: error: unable to perform 'never_inline' call at compile-time",
176 "tmp.zig:8:14: error: unable to perform 'never_tail' call at compile-time",194 "tmp.zig:8:14: error: unable to perform 'never_tail' call at compile-time",
177 "tmp.zig:11:5: error: no-inline call of inline function",195 "tmp.zig:11:5: error: no-inline call of inline function",
178 "tmp.zig:15:43: error: unable to evaluate constant expression",196 "tmp.zig:15:5: error: the specified modifier requires a comptime-known function",
179 });197 });
180198
181 cases.add("exported async function",199 cases.add("exported async function",
test/stage1/behavior/call.zig+7
...@@ -20,6 +20,13 @@ test "basic invocations" {...@@ -20,6 +20,13 @@ test "basic invocations" {
20 const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234;20 const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234;
21 comptime expect(result);21 comptime expect(result);
22 }22 }
23 {
24 // call of non comptime-known function
25 var alias_foo = foo;
26 expect(@call(.{ .modifier = .no_async }, alias_foo, .{}) == 1234);
27 expect(@call(.{ .modifier = .never_tail }, alias_foo, .{}) == 1234);
28 expect(@call(.{ .modifier = .never_inline }, alias_foo, .{}) == 1234);
29 }
23}30}
2431
25test "tuple parameters" {32test "tuple parameters" {