Merge pull request #6428 from tadeokondrak/alignment-typeinfo-struct-union

Add alignment field to TypeInfo.UnionField and TypeInfo.StructField
This commit is contained in:
Alexandros Naskos
2020-10-02 02:56:18 +03:00
committed by GitHub
7 changed files with 111 additions and 75 deletions

View File

@@ -262,6 +262,7 @@ pub const TypeInfo = union(enum) {
field_type: type,
default_value: anytype,
is_comptime: bool,
alignment: comptime_int,
};
/// This data structure is used by the Zig language code generation and
@@ -318,6 +319,7 @@ pub const TypeInfo = union(enum) {
pub const UnionField = struct {
name: []const u8,
field_type: type,
alignment: comptime_int,
};
/// This data structure is used by the Zig language code generation and

View File

@@ -854,6 +854,7 @@ pub fn ArgsTuple(comptime Function: type) type {
.field_type = arg.arg_type.?,
.default_value = @as(?(arg.arg_type.?), null),
.is_comptime = false,
.alignment = @alignOf(arg.arg_type.?),
};
}
@@ -884,6 +885,7 @@ pub fn Tuple(comptime types: []const type) type {
.field_type = T,
.default_value = @as(?T, null),
.is_comptime = false,
.alignment = @alignOf(T),
};
}

View File

@@ -47,6 +47,7 @@ pub fn TrailerFlags(comptime Fields: type) type {
@as(?struct_field.field_type, null),
),
.is_comptime = false,
.alignment = @alignOf(?struct_field.field_type),
};
}
break :blk @Type(.{

View File

@@ -25027,7 +25027,7 @@ static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, IrInst *source_instr,
fields[2]->special = ConstValSpecialStatic;
fields[2]->type = ira->codegen->builtin_types.entry_bool;
fields[2]->data.x_bool = attrs_type->data.pointer.is_volatile;
// alignment: u32
// alignment: comptime_int
ensure_field_index(result->type, "alignment", 3);
fields[3]->type = ira->codegen->builtin_types.entry_num_lit_int;
if (attrs_type->data.pointer.explicit_alignment != 0) {
@@ -25431,11 +25431,17 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
union_field_val->special = ConstValSpecialStatic;
union_field_val->type = type_info_union_field_type;
ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2);
ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 3);
// field_type: type
inner_fields[1]->special = ConstValSpecialStatic;
inner_fields[1]->type = ira->codegen->builtin_types.entry_type;
inner_fields[1]->data.x_type = union_field->type_entry;
// alignment: comptime_int
inner_fields[2]->special = ConstValSpecialStatic;
inner_fields[2]->type = ira->codegen->builtin_types.entry_num_lit_int;
bigint_init_unsigned(&inner_fields[2]->data.x_bigint, union_field->align);
ZigValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(union_field->name), true);
@@ -25502,7 +25508,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
struct_field_val->special = ConstValSpecialStatic;
struct_field_val->type = type_info_struct_field_type;
ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 4);
ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 5);
inner_fields[1]->special = ConstValSpecialStatic;
inner_fields[1]->type = ira->codegen->builtin_types.entry_type;
@@ -25518,10 +25524,16 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
}
set_optional_payload(inner_fields[2], struct_field->init_val);
// is_comptime: bool
inner_fields[3]->special = ConstValSpecialStatic;
inner_fields[3]->type = ira->codegen->builtin_types.entry_bool;
inner_fields[3]->data.x_bool = struct_field->is_comptime;
// alignment: comptime_int
inner_fields[4]->special = ConstValSpecialStatic;
inner_fields[4]->type = ira->codegen->builtin_types.entry_num_lit_int;
bigint_init_unsigned(&inner_fields[4]->data.x_bigint, struct_field->align);
ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true);
@@ -25868,8 +25880,9 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
buf_sprintf("sentinels are only allowed on slices and unknown-length pointers"));
return ira->codegen->invalid_inst_gen->value->type;
}
BigInt *bi = get_const_field_lit_int(ira, source_instr->source_node, payload, "alignment", 3);
if (bi == nullptr)
BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, payload, "alignment", 3);
if (alignment == nullptr)
return ira->codegen->invalid_inst_gen->value->type;
bool is_const;
@@ -25896,7 +25909,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
is_const,
is_volatile,
ptr_len,
bigint_as_u32(bi),
bigint_as_u32(alignment),
0, // bit_offset_in_host
0, // host_int_bytes
is_allowzero,
@@ -26133,6 +26146,10 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
}
if ((err = get_const_field_bool(ira, source_instr->source_node, field_value, "is_comptime", 3, &field->is_comptime)))
return ira->codegen->invalid_inst_gen->value->type;
BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, field_value, "alignment", 4);
if (alignment == nullptr)
return ira->codegen->invalid_inst_gen->value->type;
field->align = bigint_as_u32(alignment);
}
return entry;
@@ -26302,6 +26319,10 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
return ira->codegen->invalid_inst_gen->value->type;
field->type_val = type_value;
field->type_entry = type_value->data.x_type;
BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, field_value, "alignment", 2);
if (alignment == nullptr)
return ira->codegen->invalid_inst_gen->value->type;
field->align = bigint_as_u32(alignment);
}
return entry;
}

