From 7dd3c3814de0caf808bc112aa07044cdd8bba135 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Sep 2018 15:16:50 -0400 Subject: [PATCH] fix incorrect error union const value generation closes #1442 zig needed to insert explicit padding into this structure before it got bitcasted. --- src/analyze.cpp | 15 +++++++++++++-- src/codegen.cpp | 38 +++++++++++++++++++++++++++++--------- std/os/index.zig | 36 +++++++++++++++++++----------------- test/behavior.zig | 1 + test/cases/bugs/1442.zig | 11 +++++++++++ 5 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 test/cases/bugs/1442.zig diff --git a/src/analyze.cpp b/src/analyze.cpp index e0539df10b..07c7b94e25 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5882,12 +5882,23 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } case ZigTypeIdErrorUnion: { - buf_appendf(buf, "(error union %s constant)", buf_ptr(&type_entry->name)); + buf_appendf(buf, "%s(", buf_ptr(&type_entry->name)); + if (const_val->data.x_err_union.err == nullptr) { + render_const_value(g, buf, const_val->data.x_err_union.payload); + } else { + buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name), + buf_ptr(&const_val->data.x_err_union.err->name)); + } + buf_appendf(buf, ")"); return; } case ZigTypeIdUnion: { - buf_appendf(buf, "(union %s constant)", buf_ptr(&type_entry->name)); + uint64_t tag = bigint_as_unsigned(&const_val->data.x_union.tag); + TypeUnionField *field = &type_entry->data.unionation.fields[tag]; + buf_appendf(buf, "%s { .%s = ", buf_ptr(&type_entry->name), buf_ptr(field->name)); + render_const_value(g, buf, const_val->data.x_union.payload); + buf_append_str(buf, "}"); return; } case ZigTypeIdErrorSet: diff --git a/src/codegen.cpp b/src/codegen.cpp index 2548b3fa8c..5b6c53e8f8 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5870,13 +5870,17 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c if (make_unnamed_struct) { LLVMValueRef result = LLVMConstStruct(fields, 2, false); - size_t expected_sz = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); - size_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result)); - if (actual_sz < expected_sz) { - unsigned pad_sz = expected_sz - actual_sz; + uint64_t last_field_offset = LLVMOffsetOfElement(g->target_data_ref, LLVMTypeOf(result), 1); + uint64_t end_offset = last_field_offset + + LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(fields[1])); + uint64_t expected_sz = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); + unsigned pad_sz = expected_sz - end_offset; + if (pad_sz != 0) { fields[2] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)); result = LLVMConstStruct(fields, 3, false); } + uint64_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result)); + assert(actual_sz == expected_sz); return result; } else { return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); @@ -5917,13 +5921,29 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c err_payload_value = gen_const_val(g, payload_val, ""); make_unnamed_struct = is_llvm_value_unnamed_type(payload_val->type, err_payload_value); } - LLVMValueRef fields[] = { - err_tag_value, - err_payload_value, - }; if (make_unnamed_struct) { - return LLVMConstStruct(fields, 2, false); + uint64_t payload_off = LLVMOffsetOfElement(g->target_data_ref, type_entry->type_ref, 1); + uint64_t err_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(err_tag_value)); + unsigned pad_sz = payload_off - err_sz; + if (pad_sz == 0) { + LLVMValueRef fields[] = { + err_tag_value, + err_payload_value, + }; + return LLVMConstStruct(fields, 2, false); + } else { + LLVMValueRef fields[] = { + err_tag_value, + LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)), + err_payload_value, + }; + return LLVMConstStruct(fields, 3, false); + } } else { + LLVMValueRef fields[] = { + err_tag_value, + err_payload_value, + }; return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); } } diff --git a/std/os/index.zig b/std/os/index.zig index 3ab73a79ac..8e92fc23c5 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -343,23 +343,25 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void { const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len)); const rc = posix.write(fd, bytes.ptr + index, amt_to_write); const write_err = posix.getErrno(rc); - if (write_err > 0) { - return switch (write_err) { - posix.EINTR => continue, - posix.EINVAL, posix.EFAULT => unreachable, - posix.EAGAIN => PosixWriteError.WouldBlock, - posix.EBADF => PosixWriteError.FileClosed, - posix.EDESTADDRREQ => PosixWriteError.DestinationAddressRequired, - posix.EDQUOT => PosixWriteError.DiskQuota, - posix.EFBIG => PosixWriteError.FileTooBig, - posix.EIO => PosixWriteError.InputOutput, - posix.ENOSPC => PosixWriteError.NoSpaceLeft, - posix.EPERM => PosixWriteError.AccessDenied, - posix.EPIPE => PosixWriteError.BrokenPipe, - else => unexpectedErrorPosix(write_err), - }; + switch (write_err) { + 0 => { + index += rc; + continue; + }, + posix.EINTR => continue, + posix.EINVAL => unreachable, + posix.EFAULT => unreachable, + posix.EAGAIN => return PosixWriteError.WouldBlock, + posix.EBADF => return PosixWriteError.FileClosed, + posix.EDESTADDRREQ => return PosixWriteError.DestinationAddressRequired, + posix.EDQUOT => return PosixWriteError.DiskQuota, + posix.EFBIG => return PosixWriteError.FileTooBig, + posix.EIO => return PosixWriteError.InputOutput, + posix.ENOSPC => return PosixWriteError.NoSpaceLeft, + posix.EPERM => return PosixWriteError.AccessDenied, + posix.EPIPE => return PosixWriteError.BrokenPipe, + else => return unexpectedErrorPosix(write_err), } - index += rc; } } @@ -1614,7 +1616,7 @@ pub const Dir = struct { return null; } const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr); - if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{'.', '.'})) + if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{ '.', '.' })) continue; // Trust that Windows gives us valid UTF-16LE const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable; diff --git a/test/behavior.zig b/test/behavior.zig index cae8c4b0f3..869024f296 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -12,6 +12,7 @@ comptime { _ = @import("cases/bugs/1277.zig"); _ = @import("cases/bugs/1381.zig"); _ = @import("cases/bugs/1421.zig"); + _ = @import("cases/bugs/1442.zig"); _ = @import("cases/bugs/394.zig"); _ = @import("cases/bugs/655.zig"); _ = @import("cases/bugs/656.zig"); diff --git a/test/cases/bugs/1442.zig b/test/cases/bugs/1442.zig new file mode 100644 index 0000000000..d7057d9ed1 --- /dev/null +++ b/test/cases/bugs/1442.zig @@ -0,0 +1,11 @@ +const std = @import("std"); + +const Union = union(enum) { + Text: []const u8, + Color: u32, +}; + +test "const error union field alignment" { + var union_or_err: error!Union = Union{ .Color = 1234 }; + std.debug.assertOrPanic((union_or_err catch unreachable).Color == 1234); +}