mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 05:48:31 +00:00
Merge pull request #6428 from tadeokondrak/alignment-typeinfo-struct-union
Add alignment field to TypeInfo.UnionField and TypeInfo.StructField
This commit is contained in:
commit
0228887b94
@ -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
|
||||
|
||||
@ -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),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -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(.{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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(){};
|
||||
\\}
|
||||
|
||||
@ -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{},
|
||||
},
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user