zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 44f8e6a534bd2977c741afdbf5ba9df49bde0fd9 (tree)
parent 52879b50d9fe221c46e62e11c6815da64c70638e
Author: LemonBoy <thatlemon@gmail.com>
Date:   Wed, 21 Oct 2020 15:35:40 +0200

stage1: Fix edge case in Union ZigValue generation

Unions that passed the one_possible_value check were incorrectly
generated, none of their internal fields were initialized.

Fixes #6758

Diffstat:
Msrc/stage1/analyze.cpp | 16+++++++++++++++-
Mtest/stage1/behavior/union.zig | 24++++++++++++++++++++++++
2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp @@ -5973,7 +5973,8 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { } ZigType *field_type = resolve_struct_field_type(g, field); assert(field_type != nullptr); - result->data.x_struct.fields[i] = get_the_one_possible_value(g, field_type); + copy_const_val(g, result->data.x_struct.fields[i], + get_the_one_possible_value(g, field_type)); } } else if (result->type->id == ZigTypeIdArray) { // The elements array cannot be left unpopulated @@ -5986,7 +5987,20 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i]; copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type)); } + } else if (result->type->id == ZigTypeIdUnion) { + // The payload/tag fields cannot be left unpopulated + ZigType *union_type = result->type; + assert(union_type->data.unionation.src_field_count == 1); + TypeUnionField *only_field = &union_type->data.unionation.fields[0]; + ZigType *field_type = resolve_union_field_type(g, only_field); + assert(field_type); + bigint_init_unsigned(&result->data.x_union.tag, 0); + result->data.x_union.payload = g->pass1_arena->create<ZigValue>(); + copy_const_val(g, result->data.x_union.payload, + get_the_one_possible_value(g, field_type)); } else if (result->type->id == ZigTypeIdPointer) { + // Make sure nobody can modify the constant value + result->data.x_ptr.mut = ConstPtrMutComptimeConst; result->data.x_ptr.special = ConstPtrSpecialRef; result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type); } diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig @@ -713,3 +713,27 @@ test "switching on non exhaustive union" { S.doTheTest(); comptime S.doTheTest(); } + +test "containers with single-field enums" { + const S = struct { + const A = union(enum) { f1 }; + const B = union(enum) { f1: void }; + const C = struct { a: A }; + const D = struct { a: B }; + + fn doTheTest() void { + var array1 = [1]A{A{ .f1 = {} }}; + var array2 = [1]B{B{ .f1 = {} }}; + expect(array1[0] == .f1); + expect(array2[0] == .f1); + + var struct1 = C{ .a = A{ .f1 = {} } }; + var struct2 = D{ .a = B{ .f1 = {} } }; + expect(struct1.a == .f1); + expect(struct2.a == .f1); + } + }; + + S.doTheTest(); + comptime S.doTheTest(); +}