fix incorrect error union const value generation

closes #1442

zig needed to insert explicit padding into this structure before
it got bitcasted.
This commit is contained in:
Andrew Kelley 2018-09-11 15:16:50 -04:00
parent dd1338b0e6
commit 7dd3c3814d
No known key found for this signature in database
GPG Key ID: 4E7CD66038A4D47C
5 changed files with 73 additions and 28 deletions

View File

@ -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:

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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");

11
test/cases/bugs/1442.zig Normal file
View File

@ -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);
}