authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-05-30 01:11:22+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-05-30 01:11:22+03:00
log4c8b937fb016a54b09d7447ca634b7cf1af78fce
treebe94b0dad5a43376417c308163ade104c9055b7e
parent65c3833ec2793747961f532510feb4fbb52fd6a6
parentd88db4d34bad1f4e140217f425300b417b448b64
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5184 from alexnask/typeof_extern_call

Extern functions are now evaluated to undefined values at comptime in TypeOf calls.

3 files changed, 104 insertions(+), 0 deletions(-)

src/ir.cpp+32
......@@ -15419,6 +15419,12 @@ static IrInstGen *ir_get_deref(IrAnalyze *ira, IrInst* source_instruction, IrIns
1541915419 }
1542015420 if (instr_is_comptime(ptr)) {
1542115421 if (ptr->value->special == ConstValSpecialUndef) {
15422 // If we are in a TypeOf call, we return an undefined value instead of erroring
15423 // since we know the type.
15424 if (get_scope_typeof(source_instruction->scope)) {
15425 return ir_const_undef(ira, source_instruction, child_type);
15426 }
15427
1542215428 ir_add_error(ira, &ptr->base, buf_sprintf("attempt to dereference undefined value"));
1542315429 return ira->codegen->invalid_inst_gen;
1542415430 }
......@@ -19720,6 +19726,20 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
1972019726 }
1972119727
1972219728 if (modifier == CallModifierCompileTime) {
19729 // If we are evaluating an extern function in a TypeOf call, we can return an undefined value
19730 // of its return type.
19731 if (fn_entry != nullptr && get_scope_typeof(source_instr->scope) != nullptr &&
19732 fn_proto_node->data.fn_proto.is_extern) {
19733
19734 assert(fn_entry->body_node == nullptr);
19735 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
19736 ZigType *return_type = ir_analyze_type_expr(ira, source_instr->scope, return_type_node);
19737 if (type_is_invalid(return_type))
19738 return ira->codegen->invalid_inst_gen;
19739
19740 return ir_const_undef(ira, source_instr, return_type);
19741 }
19742
1972319743 // No special handling is needed for compile time evaluation of generic functions.
1972419744 if (!fn_entry || fn_entry->body_node == nullptr) {
1972519745 ir_add_error(ira, &fn_ref->base, buf_sprintf("unable to evaluate constant expression"));
......@@ -19792,6 +19812,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
1979219812 AstNode *body_node = fn_entry->body_node;
1979319813 ZigValue *result_ptr;
1979419814 create_result_ptr(ira->codegen, return_type, &result, &result_ptr);
19815
1979519816 if ((err = ir_eval_const_value(ira->codegen, exec_scope, body_node, result_ptr,
1979619817 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,
1979719818 fn_entry, nullptr, source_instr->source_node, nullptr, ira->new_irb.exec, return_type_node,
......@@ -21862,6 +21883,11 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
2186221883 return ir_analyze_inferred_field_ptr(ira, field_name, source_instr, container_ptr, bare_type);
2186321884 }
2186421885
21886 // Tracks wether we should return an undefined value of the correct type.
21887 // We do this if the container pointer is undefined and we are in a TypeOf call.
21888 bool return_undef = container_ptr->value->special == ConstValSpecialUndef && \
21889 get_scope_typeof(source_instr->scope) != nullptr;
21890
2186521891 if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusZeroBitsKnown)))
2186621892 return ira->codegen->invalid_inst_gen;
2186721893
......@@ -21869,6 +21895,12 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
2186921895 if (bare_type->id == ZigTypeIdStruct) {
2187021896 TypeStructField *field = find_struct_type_field(bare_type, field_name);
2187121897 if (field != nullptr) {
21898 if (return_undef) {
21899 ZigType *field_ptr_type = get_pointer_to_type(ira->codegen, resolve_struct_field_type(ira->codegen, field),
21900 container_ptr->value->type->data.pointer.is_const);
21901 return ir_const_undef(ira, source_instr, field_ptr_type);
21902 }
21903
2187221904 return ir_analyze_struct_field_ptr(ira, source_instr, field, container_ptr, bare_type, initializing);
2187321905 } else {
2187421906 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
test/stage1/behavior.zig+1
......@@ -44,6 +44,7 @@ comptime {
4444 _ = @import("behavior/bugs/3384.zig");
4545 _ = @import("behavior/bugs/3586.zig");
4646 _ = @import("behavior/bugs/3742.zig");
47 _ = @import("behavior/bugs/4328.zig");
4748 _ = @import("behavior/bugs/4560.zig");
4849 _ = @import("behavior/bugs/4769_a.zig");
4950 _ = @import("behavior/bugs/4769_b.zig");
test/stage1/behavior/bugs/4328.zig created+71
......@@ -0,0 +1,71 @@
1const expectEqual = @import("std").testing.expectEqual;
2
3const FILE = extern struct {
4 dummy_field: u8,
5};
6
7extern fn printf([*c]const u8, ...) c_int;
8extern fn fputs([*c]const u8, noalias [*c]FILE) c_int;
9extern fn ftell([*c]FILE) c_long;
10extern fn fopen([*c]const u8, [*c]const u8) [*c]FILE;
11
12const S = extern struct {
13 state: c_short,
14
15 extern fn s_do_thing([*c]S, b: c_int) c_short;
16};
17
18test "Extern function calls in @TypeOf" {
19 const Test = struct {
20 fn test_fn_1(a: var, b: var) @TypeOf(printf("%d %s\n", a, b)) {
21 return 0;
22 }
23
24 fn test_fn_2(a: var) @TypeOf((S{ .state = 0 }).s_do_thing(a)) {
25 return 1;
26 }
27
28 fn doTheTest() void {
29 expectEqual(c_int, @TypeOf(test_fn_1(0, 42)));
30 expectEqual(c_short, @TypeOf(test_fn_2(0)));
31 }
32 };
33
34 Test.doTheTest();
35 comptime Test.doTheTest();
36}
37
38test "Peer resolution of extern function calls in @TypeOf" {
39 const Test = struct {
40 fn test_fn() @TypeOf(ftell(null), fputs(null, null)) {
41 return 0;
42 }
43
44 fn doTheTest() void {
45 expectEqual(c_long, @TypeOf(test_fn()));
46 }
47 };
48
49 Test.doTheTest();
50 comptime Test.doTheTest();
51}
52
53test "Extern function calls, dereferences and field access in @TypeOf" {
54 const Test = struct {
55 fn test_fn_1(a: c_long) @TypeOf(fopen("test", "r").*) {
56 return .{ .dummy_field = 0 };
57 }
58
59 fn test_fn_2(a: var) @TypeOf(fopen("test", "r").*.dummy_field) {
60 return 255;
61 }
62
63 fn doTheTest() void {
64 expectEqual(FILE, @TypeOf(test_fn_1(0)));
65 expectEqual(u8, @TypeOf(test_fn_2(0)));
66 }
67 };
68
69 Test.doTheTest();
70 comptime Test.doTheTest();
71}
\ No newline at end of file