mirror of
https://github.com/ziglang/zig.git
synced 2026-01-30 19:23:37 +00:00
simple self-referential struct is working now
This commit is contained in:
parent
0d6a6c76ea
commit
26b79ac90e
202
src/analyze.cpp
202
src/analyze.cpp
@ -955,6 +955,126 @@ ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, Zig
|
||||
return analyze_const_value_allow_lazy(g, scope, node, type_entry, type_name, false);
|
||||
}
|
||||
|
||||
static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type,
|
||||
bool *is_zero_bits)
|
||||
{
|
||||
Error err;
|
||||
if (type_val->special != ConstValSpecialLazy) {
|
||||
assert(type_val->special == ConstValSpecialStatic);
|
||||
if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusZeroBitsKnown)))
|
||||
return err;
|
||||
*is_zero_bits = (type_val->data.x_type->abi_size == 0);
|
||||
return ErrorNone;
|
||||
}
|
||||
switch (type_val->data.x_lazy->id) {
|
||||
case LazyValueIdInvalid:
|
||||
case LazyValueIdAlignOf:
|
||||
zig_unreachable();
|
||||
case LazyValueIdPtrType: {
|
||||
LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy);
|
||||
if (lazy_ptr_type->elem_type == parent_type) {
|
||||
// Does a struct which contains a pointer field to itself have bits? Yes.
|
||||
*is_zero_bits = false;
|
||||
return ErrorNone;
|
||||
} else {
|
||||
if ((err = type_resolve(g, lazy_ptr_type->elem_type, ResolveStatusZeroBitsKnown)))
|
||||
return err;
|
||||
*is_zero_bits = type_has_bits(lazy_ptr_type->elem_type);
|
||||
return ErrorNone;
|
||||
}
|
||||
}
|
||||
case LazyValueIdSliceType:
|
||||
*is_zero_bits = false;
|
||||
return ErrorNone;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type) {
|
||||
if (type_val->special != ConstValSpecialLazy) {
|
||||
assert(type_val->special == ConstValSpecialStatic);
|
||||
*is_opaque_type = (type_val->data.x_type->id == ZigTypeIdOpaque);
|
||||
return ErrorNone;
|
||||
}
|
||||
switch (type_val->data.x_lazy->id) {
|
||||
case LazyValueIdInvalid:
|
||||
case LazyValueIdAlignOf:
|
||||
zig_unreachable();
|
||||
case LazyValueIdSliceType:
|
||||
case LazyValueIdPtrType:
|
||||
*is_opaque_type = false;
|
||||
return ErrorNone;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type) {
|
||||
if (type_val->special != ConstValSpecialLazy) {
|
||||
return type_requires_comptime(g, type_val->data.x_type, parent_type);
|
||||
}
|
||||
switch (type_val->data.x_lazy->id) {
|
||||
case LazyValueIdInvalid:
|
||||
case LazyValueIdAlignOf:
|
||||
zig_unreachable();
|
||||
case LazyValueIdSliceType: {
|
||||
LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy);
|
||||
return type_requires_comptime(g, lazy_slice_type->elem_type, parent_type);
|
||||
}
|
||||
case LazyValueIdPtrType: {
|
||||
LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy);
|
||||
return type_requires_comptime(g, lazy_ptr_type->elem_type, parent_type);
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, size_t *abi_align) {
|
||||
Error err;
|
||||
if (type_val->special != ConstValSpecialLazy) {
|
||||
assert(type_val->special == ConstValSpecialStatic);
|
||||
if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusAlignmentKnown)))
|
||||
return err;
|
||||
*abi_align = type_val->data.x_type->abi_align;
|
||||
return ErrorNone;
|
||||
}
|
||||
switch (type_val->data.x_lazy->id) {
|
||||
case LazyValueIdInvalid:
|
||||
case LazyValueIdAlignOf:
|
||||
zig_unreachable();
|
||||
case LazyValueIdSliceType:
|
||||
case LazyValueIdPtrType:
|
||||
*abi_align = g->builtin_types.entry_usize->abi_align;
|
||||
return ErrorNone;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ConstExprValue *type_val) {
|
||||
if (type_val->special != ConstValSpecialLazy) {
|
||||
return type_has_one_possible_value(g, type_val->data.x_type);
|
||||
}
|
||||
switch (type_val->data.x_lazy->id) {
|
||||
case LazyValueIdInvalid:
|
||||
case LazyValueIdAlignOf:
|
||||
zig_unreachable();
|
||||
case LazyValueIdSliceType:
|
||||
return OnePossibleValueNo; // it has the len field
|
||||
case LazyValueIdPtrType: {
|
||||
Error err;
|
||||
bool zero_bits;
|
||||
if ((err = type_val_resolve_zero_bits(g, type_val, nullptr, &zero_bits))) {
|
||||
return OnePossibleValueInvalid;
|
||||
}
|
||||
if (zero_bits) {
|
||||
return OnePossibleValueYes;
|
||||
} else {
|
||||
return OnePossibleValueNo;
|
||||
}
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
|
||||
ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr);
|
||||
if (type_is_invalid(result->type))
|
||||
@ -1604,14 +1724,38 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
|
||||
|
||||
uint32_t *host_int_bytes = packed ? allocate<uint32_t>(struct_type->data.structure.gen_field_count) : nullptr;
|
||||
|
||||
// Resolve sizes of all the field types. Done before the offset loop because the offset
|
||||
// loop has to look ahead.
|
||||
// Resolve types for fields and then resolve sizes of all the field types.
|
||||
// This is done before the offset loop because the offset loop has to look ahead.
|
||||
for (size_t i = 0; i < field_count; i += 1) {
|
||||
AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
|
||||
TypeStructField *field = &struct_type->data.structure.fields[i];
|
||||
|
||||
if ((err = ir_resolve_lazy(g, field_source_node, field->type_val))) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
return err;
|
||||
}
|
||||
field->type_entry = field->type_val->data.x_type;
|
||||
|
||||
if ((err = type_resolve(g, field->type_entry, ResolveStatusSizeKnown))) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (struct_type->data.structure.layout == ContainerLayoutExtern &&
|
||||
!type_allowed_in_extern(g, field->type_entry))
|
||||
{
|
||||
add_node_error(g, field_source_node,
|
||||
buf_sprintf("extern structs cannot contain fields of type '%s'",
|
||||
buf_ptr(&field->type_entry->name)));
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
} else if (packed) {
|
||||
if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field->type_entry, field_source_node))) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t packed_bits_offset = 0;
|
||||
@ -2133,40 +2277,33 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
|
||||
ZigType *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
|
||||
type_struct_field->type_entry = field_type;
|
||||
if (type_is_invalid(field_type)) {
|
||||
ConstExprValue *field_type_val = analyze_const_value_allow_lazy(g, scope,
|
||||
field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, true);
|
||||
if (type_is_invalid(field_type_val->type)) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
assert(field_type_val->special != ConstValSpecialRuntime);
|
||||
type_struct_field->type_val = field_type_val;
|
||||
if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
|
||||
if (struct_type->data.structure.layout == ContainerLayoutExtern &&
|
||||
!type_allowed_in_extern(g, field_type))
|
||||
{
|
||||
add_node_error(g, field_node,
|
||||
buf_sprintf("extern structs cannot contain fields of type '%s'",
|
||||
buf_ptr(&field_type->name)));
|
||||
bool field_is_opaque_type;
|
||||
if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
} else if (struct_type->data.structure.layout == ContainerLayoutPacked) {
|
||||
if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_node))) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
}
|
||||
|
||||
type_struct_field->src_index = i;
|
||||
type_struct_field->gen_index = SIZE_MAX;
|
||||
|
||||
if (field_type->id == ZigTypeIdOpaque) {
|
||||
if (field_is_opaque_type) {
|
||||
add_node_error(g, field_node->data.struct_field.type,
|
||||
buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs"));
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
switch (type_requires_comptime(g, field_type, struct_type)) {
|
||||
|
||||
type_struct_field->src_index = i;
|
||||
type_struct_field->gen_index = SIZE_MAX;
|
||||
|
||||
switch (type_val_resolve_requires_comptime(g, field_type_val, struct_type)) {
|
||||
case ReqCompTimeYes:
|
||||
struct_type->data.structure.requires_comptime = true;
|
||||
break;
|
||||
@ -2177,7 +2314,12 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!type_has_bits(field_type))
|
||||
bool field_is_zero_bits;
|
||||
if ((err = type_val_resolve_zero_bits(g, field_type_val, struct_type, &field_is_zero_bits))) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
if (field_is_zero_bits)
|
||||
continue;
|
||||
|
||||
type_struct_field->gen_index = gen_field_index;
|
||||
@ -2234,21 +2376,17 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
|
||||
if (field->gen_index == SIZE_MAX)
|
||||
continue;
|
||||
|
||||
src_assert(field->type_entry != nullptr, decl_node);
|
||||
|
||||
// TODO: https://github.com/ziglang/zig/issues/1512
|
||||
size_t this_field_align;
|
||||
if (packed) {
|
||||
// TODO: https://github.com/ziglang/zig/issues/1512
|
||||
this_field_align = 1;
|
||||
} else {
|
||||
if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) {
|
||||
if ((err = type_val_resolve_abi_align(g, field->type_val, &this_field_align))) {
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
return err;
|
||||
}
|
||||
this_field_align = field->type_entry->abi_align;
|
||||
}
|
||||
|
||||
// TODO: https://github.com/ziglang/zig/issues/1512
|
||||
if (this_field_align > struct_type->abi_align) {
|
||||
struct_type->abi_align = this_field_align;
|
||||
}
|
||||
@ -4725,7 +4863,7 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
|
||||
case ZigTypeIdStruct:
|
||||
for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
|
||||
TypeStructField *field = &type_entry->data.structure.fields[i];
|
||||
switch (type_has_one_possible_value(g, field->type_entry)) {
|
||||
switch (type_val_resolve_has_one_possible_value(g, field->type_val)) {
|
||||
case OnePossibleValueInvalid:
|
||||
return OnePossibleValueInvalid;
|
||||
case OnePossibleValueNo:
|
||||
|
||||
18
src/ir.cpp
18
src/ir.cpp
@ -10814,10 +10814,6 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod
|
||||
|
||||
if (!allow_lazy) {
|
||||
if ((err = ir_resolve_lazy(codegen, node, result))) {
|
||||
if (codegen->trace_err != nullptr) {
|
||||
codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node,
|
||||
buf_create_from_str("referenced here"));
|
||||
}
|
||||
return &codegen->invalid_instruction->value;
|
||||
}
|
||||
}
|
||||
@ -25429,7 +25425,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) {
|
||||
static Error ir_resolve_lazy_raw(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) {
|
||||
Error err;
|
||||
if (val->special != ConstValSpecialLazy)
|
||||
return ErrorNone;
|
||||
@ -25491,3 +25487,15 @@ Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *va
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) {
|
||||
Error err;
|
||||
if ((err = ir_resolve_lazy_raw(codegen, source_node, val))) {
|
||||
if (codegen->trace_err != nullptr) {
|
||||
codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node,
|
||||
buf_create_from_str("referenced here"));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user