authorgravatar for alex_naskos@hotmail.comAlexandros Naskos <alex_naskos@hotmail.com> 2020-04-27 18:07:18+03:00
committergravatar for alex_naskos@hotmail.comAlexandros Naskos <alex_naskos@hotmail.com> 2020-04-27 18:07:18+03:00
log37fa418a94fc5da695f8799b6b021b632bb1d500
treea5f84478194c56cd0541f9c8b914a00e08167cc7
parent908b908481260322b60f479ccf4cabff72fcc5d5

Cleaned up code, added a testcase for an extern member function call


2 files changed, 41 insertions(+), 25 deletions(-)

src/ir.cpp+24-21
...@@ -19707,25 +19707,31 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,...@@ -19707,25 +19707,31 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
19707 }19707 }
1970819708
19709 if (modifier == CallModifierCompileTime) {19709 if (modifier == CallModifierCompileTime) {
19710 bool extern_fn_in_typeof = false;19710 // If we are evaluating an extern function in a TypeOf call, we can return an undefined value
19711 // of its return type.
19712 if (fn_entry != nullptr && source_instr->scope->id == ScopeIdTypeOf &&
19713 fn_proto_node->data.fn_proto.is_extern) {
19714
19715 assert(fn_entry->body_node == nullptr);
19716 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
19717 ZigType *return_type = ir_analyze_type_expr(ira, source_instr->scope, return_type_node);
19718 if (type_is_invalid(return_type))
19719 return ira->codegen->invalid_inst_gen;
19720
19721 return ir_const_undef(ira, source_instr, return_type);
19722 }
1971119723
19712 // No special handling is needed for compile time evaluation of generic functions.19724 // No special handling is needed for compile time evaluation of generic functions.
19713 if (!fn_entry || fn_entry->body_node == nullptr) {19725 if (!fn_entry || fn_entry->body_node == nullptr) {
19714 // We keep evaluating extern functions directly in TypeOfs19726 ir_add_error(ira, &fn_ref->base, buf_sprintf("unable to evaluate constant expression"));
19715 if (fn_entry && source_instr->scope->id == ScopeIdTypeOf) {19727 return ira->codegen->invalid_inst_gen;
19716 extern_fn_in_typeof = true;
19717 } else {
19718 ir_add_error(ira, &fn_ref->base, buf_sprintf("unable to evaluate constant expression"));
19719 return ira->codegen->invalid_inst_gen;
19720 }
19721 }19728 }
1972219729
19723 if (!ir_emit_backward_branch(ira, source_instr))19730 if (!ir_emit_backward_branch(ira, source_instr))
19724 return ira->codegen->invalid_inst_gen;19731 return ira->codegen->invalid_inst_gen;
1972519732
19726 // Fork a scope of the function with known values for the parameters.19733 // Fork a scope of the function with known values for the parameters.
19727 // If we are evaluating an extern function in a TypeOf, we use the current scope instead.19734 Scope *exec_scope = &fn_entry->fndef_scope->base;
19728 Scope *exec_scope = extern_fn_in_typeof ? source_instr->scope : &fn_entry->fndef_scope->base;
1972919735
19730 size_t next_proto_i = 0;19736 size_t next_proto_i = 0;
19731 if (first_arg_ptr) {19737 if (first_arg_ptr) {
...@@ -19752,7 +19758,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,...@@ -19752,7 +19758,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
19752 return ira->codegen->invalid_inst_gen;19758 return ira->codegen->invalid_inst_gen;
19753 }19759 }
1975419760
19755 if (!extern_fn_in_typeof) for (size_t call_i = 0; call_i < args_len; call_i += 1) {19761 for (size_t call_i = 0; call_i < args_len; call_i += 1) {
19756 IrInstGen *old_arg = args_ptr[call_i];19762 IrInstGen *old_arg = args_ptr[call_i];
1975719763
19758 if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, old_arg, &exec_scope, &next_proto_i))19764 if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, old_arg, &exec_scope, &next_proto_i))
...@@ -19774,7 +19780,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,...@@ -19774,7 +19780,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
19774 return_type = specified_return_type;19780 return_type = specified_return_type;
19775 }19781 }
1977619782
19777 bool cacheable = !extern_fn_in_typeof && fn_eval_cacheable(exec_scope, return_type);19783 bool cacheable = fn_eval_cacheable(exec_scope, return_type);
19778 ZigValue *result = nullptr;19784 ZigValue *result = nullptr;
19779 if (cacheable) {19785 if (cacheable) {
19780 auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope);19786 auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope);
...@@ -19788,15 +19794,12 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,...@@ -19788,15 +19794,12 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
19788 ZigValue *result_ptr;19794 ZigValue *result_ptr;
19789 create_result_ptr(ira->codegen, return_type, &result, &result_ptr);19795 create_result_ptr(ira->codegen, return_type, &result, &result_ptr);
1979019796
19791 // If we are evaluating an extern function in a TypeOf, create a value and keep it undefined.19797 if ((err = ir_eval_const_value(ira->codegen, exec_scope, body_node, result_ptr,
19792 if (!extern_fn_in_typeof) {19798 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,
19793 if ((err = ir_eval_const_value(ira->codegen, exec_scope, body_node, result_ptr,19799 fn_entry, nullptr, source_instr->source_node, nullptr, ira->new_irb.exec, return_type_node,
19794 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,19800 UndefOk)))
19795 fn_entry, nullptr, source_instr->source_node, nullptr, ira->new_irb.exec, return_type_node,19801 {
19796 UndefOk)))19802 return ira->codegen->invalid_inst_gen;
19797 {
19798 return ira->codegen->invalid_inst_gen;
19799 }
19800 }19803 }
1980119804
19802 if (inferred_err_set_type != nullptr) {19805 if (inferred_err_set_type != nullptr) {
test/stage1/behavior/bugs/4328.zig+17-4
...@@ -1,18 +1,31 @@...@@ -1,18 +1,31 @@
1const expectEqual = @import("std").testing.expectEqual;1const expectEqual = @import("std").testing.expectEqual;
22
3const FILE = extern struct { dummy_field: u8, };3const FILE = extern struct {
4 dummy_field: u8,
5};
4extern fn printf([*c]const u8, ...) c_int;6extern fn printf([*c]const u8, ...) c_int;
5extern fn fputs([*c]const u8, noalias [*c]FILE) c_int;7extern fn fputs([*c]const u8, noalias [*c]FILE) c_int;
6extern fn ftell([*c]FILE) c_long;8extern fn ftell([*c]FILE) c_long;
79
8test "Extern function call in @TypeOf" {10const S = extern struct {
11 state: c_short,
12
13 extern fn s_do_thing([*c]S, b: c_int) c_short;
14};
15
16test "Extern function calls in @TypeOf" {
9 const Test = struct {17 const Test = struct {
10 fn test_fn(a: var, b: var) @TypeOf(printf("%d %s\n", a, b)) {18 fn test_fn_1(a: var, b: var) @TypeOf(printf("%d %s\n", a, b)) {
11 return 0;19 return 0;
12 }20 }
1321
22 fn test_fn_2(a: var) @TypeOf((S{ .state = 0 }).s_do_thing(a)) {
23 return 1;
24 }
25
14 fn doTheTest() void {26 fn doTheTest() void {
15 expectEqual(c_int, @TypeOf(test_fn(0, 42)));27 expectEqual(c_int, @TypeOf(test_fn_1(0, 42)));
28 expectEqual(c_short, @TypeOf(test_fn_2(0)));
16 }29 }
17 };30 };
1831