diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-08-22 14:46:26 -0400 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2019-08-22 14:46:26 -0400 |
| commit | 26b79ac90ee8cf17f28b0584c773be759e0e49bd (patch) | |
| tree | 78fc31e987e4d1ef8ee56d2da775ef1cea9b52d9 | |
| parent | 0d6a6c76eabcd020c5f58dc4667766b0e2756dfa (diff) | |
| download | zig-26b79ac90ee8cf17f28b0584c773be759e0e49bd.tar.gz zig-26b79ac90ee8cf17f28b0584c773be759e0e49bd.zip | |
simple self-referential struct is working now
| -rw-r--r-- | src/analyze.cpp | 200 | ||||
| -rw-r--r-- | src/ir.cpp | 18 |
2 files changed, 182 insertions, 36 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index ee67f259f0..a4ee17d56c 100644 --- a/src/analyze.cpp +++ b/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 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: diff --git a/src/ir.cpp b/src/ir.cpp index e64098be01..92b8598442 100644 --- a/src/ir.cpp +++ b/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; +} |
