| author | |
| committer | |
| log | 400a91e1c644228a66aa1702b9d800f018712105 |
| tree | e5c6dc1cba4df2235a88681a6273a8d6bb2aed18 |
| parent | 37fa418a94fc5da695f8799b6b021b632bb1d500 |
3 files changed, 67 insertions(+), 50 deletions(-)
src/ir.cpp+18-1| ... | ... | @@ -15406,6 +15406,12 @@ static IrInstGen *ir_get_deref(IrAnalyze *ira, IrInst* source_instruction, IrIns |
| 15406 | 15406 | } |
| 15407 | 15407 | if (instr_is_comptime(ptr)) { |
| 15408 | 15408 | if (ptr->value->special == ConstValSpecialUndef) { |
| 15409 | // If we are in a TypeOf call, we return an undefined value instead of erroring | |
| 15410 | // since we know the type. | |
| 15411 | if (get_scope_typeof(source_instruction->scope)) { | |
| 15412 | return ir_const_undef(ira, source_instruction, child_type); | |
| 15413 | } | |
| 15414 | ||
| 15409 | 15415 | ir_add_error(ira, &ptr->base, buf_sprintf("attempt to dereference undefined value")); |
| 15410 | 15416 | return ira->codegen->invalid_inst_gen; |
| 15411 | 15417 | } |
| ... | ... | @@ -19709,7 +19715,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr, |
| 19709 | 19715 | if (modifier == CallModifierCompileTime) { |
| 19710 | 19716 | // If we are evaluating an extern function in a TypeOf call, we can return an undefined value |
| 19711 | 19717 | // of its return type. |
| 19712 | if (fn_entry != nullptr && source_instr->scope->id == ScopeIdTypeOf && | |
| 19718 | if (fn_entry != nullptr && get_scope_typeof(source_instr->scope) != nullptr && | |
| 19713 | 19719 | fn_proto_node->data.fn_proto.is_extern) { |
| 19714 | 19720 | |
| 19715 | 19721 | assert(fn_entry->body_node == nullptr); |
| ... | ... | @@ -21842,6 +21848,11 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name |
| 21842 | 21848 | return ir_analyze_inferred_field_ptr(ira, field_name, source_instr, container_ptr, bare_type); |
| 21843 | 21849 | } |
| 21844 | 21850 | |
| 21851 | // Tracks wether we should return an undefined value of the correct type. | |
| 21852 | // We do this if the container pointer is undefined and we are in a TypeOf call. | |
| 21853 | bool return_undef = container_ptr->value->special == ConstValSpecialUndef && \ | |
| 21854 | get_scope_typeof(source_instr->scope) != nullptr; | |
| 21855 | ||
| 21845 | 21856 | if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusZeroBitsKnown))) |
| 21846 | 21857 | return ira->codegen->invalid_inst_gen; |
| 21847 | 21858 | |
| ... | ... | @@ -21849,6 +21860,12 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name |
| 21849 | 21860 | if (bare_type->id == ZigTypeIdStruct) { |
| 21850 | 21861 | TypeStructField *field = find_struct_type_field(bare_type, field_name); |
| 21851 | 21862 | if (field != nullptr) { |
| 21863 | if (return_undef) { | |
| 21864 | ZigType *field_ptr_type = get_pointer_to_type(ira->codegen, resolve_struct_field_type(ira->codegen, field), | |
| 21865 | container_ptr->value->type->data.pointer.is_const); | |
| 21866 | return ir_const_undef(ira, source_instr, field_ptr_type); | |
| 21867 | } | |
| 21868 | ||
| 21852 | 21869 | return ir_analyze_struct_field_ptr(ira, source_instr, field, container_ptr, bare_type, initializing); |
| 21853 | 21870 | } else { |
| 21854 | 21871 | return ir_analyze_container_member_access_inner(ira, bare_type, field_name, |
test/stage1/behavior/bugs/4328.zig deleted-49| ... | ... | @@ -1,49 +0,0 @@ |
| 1 | const expectEqual = @import("std").testing.expectEqual; | |
| 2 | ||
| 3 | const FILE = extern struct { | |
| 4 | dummy_field: u8, | |
| 5 | }; | |
| 6 | extern fn printf([*c]const u8, ...) c_int; | |
| 7 | extern fn fputs([*c]const u8, noalias [*c]FILE) c_int; | |
| 8 | extern fn ftell([*c]FILE) c_long; | |
| 9 | ||
| 10 | const S = extern struct { | |
| 11 | state: c_short, | |
| 12 | ||
| 13 | extern fn s_do_thing([*c]S, b: c_int) c_short; | |
| 14 | }; | |
| 15 | ||
| 16 | test "Extern function calls in @TypeOf" { | |
| 17 | const Test = struct { | |
| 18 | fn test_fn_1(a: var, b: var) @TypeOf(printf("%d %s\n", a, b)) { | |
| 19 | return 0; | |
| 20 | } | |
| 21 | ||
| 22 | fn test_fn_2(a: var) @TypeOf((S{ .state = 0 }).s_do_thing(a)) { | |
| 23 | return 1; | |
| 24 | } | |
| 25 | ||
| 26 | fn doTheTest() void { | |
| 27 | expectEqual(c_int, @TypeOf(test_fn_1(0, 42))); | |
| 28 | expectEqual(c_short, @TypeOf(test_fn_2(0))); | |
| 29 | } | |
| 30 | }; | |
| 31 | ||
| 32 | Test.doTheTest(); | |
| 33 | comptime Test.doTheTest(); | |
| 34 | } | |
| 35 | ||
| 36 | test "Peer resolution of extern function calls in @TypeOf" { | |
| 37 | const Test = struct { | |
| 38 | fn test_fn() @TypeOf(ftell(null), fputs(null, null)) { | |
| 39 | return 0; | |
| 40 | } | |
| 41 | ||
| 42 | fn doTheTest() void { | |
| 43 | expectEqual(c_long, @TypeOf(test_fn())); | |
| 44 | } | |
| 45 | }; | |
| 46 | ||
| 47 | Test.doTheTest(); | |
| 48 | comptime Test.doTheTest(); | |
| 49 | } |
test/stage1/behavior/bugs/4328_5305.zig created+49| ... | ... | @@ -0,0 +1,49 @@ |
| 1 | const expectEqual = @import("std").testing.expectEqual; | |
| 2 | ||
| 3 | const FILE = extern struct { | |
| 4 | dummy_field: u8, | |
| 5 | }; | |
| 6 | extern fn printf([*c]const u8, ...) c_int; | |
| 7 | extern fn fputs([*c]const u8, noalias [*c]FILE) c_int; | |
| 8 | extern fn ftell([*c]FILE) c_long; | |
| 9 | ||
| 10 | const S = extern struct { | |
| 11 | state: c_short, | |
| 12 | ||
| 13 | extern fn s_do_thing([*c]S, b: c_int) c_short; | |
| 14 | }; | |
| 15 | ||
| 16 | test "Extern function calls in @TypeOf" { | |
| 17 | const Test = struct { | |
| 18 | fn test_fn_1(a: var, b: var) @TypeOf(printf("%d %s\n", a, b)) { | |
| 19 | return 0; | |
| 20 | } | |
| 21 | ||
| 22 | fn test_fn_2(a: var) @TypeOf((S{ .state = 0 }).s_do_thing(a)) { | |
| 23 | return 1; | |
| 24 | } | |
| 25 | ||
| 26 | fn doTheTest() void { | |
| 27 | expectEqual(c_int, @TypeOf(test_fn_1(0, 42))); | |
| 28 | expectEqual(c_short, @TypeOf(test_fn_2(0))); | |
| 29 | } | |
| 30 | }; | |
| 31 | ||
| 32 | Test.doTheTest(); | |
| 33 | comptime Test.doTheTest(); | |
| 34 | } | |
| 35 | ||
| 36 | test "Peer resolution of extern function calls in @TypeOf" { | |
| 37 | const Test = struct { | |
| 38 | fn test_fn() @TypeOf(ftell(null), fputs(null, null)) { | |
| 39 | return 0; | |
| 40 | } | |
| 41 | ||
| 42 | fn doTheTest() void { | |
| 43 | expectEqual(c_long, @TypeOf(test_fn())); | |
| 44 | } | |
| 45 | }; | |
| 46 | ||
| 47 | Test.doTheTest(); | |
| 48 | comptime Test.doTheTest(); | |
| 49 | } |