Commit 8e96922f31
Changed files (4)
test
stage1
behavior
src/analyze.cpp
@@ -858,10 +858,12 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
entry->data.structure.fields[slice_ptr_index]->type_entry = ptr_type;
entry->data.structure.fields[slice_ptr_index]->src_index = slice_ptr_index;
entry->data.structure.fields[slice_ptr_index]->gen_index = 0;
+ entry->data.structure.fields[slice_ptr_index]->offset = 0;
entry->data.structure.fields[slice_len_index]->name = len_field_name;
entry->data.structure.fields[slice_len_index]->type_entry = g->builtin_types.entry_usize;
entry->data.structure.fields[slice_len_index]->src_index = slice_len_index;
entry->data.structure.fields[slice_len_index]->gen_index = 1;
+ entry->data.structure.fields[slice_len_index]->offset = ptr_type->abi_size;
entry->data.structure.fields_by_name.put(ptr_field_name, entry->data.structure.fields[slice_ptr_index]);
entry->data.structure.fields_by_name.put(len_field_name, entry->data.structure.fields[slice_len_index]);
src/codegen.cpp
@@ -7140,12 +7140,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
ZigType *type_entry = const_val->type;
assert(type_has_bits(g, type_entry));
-check: switch (const_val->special) {
+ if (const_val->special == ConstValSpecialLazy &&
+ (err = ir_resolve_lazy(g, nullptr, const_val)))
+ codegen_report_errors_and_exit(g);
+
+ switch (const_val->special) {
case ConstValSpecialLazy:
- if ((err = ir_resolve_lazy(g, nullptr, const_val))) {
- codegen_report_errors_and_exit(g);
- }
- goto check;
case ConstValSpecialRuntime:
zig_unreachable();
case ConstValSpecialUndef:
@@ -7222,12 +7222,26 @@ check: switch (const_val->special) {
make_unnamed_struct = false;
}
+
LLVMValueRef fields[] = {
child_val,
maybe_val,
+ nullptr,
};
if (make_unnamed_struct) {
- return LLVMConstStruct(fields, 2, false);
+ LLVMValueRef result = LLVMConstStruct(fields, 2, false);
+ 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 = LLVMABISizeOfType(g->target_data_ref, get_llvm_type(g, type_entry));
+ 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(get_llvm_type(g, type_entry), fields, 2);
}
@@ -7316,32 +7330,50 @@ check: switch (const_val->special) {
continue;
}
ZigValue *field_val = const_val->data.x_struct.fields[i];
- assert(field_val->type != nullptr);
- if ((err = ensure_const_val_repr(nullptr, g, nullptr, field_val,
- type_struct_field->type_entry)))
- {
+ ZigType *field_type = field_val->type;
+ assert(field_type != nullptr);
+ if ((err = ensure_const_val_repr(nullptr, g, nullptr, field_val, field_type))) {
zig_unreachable();
}
LLVMValueRef val = gen_const_val(g, field_val, "");
- fields[type_struct_field->gen_index] = val;
- make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_val->type, val);
-
- size_t end_pad_gen_index = (i + 1 < src_field_count) ?
- type_entry->data.structure.fields[i + 1]->gen_index :
- type_entry->data.structure.gen_field_count;
- size_t next_offset = (i + 1 < src_field_count) ?
- type_entry->data.structure.fields[i + 1]->offset : type_entry->abi_size;
- if (end_pad_gen_index != SIZE_MAX) {
- for (size_t gen_i = type_struct_field->gen_index + 1; gen_i < end_pad_gen_index;
- gen_i += 1)
- {
- size_t pad_bytes = next_offset -
- (type_struct_field->offset + type_struct_field->type_entry->abi_size);
- LLVMTypeRef llvm_array_type = LLVMArrayType(LLVMInt8Type(), pad_bytes);
- fields[gen_i] = LLVMGetUndef(llvm_array_type);
+ make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, field_type, val);
+
+ // Find the next runtime field
+ size_t next_rt_gen_index = type_entry->data.structure.gen_field_count;
+ size_t next_offset = type_entry->abi_size;
+ for (size_t j = i + 1; j < src_field_count; j++) {
+ const size_t index = type_entry->data.structure.fields[j]->gen_index;
+ const size_t offset = type_entry->data.structure.fields[j]->offset;
+
+ if (index != SIZE_MAX) {
+ next_rt_gen_index = index;
+ next_offset = offset;
+ break;
}
}
+
+ // How much padding is needed to reach the next field
+ const size_t pad_bytes = next_offset -
+ (type_struct_field->offset + LLVMABISizeOfType(g->target_data_ref, LLVMTypeOf(val)));
+ // Catch underflow
+ assert((ssize_t)pad_bytes >= 0);
+
+ if (type_struct_field->gen_index + 1 != next_rt_gen_index) {
+ // If there's a hole between this field and the next
+ // we have an alignment gap to fill
+ fields[type_struct_field->gen_index] = val;
+ fields[type_struct_field->gen_index + 1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_bytes));
+ } else if (pad_bytes != 0) {
+ LLVMValueRef padded_val[] = {
+ val,
+ LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_bytes)),
+ };
+ fields[type_struct_field->gen_index] = LLVMConstStruct(padded_val, 2, true);
+ make_unnamed_struct = true;
+ } else {
+ fields[type_struct_field->gen_index] = val;
+ }
}
}
if (make_unnamed_struct) {
test/stage1/behavior/optional.zig
@@ -1,4 +1,7 @@
-const expect = @import("std").testing.expect;
+const std = @import("std");
+const testing = std.testing;
+const expect = testing.expect;
+const expectEqual = testing.expectEqual;
pub const EmptyStruct = struct {};
@@ -198,3 +201,35 @@ test "0-bit child type coerced to optional" {
S.doTheTest();
comptime S.doTheTest();
}
+
+test "array of optional unaligned types" {
+ const Enum = enum { one, two, three };
+
+ const SomeUnion = union(enum) {
+ Num: Enum,
+ Other: u32,
+ };
+
+ const values = [_]?SomeUnion{
+ SomeUnion{ .Num = .one },
+ SomeUnion{ .Num = .two },
+ SomeUnion{ .Num = .three },
+ SomeUnion{ .Num = .one },
+ SomeUnion{ .Num = .two },
+ SomeUnion{ .Num = .three },
+ };
+
+ // The index must be a runtime value
+ var i: usize = 0;
+ expectEqual(Enum.one, values[i].?.Num);
+ i += 1;
+ expectEqual(Enum.two, values[i].?.Num);
+ i += 1;
+ expectEqual(Enum.three, values[i].?.Num);
+ i += 1;
+ expectEqual(Enum.one, values[i].?.Num);
+ i += 1;
+ expectEqual(Enum.two, values[i].?.Num);
+ i += 1;
+ expectEqual(Enum.three, values[i].?.Num);
+}
test/stage1/behavior/struct.zig
@@ -825,3 +825,19 @@ test "self-referencing struct via array member" {
x = T{ .children = .{&x} };
expect(x.children[0] == &x);
}
+
+test "struct with union field" {
+ const Value = struct {
+ ref: u32 = 2,
+ kind: union(enum) {
+ None: usize,
+ Bool: bool,
+ },
+ };
+
+ var True = Value{
+ .kind = .{ .Bool = true },
+ };
+ expectEqual(@as(u32, 2), True.ref);
+ expectEqual(true, True.kind.Bool);
+}