Commit 37fa418a94

Alexandros Naskos <alex_naskos@hotmail.com>
2020-04-27 17:07:18
Cleaned up code, added a testcase for an extern member function call
1 parent 908b908
Changed files (2)
src
test
stage1
behavior
src/ir.cpp
@@ -19707,25 +19707,31 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
     }
 
     if (modifier == CallModifierCompileTime) {
-        bool extern_fn_in_typeof = false;
+        // If we are evaluating an extern function in a TypeOf call, we can return an undefined value
+        // of its return type.
+        if (fn_entry != nullptr && source_instr->scope->id == ScopeIdTypeOf &&
+            fn_proto_node->data.fn_proto.is_extern) {
+
+            assert(fn_entry->body_node == nullptr);
+            AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
+            ZigType *return_type = ir_analyze_type_expr(ira, source_instr->scope, return_type_node);
+            if (type_is_invalid(return_type))
+                return ira->codegen->invalid_inst_gen;
+
+            return ir_const_undef(ira, source_instr, return_type);
+        }
 
         // No special handling is needed for compile time evaluation of generic functions.
         if (!fn_entry || fn_entry->body_node == nullptr) {
-            // We keep evaluating extern functions directly in TypeOfs
-            if (fn_entry && source_instr->scope->id == ScopeIdTypeOf) {
-                extern_fn_in_typeof = true;
-            } else {
-                ir_add_error(ira, &fn_ref->base, buf_sprintf("unable to evaluate constant expression"));
-                return ira->codegen->invalid_inst_gen;
-            }
+            ir_add_error(ira, &fn_ref->base, buf_sprintf("unable to evaluate constant expression"));
+            return ira->codegen->invalid_inst_gen;
         }
 
         if (!ir_emit_backward_branch(ira, source_instr))
             return ira->codegen->invalid_inst_gen;
 
         // Fork a scope of the function with known values for the parameters.
-        // If we are evaluating an extern function in a TypeOf, we use the current scope instead.
-        Scope *exec_scope = extern_fn_in_typeof ? source_instr->scope : &fn_entry->fndef_scope->base;
+        Scope *exec_scope = &fn_entry->fndef_scope->base;
 
         size_t next_proto_i = 0;
         if (first_arg_ptr) {
@@ -19752,7 +19758,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
                 return ira->codegen->invalid_inst_gen;
         }
 
-        if (!extern_fn_in_typeof) for (size_t call_i = 0; call_i < args_len; call_i += 1) {
+        for (size_t call_i = 0; call_i < args_len; call_i += 1) {
             IrInstGen *old_arg = args_ptr[call_i];
 
             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,
             return_type = specified_return_type;
         }
 
-        bool cacheable = !extern_fn_in_typeof && fn_eval_cacheable(exec_scope, return_type);
+        bool cacheable = fn_eval_cacheable(exec_scope, return_type);
         ZigValue *result = nullptr;
         if (cacheable) {
             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,
             ZigValue *result_ptr;
             create_result_ptr(ira->codegen, return_type, &result, &result_ptr);
 
-            // If we are evaluating an extern function in a TypeOf, create a value and keep it undefined.
-            if (!extern_fn_in_typeof) {
-                if ((err = ir_eval_const_value(ira->codegen, exec_scope, body_node, result_ptr,
-                    ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,
-                    fn_entry, nullptr, source_instr->source_node, nullptr, ira->new_irb.exec, return_type_node,
-                    UndefOk)))
-                {
-                    return ira->codegen->invalid_inst_gen;
-                }
+            if ((err = ir_eval_const_value(ira->codegen, exec_scope, body_node, result_ptr,
+                ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,
+                fn_entry, nullptr, source_instr->source_node, nullptr, ira->new_irb.exec, return_type_node,
+                UndefOk)))
+            {
+                return ira->codegen->invalid_inst_gen;
             }
 
             if (inferred_err_set_type != nullptr) {
test/stage1/behavior/bugs/4328.zig
@@ -1,18 +1,31 @@
 const expectEqual = @import("std").testing.expectEqual;
 
-const FILE = extern struct { dummy_field: u8, };
+const FILE = extern struct {
+    dummy_field: u8,
+};
 extern fn printf([*c]const u8, ...) c_int;
 extern fn fputs([*c]const u8, noalias [*c]FILE) c_int;
 extern fn ftell([*c]FILE) c_long;
 
-test "Extern function call in @TypeOf" {
+const S = extern struct {
+    state: c_short,
+
+    extern fn s_do_thing([*c]S, b: c_int) c_short;
+};
+
+test "Extern function calls in @TypeOf" {
     const Test = struct {
-        fn test_fn(a: var, b: var) @TypeOf(printf("%d %s\n", a, b)) {
+        fn test_fn_1(a: var, b: var) @TypeOf(printf("%d %s\n", a, b)) {
             return 0;
         }
 
+        fn test_fn_2(a: var) @TypeOf((S{ .state = 0 }).s_do_thing(a)) {
+            return 1;
+        }
+
         fn doTheTest() void {
-            expectEqual(c_int, @TypeOf(test_fn(0, 42)));
+            expectEqual(c_int, @TypeOf(test_fn_1(0, 42)));
+            expectEqual(c_short, @TypeOf(test_fn_2(0)));
         }
     };