View File

@@ -38,6 +38,61 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:20: error: TypeInfo.Enum.tag_type must be an integer type, not 'bool'",
});
cases.add("@Type for tagged union with extra enum field",
\\const TypeInfo = @import("builtin").TypeInfo;
\\const Tag = @Type(.{
\\ .Enum = .{
\\ .layout = .Auto,
\\ .tag_type = u2,
\\ .fields = &[_]TypeInfo.EnumField{
\\ .{ .name = "signed", .value = 0 },
\\ .{ .name = "unsigned", .value = 1 },
\\ .{ .name = "arst", .value = 2 },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ .is_exhaustive = true,
\\ },
\\});
\\const Tagged = @Type(.{
\\ .Union = .{
\\ .layout = .Auto,
\\ .tag_type = Tag,
\\ .fields = &[_]TypeInfo.UnionField{
\\ .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) },
\\ .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ },
\\});
\\export fn entry() void {
\\ var tagged = Tagged{ .signed = -1 };
\\ tagged = .{ .unsigned = 1 };
\\}
, &[_][]const u8{
"tmp.zig:15:23: error: enum field missing: 'arst'",
"tmp.zig:27:24: note: referenced here",
});
cases.add("@Type for union with opaque field",
\\const TypeInfo = @import("builtin").TypeInfo;
\\const Untagged = @Type(.{
\\ .Union = .{
\\ .layout = .Auto,
\\ .tag_type = null,
\\ .fields = &[_]TypeInfo.UnionField{
\\ .{ .name = "foo", .field_type = @Type(.Opaque), .alignment = 1 },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ },
\\});
\\export fn entry() void {
\\ _ = Untagged{};
\\}
, &[_][]const u8{
"tmp.zig:2:25: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
"tmp.zig:13:17: note: referenced here",
});
cases.add("slice sentinel mismatch",
\\export fn entry() void {
\\ const x = @import("std").meta.Vector(3, f32){ 25, 75, 5, 0 };
@@ -54,26 +109,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'",
});
cases.add("@Type for union with opaque field",
\\const TypeInfo = @import("builtin").TypeInfo;
\\const Untagged = @Type(.{
\\ .Union = .{
\\ .layout = .Auto,
\\ .tag_type = null,
\\ .fields = &[_]TypeInfo.UnionField{
\\ .{ .name = "foo", .field_type = @Type(.Opaque) },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ },
\\});
\\export fn entry() void {
\\ _ = Untagged{};
\\}
, &[_][]const u8{
"tmp.zig:2:25: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
"tmp.zig:13:17: note: referenced here",
});
cases.add("@Type for union with zero fields",
\\const TypeInfo = @import("builtin").TypeInfo;
\\const Untagged = @Type(.{
@@ -130,9 +165,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ .layout = .Auto,
\\ .tag_type = Tag,
\\ .fields = &[_]TypeInfo.UnionField{
\\ .{ .name = "signed", .field_type = i32 },
\\ .{ .name = "unsigned", .field_type = u32 },
\\ .{ .name = "arst", .field_type = f32 },
\\ .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) },
\\ .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) },
\\ .{ .name = "arst", .field_type = f32, .alignment = @alignOf(f32) },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ },
@@ -147,42 +182,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:27:24: note: referenced here",
});
cases.add("@Type for tagged union with extra enum field",
\\const TypeInfo = @import("builtin").TypeInfo;
\\const Tag = @Type(.{
\\ .Enum = .{
\\ .layout = .Auto,
\\ .tag_type = u2,
\\ .fields = &[_]TypeInfo.EnumField{
\\ .{ .name = "signed", .value = 0 },
\\ .{ .name = "unsigned", .value = 1 },
\\ .{ .name = "arst", .field_type = 2 },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ .is_exhaustive = true,
\\ },
\\});
\\const Tagged = @Type(.{
\\ .Union = .{
\\ .layout = .Auto,
\\ .tag_type = Tag,
\\ .fields = &[_]TypeInfo.UnionField{
\\ .{ .name = "signed", .field_type = i32 },
\\ .{ .name = "unsigned", .field_type = u32 },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ },
\\});
\\export fn entry() void {
\\ var tagged = Tagged{ .signed = -1 };
\\ tagged = .{ .unsigned = 1 };
\\}
, &[_][]const u8{
"tmp.zig:9:32: error: no member named 'field_type' in struct 'std.builtin.EnumField'",
"tmp.zig:18:21: note: referenced here",
"tmp.zig:27:18: note: referenced here",
});
cases.add("@Type with undefined",
\\comptime {
\\ _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } });
@@ -7592,7 +7591,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add( // fixed bug #2032
"compile diagnostic string for top level decl type",
"compile diagnostic string for top level decl type",
\\export fn entry() void {
\\ var foo: u32 = @This(){};
\\}

View File

@@ -320,8 +320,8 @@ test "Type.Union" {
.layout = .Auto,
.tag_type = null,
.fields = &[_]TypeInfo.UnionField{
.{ .name = "int", .field_type = i32 },
.{ .name = "float", .field_type = f32 },
.{ .name = "int", .field_type = i32, .alignment = @alignOf(f32) },
.{ .name = "float", .field_type = f32, .alignment = @alignOf(f32) },
},
.decls = &[_]TypeInfo.Declaration{},
},
@@ -336,8 +336,8 @@ test "Type.Union" {
.layout = .Packed,
.tag_type = null,
.fields = &[_]TypeInfo.UnionField{
.{ .name = "signed", .field_type = i32 },
.{ .name = "unsigned", .field_type = u32 },
.{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) },
.{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) },
},
.decls = &[_]TypeInfo.Declaration{},
},
@@ -363,8 +363,8 @@ test "Type.Union" {
.layout = .Auto,
.tag_type = Tag,
.fields = &[_]TypeInfo.UnionField{
.{ .name = "signed", .field_type = i32 },
.{ .name = "unsigned", .field_type = u32 },
.{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) },
.{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) },
},
.decls = &[_]TypeInfo.Declaration{},
},
@@ -392,7 +392,7 @@ test "Type.Union from Type.Enum" {
.layout = .Auto,
.tag_type = Tag,
.fields = &[_]TypeInfo.UnionField{
.{ .name = "working_as_expected", .field_type = u32 },
.{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) },
},
.decls = &[_]TypeInfo.Declaration{},
},
@@ -408,7 +408,7 @@ test "Type.Union from regular enum" {
.layout = .Auto,
.tag_type = E,
.fields = &[_]TypeInfo.UnionField{
.{ .name = "working_as_expected", .field_type = u32 },
.{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) },
},
.decls = &[_]TypeInfo.Declaration{},
},

