mirror of
https://github.com/ziglang/zig.git
synced 2026-01-03 12:03:19 +00:00
Merge pull request #5184 from alexnask/typeof_extern_call
Extern functions are now evaluated to undefined values at comptime in TypeOf calls.
This commit is contained in:
commit
4c8b937fb0
32
src/ir.cpp
32
src/ir.cpp
@ -15419,6 +15419,12 @@ static IrInstGen *ir_get_deref(IrAnalyze *ira, IrInst* source_instruction, IrIns
|
||||
}
|
||||
if (instr_is_comptime(ptr)) {
|
||||
if (ptr->value->special == ConstValSpecialUndef) {
|
||||
// If we are in a TypeOf call, we return an undefined value instead of erroring
|
||||
// since we know the type.
|
||||
if (get_scope_typeof(source_instruction->scope)) {
|
||||
return ir_const_undef(ira, source_instruction, child_type);
|
||||
}
|
||||
|
||||
ir_add_error(ira, &ptr->base, buf_sprintf("attempt to dereference undefined value"));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
@ -19720,6 +19726,20 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
|
||||
}
|
||||
|
||||
if (modifier == CallModifierCompileTime) {
|
||||
// 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 && get_scope_typeof(source_instr->scope) != nullptr &&
|
||||
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) {
|
||||
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,
|
||||
AstNode *body_node = fn_entry->body_node;
|
||||
ZigValue *result_ptr;
|
||||
create_result_ptr(ira->codegen, return_type, &result, &result_ptr);
|
||||
|
||||
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,
|
||||
@ -21862,6 +21883,11 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
|
||||
return ir_analyze_inferred_field_ptr(ira, field_name, source_instr, container_ptr, bare_type);
|
||||
}
|
||||
|
||||
// Tracks wether we should return an undefined value of the correct type.
|
||||
// We do this if the container pointer is undefined and we are in a TypeOf call.
|
||||
bool return_undef = container_ptr->value->special == ConstValSpecialUndef && \
|
||||
get_scope_typeof(source_instr->scope) != nullptr;
|
||||
|
||||
if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
||||
@ -21869,6 +21895,12 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
|
||||
if (bare_type->id == ZigTypeIdStruct) {
|
||||
TypeStructField *field = find_struct_type_field(bare_type, field_name);
|
||||
if (field != nullptr) {
|
||||
if (return_undef) {
|
||||
ZigType *field_ptr_type = get_pointer_to_type(ira->codegen, resolve_struct_field_type(ira->codegen, field),
|
||||
container_ptr->value->type->data.pointer.is_const);
|
||||
return ir_const_undef(ira, source_instr, field_ptr_type);
|
||||
}
|
||||
|
||||
return ir_analyze_struct_field_ptr(ira, source_instr, field, container_ptr, bare_type, initializing);
|
||||
} else {
|
||||
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
|
||||
|
||||
@ -44,6 +44,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");
|
||||
|
||||
71
test/stage1/behavior/bugs/4328.zig
Normal file
71
test/stage1/behavior/bugs/4328.zig
Normal file
@ -0,0 +1,71 @@
|
||||
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;
|
||||
extern fn fopen([*c]const u8, [*c]const u8) [*c]FILE;
|
||||
|
||||
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_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_1(0, 42)));
|
||||
expectEqual(c_short, @TypeOf(test_fn_2(0)));
|
||||
}
|
||||
};
|
||||
|
||||
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 "Extern function calls, dereferences and field access in @TypeOf" {
|
||||
const Test = struct {
|
||||
fn test_fn_1(a: c_long) @TypeOf(fopen("test", "r").*) {
|
||||
return .{ .dummy_field = 0 };
|
||||
}
|
||||
|
||||
fn test_fn_2(a: var) @TypeOf(fopen("test", "r").*.dummy_field) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
fn doTheTest() void {
|
||||
expectEqual(FILE, @TypeOf(test_fn_1(0)));
|
||||
expectEqual(u8, @TypeOf(test_fn_2(0)));
|
||||
}
|
||||
};
|
||||
|
||||
Test.doTheTest();
|
||||
comptime Test.doTheTest();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user