From 2a25398c869fcdefe8b6508974a5c463ca833520 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 24 Dec 2017 04:10:26 -0500 Subject: [PATCH] fix segfault when passing union enum with sub byte... ...field to const slice parameter we use a packed struct internally to represent a const array of disparate union values, and needed to update the internal getelementptr instruction to recognize that. closes #664 --- src/codegen.cpp | 26 +++++++++++++++++++------- std/debug/index.zig | 2 +- test/cases/union.zig | 15 +++++++++++++++ 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 339c643425..552467989e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3705,12 +3705,24 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar ConstParent *parent = &array_const_val->data.x_array.s_none.parent; LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent); - TypeTableEntry *usize = g->builtin_types.entry_usize; - LLVMValueRef indices[] = { - LLVMConstNull(usize->type_ref), - LLVMConstInt(usize->type_ref, index, false), - }; - return LLVMConstInBoundsGEP(base_ptr, indices, 2); + LLVMTypeKind el_type = LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(base_ptr))); + if (el_type == LLVMArrayTypeKind) { + TypeTableEntry *usize = g->builtin_types.entry_usize; + LLVMValueRef indices[] = { + LLVMConstNull(usize->type_ref), + LLVMConstInt(usize->type_ref, index, false), + }; + return LLVMConstInBoundsGEP(base_ptr, indices, 2); + } else if (el_type == LLVMStructTypeKind) { + TypeTableEntry *u32 = g->builtin_types.entry_u32; + LLVMValueRef indices[] = { + LLVMConstNull(u32->type_ref), + LLVMConstInt(u32->type_ref, index, false), + }; + return LLVMConstInBoundsGEP(base_ptr, indices, 2); + } else { + zig_unreachable(); + } } static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) { @@ -3732,7 +3744,7 @@ static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *un TypeTableEntry *u32 = g->builtin_types.entry_u32; LLVMValueRef indices[] = { LLVMConstNull(u32->type_ref), - LLVMConstInt(u32->type_ref, 0, false), + LLVMConstInt(u32->type_ref, 0, false), // TODO test const union with more aligned tag type than payload }; return LLVMConstInBoundsGEP(base_ptr, indices, 2); } diff --git a/std/debug/index.zig b/std/debug/index.zig index 3f722b494d..251b6f6f93 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -8,7 +8,7 @@ const DW = std.dwarf; const ArrayList = std.ArrayList; const builtin = @import("builtin"); -pub use @import("./failing_allocator.zig"); +pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator; error MissingDebugInfo; error InvalidDebugInfo; diff --git a/test/cases/union.zig b/test/cases/union.zig index 90d869289f..6db43fc14b 100644 --- a/test/cases/union.zig +++ b/test/cases/union.zig @@ -220,3 +220,18 @@ fn assertIsTheUnion2Item1(value: &const TheUnion2) { assert(*value == TheUnion2.Item1); } + +pub const PackThis = union(enum) { + Invalid: bool, + StringLiteral: u2, +}; + +test "constant packed union" { + testConstPackedUnion([]PackThis { + PackThis { .StringLiteral = 1 }, + }); +} + +fn testConstPackedUnion(expected_tokens: []const PackThis) { + assert(expected_tokens[0].StringLiteral == 1); +}