View File

@@ -211,7 +211,9 @@ fn testUnion() void {
expect(notag_union_info.Union.tag_type == null);
expect(notag_union_info.Union.layout == .Auto);
expect(notag_union_info.Union.fields.len == 2);
expect(notag_union_info.Union.fields[0].alignment == @alignOf(void));
expect(notag_union_info.Union.fields[1].field_type == u32);
expect(notag_union_info.Union.fields[1].alignment == @alignOf(u32));
const TestExternUnion = extern union {
foo: *c_void,
@@ -229,13 +231,18 @@ test "type info: struct info" {
}
fn testStruct() void {
const unpacked_struct_info = @typeInfo(TestUnpackedStruct);
expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
const struct_info = @typeInfo(TestStruct);
expect(struct_info == .Struct);
expect(struct_info.Struct.layout == .Packed);
expect(struct_info.Struct.fields.len == 4);
expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize));
expect(struct_info.Struct.fields[2].field_type == *TestStruct);
expect(struct_info.Struct.fields[2].default_value == null);
expect(struct_info.Struct.fields[3].default_value.? == 4);
expect(struct_info.Struct.fields[3].alignment == 1);
expect(struct_info.Struct.decls.len == 2);
expect(struct_info.Struct.decls[0].is_pub);
expect(!struct_info.Struct.decls[0].data.Fn.is_extern);
@@ -244,8 +251,12 @@ fn testStruct() void {
expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void);
}
const TestUnpackedStruct = struct {
fieldA: u32 = 4,
};
const TestStruct = packed struct {
fieldA: usize,
fieldA: usize align(2 * @alignOf(usize)),
fieldB: void,
fieldC: *Self,
fieldD: u32 = 4,