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
1868718687 IrInstruction *fn_ref = pass1_fn_ref->child;
1868818688 if (type_is_invalid(fn_ref->value->type))
1868918689 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
1870318691 TypeStructField *modifier_field = find_struct_type_field(options->value->type, buf_create_from_str("modifier"));
1870418692 ir_assert(modifier_field != nullptr, source_instr);
......@@ -18733,22 +18721,52 @@ static IrInstruction *ir_analyze_call_extra(IrAnalyze *ira, IrInstruction *sourc
1873318721 }
1873418722 }
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
1873618754 TypeStructField *stack_field = find_struct_type_field(options->value->type, buf_create_from_str("stack"));
1873718755 ir_assert(stack_field != nullptr, source_instr);
1873818756 IrInstruction *opt_stack = ir_analyze_struct_value_field_value(ira, source_instr, options, stack_field);
1873918757 if (type_is_invalid(opt_stack->value->type))
1874018758 return ira->codegen->invalid_instruction;
18759
1874118760 IrInstruction *stack_is_non_null_inst = ir_analyze_test_non_null(ira, source_instr, opt_stack);
1874218761 bool stack_is_non_null;
1874318762 if (!ir_resolve_bool(ira, stack_is_non_null_inst, &stack_is_non_null))
1874418763 return ira->codegen->invalid_instruction;
18745 IrInstruction *stack;
18764
18765 IrInstruction *stack = nullptr;
1874618766 if (stack_is_non_null) {
1874718767 stack = ir_analyze_optional_value_payload_value(ira, source_instr, opt_stack, false);
18748 if (type_is_invalid(stack->value->type))
18749 return ira->codegen->invalid_instruction;
18750 } else {
18751 stack = nullptr;
18768 if (type_is_invalid(stack->value->type))
18769 return ira->codegen->invalid_instruction;
1875218770 }
1875318771
1875418772 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 {
1111 "tmp.zig:3:26: error: expected 2 arguments, found 1",
1212 });
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
1432 cases.addTest("error in struct initializer doesn't crash the compiler",
1533 \\pub export fn entry() void {
1634 \\ const bitfield = struct {
test/stage1/behavior/call.zig+7
......@@ -20,6 +20,13 @@ test "basic invocations" {
2020 const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234;
2121 comptime expect(result);
2222 }
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 }
2330}
2431
2532test "tuple parameters" {