Commit 908b908481

Alexandros Naskos <alex_naskos@hotmail.com>
2020-04-27 14:22:15
Added tests.
1 parent 179423e
Changed files (3)
src
test
stage1
behavior
src/ir.cpp
@@ -19706,13 +19706,13 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
         return ira->codegen->invalid_inst_gen;
     }
 
-    bool extern_fn_in_typeof = false;
-
     if (modifier == CallModifierCompileTime) {
+        bool extern_fn_in_typeof = false;
+
         // 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 in TypeOfs
-            if (get_scope_typeof(source_instr->scope) != nullptr && fn_entry) {
+            // 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"));
@@ -19724,7 +19724,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* 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 TypeOf's scope instead.
+        // 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;
 
         size_t next_proto_i = 0;
@@ -19752,7 +19752,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
                 return ira->codegen->invalid_inst_gen;
         }
 
-        for (size_t call_i = 0; call_i < args_len; call_i += 1) {
+        if (!extern_fn_in_typeof) 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))
test/stage1/behavior/bugs/4328.zig
@@ -0,0 +1,36 @@
+const expectEqual = @import("std").testing.expectEqual;
+
+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 Test = struct {
+        fn test_fn(a: var, b: var) @TypeOf(printf("%d %s\n", a, b)) {
+            return 0;
+        }
+
+        fn doTheTest() void {
+            expectEqual(c_int, @TypeOf(test_fn(0, 42)));
+        }
+    };
+
+    Test.doTheTest();
+    comptime Test.doTheTest();
+}
+
+test "Peer resolution of extern function calls in @TypeOf" {
+    const Test = struct {
+        fn test_fn() @TypeOf(ftell(null), fputs(null, null)) {
+            return 0;
+        }
+
+        fn doTheTest() void {
+            expectEqual(c_long, @TypeOf(test_fn()));
+        }
+    };
+
+    Test.doTheTest();
+    comptime Test.doTheTest();
+}
test/stage1/behavior.zig
@@ -40,6 +40,7 @@ comptime {
     _ = @import("behavior/bugs/3384.zig");
     _ = @import("behavior/bugs/3586.zig");
     _ = @import("behavior/bugs/3742.zig");
+    _ = @import("behavior/bugs/4328.zig");
     _ = @import("behavior/bugs/4560.zig");
     _ = @import("behavior/bugs/4769_a.zig");
     _ = @import("behavior/bugs/4769_b.zig");