diff --git a/src/ir.cpp b/src/ir.cpp index 8ed22b12cb..64f39bf6f5 100644 --- a/src/ir.cpp +++ b/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)) diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 61b0c1aa56..a420fd6886 100644 --- a/test/stage1/behavior.zig +++ b/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"); diff --git a/test/stage1/behavior/bugs/4328.zig b/test/stage1/behavior/bugs/4328.zig new file mode 100644 index 0000000000..631c213df1 --- /dev/null +++ b/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(); +}