simple self-referential struct is working now

This commit is contained in:
Andrew Kelley 2019-08-22 14:46:26 -04:00
parent 0d6a6c76ea
commit 26b79ac90e
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
2 changed files with 183 additions and 37 deletions

View File

@ -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:

View File

@ -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;
}