authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-01-12 23:49:26+01:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-01-12 23:51:18+01:00
log34cdcb13c05473b4e4c437e7ad484b5e1f953c37
treefba5b755d91686ec96019bbb97d823f3aad07923
parentc96131f30caaf6d7cd1d202891a28ee0df8b577e

Fix @call being too eager to resolve the fn argument

Closes #4020

3 files changed, 60 insertions(+), 17 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+18
...@@ -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 {
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" {