Commit 7dd3c3814d

Andrew Kelley <superjoe30@gmail.com>
2018-09-11 21:16:50
fix incorrect error union const value generation
closes #1442 zig needed to insert explicit padding into this structure before it got bitcasted.
1 parent dd1338b
Changed files (5)
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:
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);
                     }
                 }
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;
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);
+}
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");