authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2022-08-08 18:39:14+02:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2022-08-10 19:54:45+02:00
log0d32b73078aa4579187f7d5c67343a6036eed277
tree061cf1edf45d22198554159de00a7426748dad97
parentbb1c3e8b7e2be201221e14719d2d39e6298cc66c
signaturelock-open Commit is signed but in an unrecognized format.

stage2: Implement explicit backing integers for packed structs

Now the backing integer of a packed struct type may be explicitly specified with e.g. `packed struct(u32) { ... }`.

20 files changed, 493 insertions(+), 73 deletions(-)

lib/std/builtin.zig+2
......@@ -294,6 +294,8 @@ pub const Type = union(enum) {
294294 /// therefore must be kept in sync with the compiler implementation.
295295 pub const Struct = struct {
296296 layout: ContainerLayout,
297 /// Only valid if layout is .Packed
298 backing_integer: ?type = null,
297299 fields: []const StructField,
298300 decls: []const Declaration,
299301 is_tuple: bool,
lib/std/zig/Ast.zig+1-1
......@@ -2967,7 +2967,7 @@ pub const Node = struct {
29672967 /// Same as ContainerDeclTwo except there is known to be a trailing comma
29682968 /// or semicolon before the rbrace.
29692969 container_decl_two_trailing,
2970 /// `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`.
2970 /// `struct(lhs)` / `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`.
29712971 container_decl_arg,
29722972 /// Same as container_decl_arg but there is known to be a trailing
29732973 /// comma or semicolon before the rbrace.
lib/std/zig/parse.zig+6-4
......@@ -3356,16 +3356,18 @@ const Parser = struct {
33563356 }
33573357
33583358 /// Caller must have already verified the first token.
3359 /// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE
3360 ///
33593361 /// ContainerDeclType
3360 /// <- KEYWORD_struct
3362 /// <- KEYWORD_struct (LPAREN Expr RPAREN)?
3363 /// / KEYWORD_opaque
33613364 /// / KEYWORD_enum (LPAREN Expr RPAREN)?
33623365 /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
3363 /// / KEYWORD_opaque
33643366 fn parseContainerDeclAuto(p: *Parser) !Node.Index {
33653367 const main_token = p.nextToken();
33663368 const arg_expr = switch (p.token_tags[main_token]) {
3367 .keyword_struct, .keyword_opaque => null_node,
3368 .keyword_enum => blk: {
3369 .keyword_opaque => null_node,
3370 .keyword_struct, .keyword_enum => blk: {
33693371 if (p.eatToken(.l_paren)) |_| {
33703372 const expr = try p.expectExpr();
33713373 _ = try p.expectToken(.r_paren);
lib/std/zig/parser_test.zig+7
......@@ -3064,6 +3064,13 @@ test "zig fmt: struct declaration" {
30643064 \\ c: u8,
30653065 \\};
30663066 \\
3067 \\const Ps = packed struct(u32) {
3068 \\ a: u1,
3069 \\ b: u2,
3070 \\
3071 \\ c: u29,
3072 \\};
3073 \\
30673074 \\const Es = extern struct {
30683075 \\ a: u8,
30693076 \\ b: u8,
src/AstGen.zig+50-6
......@@ -152,6 +152,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
152152 0,
153153 tree.containerDeclRoot(),
154154 .Auto,
155 0,
155156 )) |struct_decl_ref| {
156157 assert(refToIndex(struct_decl_ref).? == 0);
157158 } else |err| switch (err) {
......@@ -4223,15 +4224,18 @@ fn structDeclInner(
42234224 node: Ast.Node.Index,
42244225 container_decl: Ast.full.ContainerDecl,
42254226 layout: std.builtin.Type.ContainerLayout,
4227 backing_int_node: Ast.Node.Index,
42264228) InnerError!Zir.Inst.Ref {
42274229 const decl_inst = try gz.reserveInstructionIndex();
42284230
4229 if (container_decl.ast.members.len == 0) {
4231 if (container_decl.ast.members.len == 0 and backing_int_node == 0) {
42304232 try gz.setStruct(decl_inst, .{
42314233 .src_node = node,
42324234 .layout = layout,
42334235 .fields_len = 0,
42344236 .decls_len = 0,
4237 .backing_int_ref = .none,
4238 .backing_int_body_len = 0,
42354239 .known_non_opv = false,
42364240 .known_comptime_only = false,
42374241 });
......@@ -4266,6 +4270,35 @@ fn structDeclInner(
42664270 };
42674271 defer block_scope.unstack();
42684272
4273 const scratch_top = astgen.scratch.items.len;
4274 defer astgen.scratch.items.len = scratch_top;
4275
4276 var backing_int_body_len: usize = 0;
4277 const backing_int_ref: Zir.Inst.Ref = blk: {
4278 if (backing_int_node != 0) {
4279 if (layout != .Packed) {
4280 return astgen.failNode(backing_int_node, "non-packed struct does not support backing integer type", .{});
4281 } else {
4282 const backing_int_ref = try typeExpr(&block_scope, &namespace.base, backing_int_node);
4283 if (!block_scope.isEmpty()) {
4284 if (!block_scope.endsWithNoReturn()) {
4285 _ = try block_scope.addBreak(.break_inline, decl_inst, backing_int_ref);
4286 }
4287
4288 const body = block_scope.instructionsSlice();
4289 const old_scratch_len = astgen.scratch.items.len;
4290 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
4291 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
4292 backing_int_body_len = astgen.scratch.items.len - old_scratch_len;
4293 block_scope.instructions.items.len = block_scope.instructions_top;
4294 }
4295 break :blk backing_int_ref;
4296 }
4297 } else {
4298 break :blk .none;
4299 }
4300 };
4301
42694302 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);
42704303 const field_count = @intCast(u32, container_decl.ast.members.len - decl_count);
42714304
......@@ -4378,6 +4411,8 @@ fn structDeclInner(
43784411 .layout = layout,
43794412 .fields_len = field_count,
43804413 .decls_len = decl_count,
4414 .backing_int_ref = backing_int_ref,
4415 .backing_int_body_len = @intCast(u32, backing_int_body_len),
43814416 .known_non_opv = known_non_opv,
43824417 .known_comptime_only = known_comptime_only,
43834418 });
......@@ -4386,7 +4421,9 @@ fn structDeclInner(
43864421 const decls_slice = wip_members.declsSlice();
43874422 const fields_slice = wip_members.fieldsSlice();
43884423 const bodies_slice = astgen.scratch.items[bodies_start..];
4389 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + fields_slice.len + bodies_slice.len);
4424 try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len +
4425 decls_slice.len + fields_slice.len + bodies_slice.len);
4426 astgen.extra.appendSliceAssumeCapacity(astgen.scratch.items[scratch_top..][0..backing_int_body_len]);
43904427 astgen.extra.appendSliceAssumeCapacity(decls_slice);
43914428 astgen.extra.appendSliceAssumeCapacity(fields_slice);
43924429 astgen.extra.appendSliceAssumeCapacity(bodies_slice);
......@@ -4582,9 +4619,7 @@ fn containerDecl(
45824619 else => unreachable,
45834620 } else std.builtin.Type.ContainerLayout.Auto;
45844621
4585 assert(container_decl.ast.arg == 0);
4586
4587 const result = try structDeclInner(gz, scope, node, container_decl, layout);
4622 const result = try structDeclInner(gz, scope, node, container_decl, layout, container_decl.ast.arg);
45884623 return rvalue(gz, rl, result, node);
45894624 },
45904625 .keyword_union => {
......@@ -11254,6 +11289,8 @@ const GenZir = struct {
1125411289 src_node: Ast.Node.Index,
1125511290 fields_len: u32,
1125611291 decls_len: u32,
11292 backing_int_ref: Zir.Inst.Ref,
11293 backing_int_body_len: u32,
1125711294 layout: std.builtin.Type.ContainerLayout,
1125811295 known_non_opv: bool,
1125911296 known_comptime_only: bool,
......@@ -11261,7 +11298,7 @@ const GenZir = struct {
1126111298 const astgen = gz.astgen;
1126211299 const gpa = astgen.gpa;
1126311300
11264 try astgen.extra.ensureUnusedCapacity(gpa, 4);
11301 try astgen.extra.ensureUnusedCapacity(gpa, 6);
1126511302 const payload_index = @intCast(u32, astgen.extra.items.len);
1126611303
1126711304 if (args.src_node != 0) {
......@@ -11274,6 +11311,12 @@ const GenZir = struct {
1127411311 if (args.decls_len != 0) {
1127511312 astgen.extra.appendAssumeCapacity(args.decls_len);
1127611313 }
11314 if (args.backing_int_ref != .none) {
11315 astgen.extra.appendAssumeCapacity(args.backing_int_body_len);
11316 if (args.backing_int_body_len == 0) {
11317 astgen.extra.appendAssumeCapacity(@enumToInt(args.backing_int_ref));
11318 }
11319 }
1127711320 astgen.instructions.set(inst, .{
1127811321 .tag = .extended,
1127911322 .data = .{ .extended = .{
......@@ -11282,6 +11325,7 @@ const GenZir = struct {
1128211325 .has_src_node = args.src_node != 0,
1128311326 .has_fields_len = args.fields_len != 0,
1128411327 .has_decls_len = args.decls_len != 0,
11328 .has_backing_int = args.backing_int_ref != .none,
1128511329 .known_non_opv = args.known_non_opv,
1128611330 .known_comptime_only = args.known_comptime_only,
1128711331 .name_strategy = gz.anon_name_strategy,
src/Autodoc.zig+11
......@@ -2536,6 +2536,17 @@ fn walkInstruction(
25362536 break :blk decls_len;
25372537 } else 0;
25382538
2539 // TODO: Expose explicit backing integer types in some way.
2540 if (small.has_backing_int) {
2541 const backing_int_body_len = file.zir.extra[extra_index];
2542 extra_index += 1; // backing_int_body_len
2543 if (backing_int_body_len == 0) {
2544 extra_index += 1; // backing_int_ref
2545 } else {
2546 extra_index += backing_int_body_len; // backing_int_body_inst
2547 }
2548 }
2549
25392550 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
25402551 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
25412552
src/Module.zig+7-14
......@@ -895,6 +895,11 @@ pub const Struct = struct {
895895 zir_index: Zir.Inst.Index,
896896
897897 layout: std.builtin.Type.ContainerLayout,
898 /// If the layout is not packed, this is the noreturn type.
899 /// If the layout is packed, this is the backing integer type of the packed struct.
900 /// Whether zig chooses this type or the user specifies it, it is stored here.
901 /// This will be set to the noreturn type until status is `have_layout`.
902 backing_int_ty: Type = Type.initTag(.noreturn),
898903 status: enum {
899904 none,
900905 field_types_wip,
......@@ -1025,7 +1030,7 @@ pub const Struct = struct {
10251030
10261031 pub fn packedFieldBitOffset(s: Struct, target: Target, index: usize) u16 {
10271032 assert(s.layout == .Packed);
1028 assert(s.haveFieldTypes());
1033 assert(s.haveLayout());
10291034 var bit_sum: u64 = 0;
10301035 for (s.fields.values()) |field, i| {
10311036 if (i == index) {
......@@ -1033,19 +1038,7 @@ pub const Struct = struct {
10331038 }
10341039 bit_sum += field.ty.bitSize(target);
10351040 }
1036 return @intCast(u16, bit_sum);
1037 }
1038
1039 pub fn packedIntegerBits(s: Struct, target: Target) u16 {
1040 return s.packedFieldBitOffset(target, s.fields.count());
1041 }
1042
1043 pub fn packedIntegerType(s: Struct, target: Target, buf: *Type.Payload.Bits) Type {
1044 buf.* = .{
1045 .base = .{ .tag = .int_unsigned },
1046 .data = s.packedIntegerBits(target),
1047 };
1048 return Type.initPayload(&buf.base);
1041 unreachable; // index out of bounds
10491042 }
10501043};
10511044
src/Sema.zig+199-8
......@@ -2239,6 +2239,16 @@ pub fn analyzeStructDecl(
22392239 break :blk decls_len;
22402240 } else 0;
22412241
2242 if (small.has_backing_int) {
2243 const backing_int_body_len = sema.code.extra[extra_index];
2244 extra_index += 1; // backing_int_body_len
2245 if (backing_int_body_len == 0) {
2246 extra_index += 1; // backing_int_ref
2247 } else {
2248 extra_index += backing_int_body_len; // backing_int_body_inst
2249 }
2250 }
2251
22422252 _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl);
22432253}
22442254
......@@ -14285,13 +14295,27 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1428514295
1428614296 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespace());
1428714297
14288 const field_values = try sema.arena.create([4]Value);
14298 const backing_integer_val = blk: {
14299 if (layout == .Packed) {
14300 const struct_obj = struct_ty.castTag(.@"struct").?.data;
14301 assert(struct_obj.haveLayout());
14302 assert(struct_obj.backing_int_ty.isInt());
14303 const backing_int_ty_val = try Value.Tag.ty.create(sema.arena, struct_obj.backing_int_ty);
14304 break :blk try Value.Tag.opt_payload.create(sema.arena, backing_int_ty_val);
14305 } else {
14306 break :blk Value.initTag(.null_value);
14307 }
14308 };
14309
14310 const field_values = try sema.arena.create([5]Value);
1428914311 field_values.* = .{
1429014312 // layout: ContainerLayout,
1429114313 try Value.Tag.enum_field_index.create(
1429214314 sema.arena,
1429314315 @enumToInt(layout),
1429414316 ),
14317 // backing_integer: ?type,
14318 backing_integer_val,
1429514319 // fields: []const StructField,
1429614320 fields_val,
1429714321 // decls: []const Declaration,
......@@ -16308,7 +16332,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
1630816332 if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) {
1630916333 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
1631016334 }
16311 const abi_align = @intCast(u29, alignment_val.toUnsignedInt(target));
16335 const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?);
1631216336
1631316337 var buffer: Value.ToTypeBuffer = undefined;
1631416338 const unresolved_elem_ty = child_val.toType(&buffer);
......@@ -16473,22 +16497,31 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
1647316497 const struct_val = union_val.val.castTag(.aggregate).?.data;
1647416498 // layout: containerlayout,
1647516499 const layout_val = struct_val[0];
16500 // backing_int: ?type,
16501 const backing_int_val = struct_val[1];
1647616502 // fields: []const enumfield,
16477 const fields_val = struct_val[1];
16503 const fields_val = struct_val[2];
1647816504 // decls: []const declaration,
16479 const decls_val = struct_val[2];
16505 const decls_val = struct_val[3];
1648016506 // is_tuple: bool,
16481 const is_tuple_val = struct_val[3];
16507 const is_tuple_val = struct_val[4];
16508 assert(struct_val.len == 5);
16509
16510 const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout);
1648216511
1648316512 // Decls
1648416513 if (decls_val.sliceLen(mod) > 0) {
1648516514 return sema.fail(block, src, "reified structs must have no decls", .{});
1648616515 }
1648716516
16517 if (layout != .Packed and !backing_int_val.isNull()) {
16518 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
16519 }
16520
1648816521 return if (is_tuple_val.toBool())
1648916522 try sema.reifyTuple(block, src, fields_val)
1649016523 else
16491 try sema.reifyStruct(block, inst, src, layout_val, fields_val, name_strategy);
16524 try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy);
1649216525 },
1649316526 .Enum => {
1649416527 const struct_val = union_val.val.castTag(.aggregate).?.data;
......@@ -16981,7 +17014,8 @@ fn reifyStruct(
1698117014 block: *Block,
1698217015 inst: Zir.Inst.Index,
1698317016 src: LazySrcLoc,
16984 layout_val: Value,
17017 layout: std.builtin.Type.ContainerLayout,
17018 backing_int_val: Value,
1698517019 fields_val: Value,
1698617020 name_strategy: Zir.Inst.NameStrategy,
1698717021) CompileError!Air.Inst.Ref {
......@@ -17004,7 +17038,7 @@ fn reifyStruct(
1700417038 .owner_decl = new_decl_index,
1700517039 .fields = .{},
1700617040 .zir_index = inst,
17007 .layout = layout_val.toEnum(std.builtin.Type.ContainerLayout),
17041 .layout = layout,
1700817042 .status = .have_field_types,
1700917043 .known_non_opv = false,
1701017044 .namespace = .{
......@@ -17070,6 +17104,41 @@ fn reifyStruct(
1707017104 };
1707117105 }
1707217106
17107 if (layout == .Packed) {
17108 struct_obj.status = .layout_wip;
17109
17110 for (struct_obj.fields.values()) |field, index| {
17111 sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) {
17112 error.AnalysisFail => {
17113 const msg = sema.err orelse return err;
17114 try sema.addFieldErrNote(block, struct_ty, index, msg, "while checking this field", .{});
17115 return err;
17116 },
17117 else => return err,
17118 };
17119 }
17120
17121 var fields_bit_sum: u64 = 0;
17122 for (struct_obj.fields.values()) |field| {
17123 fields_bit_sum += field.ty.bitSize(target);
17124 }
17125
17126 if (backing_int_val.optionalValue()) |payload| {
17127 var buf: Value.ToTypeBuffer = undefined;
17128 const backing_int_ty = payload.toType(&buf);
17129 try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
17130 struct_obj.backing_int_ty = try backing_int_ty.copy(new_decl_arena_allocator);
17131 } else {
17132 var buf: Type.Payload.Bits = .{
17133 .base = .{ .tag = .int_unsigned },
17134 .data = @intCast(u16, fields_bit_sum),
17135 };
17136 struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(new_decl_arena_allocator);
17137 }
17138
17139 struct_obj.status = .have_layout;
17140 }
17141
1707317142 try new_decl.finalizeNewArena(&new_decl_arena);
1707417143 return sema.analyzeDeclVal(block, src, new_decl_index);
1707517144}
......@@ -27154,6 +27223,11 @@ fn resolveStructLayout(
2715427223 else => return err,
2715527224 };
2715627225 }
27226
27227 if (struct_obj.layout == .Packed) {
27228 try semaBackingIntType(sema.mod, struct_obj);
27229 }
27230
2715727231 struct_obj.status = .have_layout;
2715827232
2715927233 // In case of querying the ABI alignment of this struct, we will ask
......@@ -27173,6 +27247,109 @@ fn resolveStructLayout(
2717327247 // otherwise it's a tuple; no need to resolve anything
2717427248}
2717527249
27250fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
27251 const gpa = mod.gpa;
27252 const target = mod.getTarget();
27253
27254 var fields_bit_sum: u64 = 0;
27255 for (struct_obj.fields.values()) |field| {
27256 fields_bit_sum += field.ty.bitSize(target);
27257 }
27258
27259 const decl_index = struct_obj.owner_decl;
27260 const decl = mod.declPtr(decl_index);
27261 var decl_arena = decl.value_arena.?.promote(gpa);
27262 defer decl.value_arena.?.* = decl_arena.state;
27263 const decl_arena_allocator = decl_arena.allocator();
27264
27265 const zir = struct_obj.namespace.file_scope.zir;
27266 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
27267 assert(extended.opcode == .struct_decl);
27268 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
27269
27270 if (small.has_backing_int) {
27271 var extra_index: usize = extended.operand;
27272 extra_index += @boolToInt(small.has_src_node);
27273 extra_index += @boolToInt(small.has_fields_len);
27274 extra_index += @boolToInt(small.has_decls_len);
27275
27276 const backing_int_body_len = zir.extra[extra_index];
27277 extra_index += 1;
27278
27279 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
27280 defer analysis_arena.deinit();
27281
27282 var sema: Sema = .{
27283 .mod = mod,
27284 .gpa = gpa,
27285 .arena = analysis_arena.allocator(),
27286 .perm_arena = decl_arena_allocator,
27287 .code = zir,
27288 .owner_decl = decl,
27289 .owner_decl_index = decl_index,
27290 .func = null,
27291 .fn_ret_ty = Type.void,
27292 .owner_func = null,
27293 };
27294 defer sema.deinit();
27295
27296 var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope);
27297 defer wip_captures.deinit();
27298
27299 var block: Block = .{
27300 .parent = null,
27301 .sema = &sema,
27302 .src_decl = decl_index,
27303 .namespace = &struct_obj.namespace,
27304 .wip_capture_scope = wip_captures.scope,
27305 .instructions = .{},
27306 .inlining = null,
27307 .is_comptime = true,
27308 };
27309 defer {
27310 assert(block.instructions.items.len == 0);
27311 block.params.deinit(gpa);
27312 }
27313
27314 const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 };
27315 const backing_int_ty = blk: {
27316 if (backing_int_body_len == 0) {
27317 const backing_int_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
27318 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);
27319 } else {
27320 const body = zir.extra[extra_index..][0..backing_int_body_len];
27321 const ty_ref = try sema.resolveBody(&block, body, struct_obj.zir_index);
27322 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);
27323 }
27324 };
27325
27326 try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
27327 struct_obj.backing_int_ty = try backing_int_ty.copy(decl_arena_allocator);
27328 } else {
27329 var buf: Type.Payload.Bits = .{
27330 .base = .{ .tag = .int_unsigned },
27331 .data = @intCast(u16, fields_bit_sum),
27332 };
27333 struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(decl_arena_allocator);
27334 }
27335}
27336
27337fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
27338 const target = sema.mod.getTarget();
27339
27340 if (!backing_int_ty.isInt()) {
27341 return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(sema.mod)});
27342 }
27343 if (backing_int_ty.bitSize(target) != fields_bit_sum) {
27344 return sema.fail(
27345 block,
27346 src,
27347 "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}",
27348 .{ backing_int_ty.fmt(sema.mod), backing_int_ty.bitSize(target), fields_bit_sum },
27349 );
27350 }
27351}
27352
2717627353fn resolveUnionLayout(
2717727354 sema: *Sema,
2717827355 block: *Block,
......@@ -27495,12 +27672,26 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2749527672 break :decls_len decls_len;
2749627673 } else 0;
2749727674
27675 // The backing integer cannot be handled until `resolveStructLayout()`.
27676 if (small.has_backing_int) {
27677 const backing_int_body_len = zir.extra[extra_index];
27678 extra_index += 1; // backing_int_body_len
27679 if (backing_int_body_len == 0) {
27680 extra_index += 1; // backing_int_ref
27681 } else {
27682 extra_index += backing_int_body_len; // backing_int_body_inst
27683 }
27684 }
27685
2749827686 // Skip over decls.
2749927687 var decls_it = zir.declIteratorInner(extra_index, decls_len);
2750027688 while (decls_it.next()) |_| {}
2750127689 extra_index = decls_it.extra_index;
2750227690
2750327691 if (fields_len == 0) {
27692 if (struct_obj.layout == .Packed) {
27693 try semaBackingIntType(mod, struct_obj);
27694 }
2750427695 struct_obj.status = .have_layout;
2750527696 return;
2750627697 }
src/Zir.zig+10-6
......@@ -3085,13 +3085,16 @@ pub const Inst = struct {
30853085 /// 0. src_node: i32, // if has_src_node
30863086 /// 1. fields_len: u32, // if has_fields_len
30873087 /// 2. decls_len: u32, // if has_decls_len
3088 /// 3. decl_bits: u32 // for every 8 decls
3088 /// 3. backing_int_body_len: u32, // if has_backing_int
3089 /// 4. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
3090 /// 5. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
3091 /// 6. decl_bits: u32 // for every 8 decls
30893092 /// - sets of 4 bits:
30903093 /// 0b000X: whether corresponding decl is pub
30913094 /// 0b00X0: whether corresponding decl is exported
30923095 /// 0b0X00: whether corresponding decl has an align expression
30933096 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3094 /// 4. decl: { // for every decls_len
3097 /// 7. decl: { // for every decls_len
30953098 /// src_hash: [4]u32, // hash of source bytes
30963099 /// line: u32, // line number of decl, relative to parent
30973100 /// name: u32, // null terminated string index
......@@ -3109,13 +3112,13 @@ pub const Inst = struct {
31093112 /// address_space: Ref,
31103113 /// }
31113114 /// }
3112 /// 5. flags: u32 // for every 8 fields
3115 /// 8. flags: u32 // for every 8 fields
31133116 /// - sets of 4 bits:
31143117 /// 0b000X: whether corresponding field has an align expression
31153118 /// 0b00X0: whether corresponding field has a default expression
31163119 /// 0b0X00: whether corresponding field is comptime
31173120 /// 0bX000: whether corresponding field has a type expression
3118 /// 6. fields: { // for every fields_len
3121 /// 9. fields: { // for every fields_len
31193122 /// field_name: u32,
31203123 /// doc_comment: u32, // 0 if no doc comment
31213124 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
......@@ -3123,7 +3126,7 @@ pub const Inst = struct {
31233126 /// align_body_len: u32, // if corresponding bit is set
31243127 /// init_body_len: u32, // if corresponding bit is set
31253128 /// }
3126 /// 7. bodies: { // for every fields_len
3129 /// 10. bodies: { // for every fields_len
31273130 /// field_type_body_inst: Inst, // for each field_type_body_len
31283131 /// align_body_inst: Inst, // for each align_body_len
31293132 /// init_body_inst: Inst, // for each init_body_len
......@@ -3133,11 +3136,12 @@ pub const Inst = struct {
31333136 has_src_node: bool,
31343137 has_fields_len: bool,
31353138 has_decls_len: bool,
3139 has_backing_int: bool,
31363140 known_non_opv: bool,
31373141 known_comptime_only: bool,
31383142 name_strategy: NameStrategy,
31393143 layout: std.builtin.Type.ContainerLayout,
3140 _: u7 = undefined,
3144 _: u6 = undefined,
31413145 };
31423146 };
31433147
src/codegen/llvm.zig+6-9
......@@ -1683,8 +1683,7 @@ pub const Object = struct {
16831683 if (ty.castTag(.@"struct")) |payload| {
16841684 const struct_obj = payload.data;
16851685 if (struct_obj.layout == .Packed) {
1686 var buf: Type.Payload.Bits = undefined;
1687 const info = struct_obj.packedIntegerType(target, &buf).intInfo(target);
1686 const info = struct_obj.backing_int_ty.intInfo(target);
16881687 const dwarf_encoding: c_uint = switch (info.signedness) {
16891688 .signed => DW.ATE.signed,
16901689 .unsigned => DW.ATE.unsigned,
......@@ -2679,9 +2678,7 @@ pub const DeclGen = struct {
26792678 const struct_obj = t.castTag(.@"struct").?.data;
26802679
26812680 if (struct_obj.layout == .Packed) {
2682 var buf: Type.Payload.Bits = undefined;
2683 const int_ty = struct_obj.packedIntegerType(target, &buf);
2684 const int_llvm_ty = try dg.lowerType(int_ty);
2681 const int_llvm_ty = try dg.lowerType(struct_obj.backing_int_ty);
26852682 gop.value_ptr.* = int_llvm_ty;
26862683 return int_llvm_ty;
26872684 }
......@@ -3330,8 +3327,8 @@ pub const DeclGen = struct {
33303327 const struct_obj = tv.ty.castTag(.@"struct").?.data;
33313328
33323329 if (struct_obj.layout == .Packed) {
3333 const big_bits = struct_obj.packedIntegerBits(target);
3334 const int_llvm_ty = dg.context.intType(big_bits);
3330 const big_bits = struct_obj.backing_int_ty.bitSize(target);
3331 const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits));
33353332 const fields = struct_obj.fields.values();
33363333 comptime assert(Type.packed_struct_layout_version == 2);
33373334 var running_int: *const llvm.Value = int_llvm_ty.constNull();
......@@ -8243,8 +8240,8 @@ pub const FuncGen = struct {
82438240 .Struct => {
82448241 if (result_ty.containerLayout() == .Packed) {
82458242 const struct_obj = result_ty.castTag(.@"struct").?.data;
8246 const big_bits = struct_obj.packedIntegerBits(target);
8247 const int_llvm_ty = self.dg.context.intType(big_bits);
8243 const big_bits = struct_obj.backing_int_ty.bitSize(target);
8244 const int_llvm_ty = self.dg.context.intType(@intCast(c_uint, big_bits));
82488245 const fields = struct_obj.fields.values();
82498246 comptime assert(Type.packed_struct_layout_version == 2);
82508247 var running_int: *const llvm.Value = int_llvm_ty.constNull();
src/print_zir.zig+22-3
......@@ -1245,9 +1245,28 @@ const Writer = struct {
12451245
12461246 try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv);
12471247 try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);
1248 try stream.print("{s}, {s}, ", .{
1249 @tagName(small.name_strategy), @tagName(small.layout),
1250 });
1248
1249 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
1250
1251 if (small.layout == .Packed and small.has_backing_int) {
1252 const backing_int_body_len = self.code.extra[extra_index];
1253 extra_index += 1;
1254 try stream.writeAll("Packed(");
1255 if (backing_int_body_len == 0) {
1256 const backing_int_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1257 extra_index += 1;
1258 try self.writeInstRef(stream, backing_int_ref);
1259 } else {
1260 const body = self.code.extra[extra_index..][0..backing_int_body_len];
1261 extra_index += backing_int_body_len;
1262 self.indent += 2;
1263 try self.writeBracedDecl(stream, body);
1264 self.indent -= 2;
1265 }
1266 try stream.writeAll("), ");
1267 } else {
1268 try stream.print("{s}, ", .{@tagName(small.layout)});
1269 }
12511270
12521271 if (decls_len == 0) {
12531272 try stream.writeAll("{}, ");
src/stage1/all_types.hpp+1
......@@ -1116,6 +1116,7 @@ struct AstNodeContainerDecl {
11161116 ContainerLayout layout;
11171117
11181118 bool auto_enum, is_root; // union(enum)
1119 bool unsupported_explicit_backing_int;
11191120};
11201121
11211122struct AstNodeErrorSetField {
src/stage1/analyze.cpp+6
......@@ -3034,6 +3034,12 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
30343034
30353035 AstNode *decl_node = struct_type->data.structure.decl_node;
30363036
3037 if (decl_node->data.container_decl.unsupported_explicit_backing_int) {
3038 add_node_error(g, decl_node, buf_create_from_str(
3039 "the stage1 compiler does not support explicit backing integer types on packed structs"));
3040 return ErrorSemanticAnalyzeFail;
3041 }
3042
30373043 if (struct_type->data.structure.resolve_loop_flag_zero_bits) {
30383044 if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
30393045 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
src/stage1/ir.cpp+28-12
......@@ -18640,7 +18640,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
1864018640 result->special = ConstValSpecialStatic;
1864118641 result->type = ir_type_info_get_type(ira, "Struct", nullptr);
1864218642
18643 ZigValue **fields = alloc_const_vals_ptrs(g, 4);
18643 ZigValue **fields = alloc_const_vals_ptrs(g, 5);
1864418644 result->data.x_struct.fields = fields;
1864518645
1864618646 // layout: ContainerLayout
......@@ -18648,8 +18648,17 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
1864818648 fields[0]->special = ConstValSpecialStatic;
1864918649 fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr);
1865018650 bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.structure.layout);
18651
18652 // backing_integer: ?type
18653 ensure_field_index(result->type, "backing_integer", 1);
18654 fields[1]->special = ConstValSpecialStatic;
18655 fields[1]->type = get_optional_type(g, g->builtin_types.entry_type);
18656 // This is always null in stage1, as stage1 does not support explicit backing integers
18657 // for packed structs.
18658 fields[1]->data.x_optional = nullptr;
18659
1865118660 // fields: []Type.StructField
18652 ensure_field_index(result->type, "fields", 1);
18661 ensure_field_index(result->type, "fields", 2);
1865318662
1865418663 ZigType *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField", nullptr);
1865518664 if ((err = type_resolve(g, type_info_struct_field_type, ResolveStatusSizeKnown))) {
......@@ -18663,7 +18672,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
1866318672 struct_field_array->data.x_array.special = ConstArraySpecialNone;
1866418673 struct_field_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(struct_field_count);
1866518674
18666 init_const_slice(g, fields[1], struct_field_array, 0, struct_field_count, false, nullptr);
18675 init_const_slice(g, fields[2], struct_field_array, 0, struct_field_count, false, nullptr);
1866718676
1866818677 for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) {
1866918678 TypeStructField *struct_field = type_entry->data.structure.fields[struct_field_index];
......@@ -18710,18 +18719,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
1871018719 struct_field_val->parent.data.p_array.elem_index = struct_field_index;
1871118720 }
1871218721 // decls: []Type.Declaration
18713 ensure_field_index(result->type, "decls", 2);
18714 if ((err = ir_make_type_info_decls(ira, source_node, fields[2],
18722 ensure_field_index(result->type, "decls", 3);
18723 if ((err = ir_make_type_info_decls(ira, source_node, fields[3],
1871518724 type_entry->data.structure.decls_scope, false)))
1871618725 {
1871718726 return err;
1871818727 }
1871918728
1872018729 // is_tuple: bool
18721 ensure_field_index(result->type, "is_tuple", 3);
18722 fields[3]->special = ConstValSpecialStatic;
18723 fields[3]->type = g->builtin_types.entry_bool;
18724 fields[3]->data.x_bool = is_tuple(type_entry);
18730 ensure_field_index(result->type, "is_tuple", 4);
18731 fields[4]->special = ConstValSpecialStatic;
18732 fields[4]->type = g->builtin_types.entry_bool;
18733 fields[4]->data.x_bool = is_tuple(type_entry);
1872518734
1872618735 break;
1872718736 }
......@@ -19313,7 +19322,14 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
1931319322 assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr));
1931419323 ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag);
1931519324
19316 ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 1);
19325 ZigType *tag_type = get_const_field_meta_type_optional(ira, source_node, payload, "backing_integer", 1);
19326 if (tag_type != nullptr) {
19327 ir_add_error_node(ira, source_node, buf_create_from_str(
19328 "the stage1 compiler does not support explicit backing integer types on packed structs"));
19329 return ira->codegen->invalid_inst_gen->value->type;
19330 }
19331
19332 ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 2);
1931719333 if (fields_value == nullptr)
1931819334 return ira->codegen->invalid_inst_gen->value->type;
1931919335 assert(fields_value->special == ConstValSpecialStatic);
......@@ -19322,7 +19338,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
1932219338 ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index];
1932319339 size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint);
1932419340
19325 ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 2);
19341 ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 3);
1932619342 if (decls_value == nullptr)
1932719343 return ira->codegen->invalid_inst_gen->value->type;
1932819344 assert(decls_value->special == ConstValSpecialStatic);
......@@ -19335,7 +19351,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
1933519351 }
1933619352
1933719353 bool is_tuple;
19338 if ((err = get_const_field_bool(ira, source_node, payload, "is_tuple", 3, &is_tuple)))
19354 if ((err = get_const_field_bool(ira, source_node, payload, "is_tuple", 4, &is_tuple)))
1933919355 return ira->codegen->invalid_inst_gen->value->type;
1934019356
1934119357 ZigType *entry = new_type_table_entry(ZigTypeIdStruct);
src/stage1/parser.cpp+10-1
......@@ -2902,16 +2902,25 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) {
29022902}
29032903
29042904// ContainerDeclType
2905// <- KEYWORD_struct
2905// <- KEYWORD_struct (LPAREN Expr RPAREN)?
29062906// / KEYWORD_enum (LPAREN Expr RPAREN)?
29072907// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
29082908// / KEYWORD_opaque
29092909static AstNode *ast_parse_container_decl_type(ParseContext *pc) {
29102910 TokenIndex first = eat_token_if(pc, TokenIdKeywordStruct);
29112911 if (first != 0) {
2912 bool explicit_backing_int = false;
2913 if (eat_token_if(pc, TokenIdLParen) != 0) {
2914 explicit_backing_int = true;
2915 ast_expect(pc, ast_parse_expr);
2916 expect_token(pc, TokenIdRParen);
2917 }
29122918 AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first);
29132919 res->data.container_decl.init_arg_expr = nullptr;
29142920 res->data.container_decl.kind = ContainerKindStruct;
2921 // We want this to be an error in semantic analysis not parsing to make sharing
2922 // the test suite between stage1 and self hosted easier.
2923 res->data.container_decl.unsupported_explicit_backing_int = explicit_backing_int;
29152924 return res;
29162925 }
29172926
src/type.zig+15-8
......@@ -3000,9 +3000,17 @@ pub const Type = extern union {
30003000 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },
30013001 };
30023002 if (struct_obj.layout == .Packed) {
3003 var buf: Type.Payload.Bits = undefined;
3004 const int_ty = struct_obj.packedIntegerType(target, &buf);
3005 return AbiAlignmentAdvanced{ .scalar = int_ty.abiAlignment(target) };
3003 switch (strat) {
3004 .sema_kit => |sk| try sk.sema.resolveTypeLayout(sk.block, sk.src, ty),
3005 .lazy => |arena| {
3006 if (!struct_obj.haveLayout()) {
3007 return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) };
3008 }
3009 },
3010 .eager => {},
3011 }
3012 assert(struct_obj.haveLayout());
3013 return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(target) };
30063014 }
30073015
30083016 const fields = ty.structFields();
......@@ -3192,17 +3200,16 @@ pub const Type = extern union {
31923200 .Packed => {
31933201 const struct_obj = ty.castTag(.@"struct").?.data;
31943202 switch (strat) {
3195 .sema_kit => |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty),
3203 .sema_kit => |sk| try sk.sema.resolveTypeLayout(sk.block, sk.src, ty),
31963204 .lazy => |arena| {
3197 if (!struct_obj.haveFieldTypes()) {
3205 if (!struct_obj.haveLayout()) {
31983206 return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) };
31993207 }
32003208 },
32013209 .eager => {},
32023210 }
3203 var buf: Type.Payload.Bits = undefined;
3204 const int_ty = struct_obj.packedIntegerType(target, &buf);
3205 return AbiSizeAdvanced{ .scalar = int_ty.abiSize(target) };
3211 assert(struct_obj.haveLayout());
3212 return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(target) };
32063213 },
32073214 else => {
32083215 switch (strat) {
test/behavior.zig+1
......@@ -165,6 +165,7 @@ test {
165165
166166 if (builtin.zig_backend != .stage1) {
167167 _ = @import("behavior/decltest.zig");
168 _ = @import("behavior/packed_struct_explicit_backing_int.zig");
168169 }
169170
170171 if (builtin.os.tag != .wasi) {
test/behavior/packed_struct_explicit_backing_int.zig created+53
......@@ -0,0 +1,53 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const expectEqual = std.testing.expectEqual;
5const native_endian = builtin.cpu.arch.endian();
6
7test "packed struct explicit backing integer" {
8 assert(builtin.zig_backend != .stage1);
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14
15 const S1 = packed struct { a: u8, b: u8, c: u8 };
16
17 const S2 = packed struct(i24) { d: u8, e: u8, f: u8 };
18
19 const S3 = packed struct { x: S1, y: S2 };
20 const S3Padded = packed struct(u64) { s3: S3, pad: u16 };
21
22 try expectEqual(48, @bitSizeOf(S3));
23 try expectEqual(@sizeOf(u48), @sizeOf(S3));
24
25 try expectEqual(3, @offsetOf(S3, "y"));
26 try expectEqual(24, @bitOffsetOf(S3, "y"));
27
28 if (native_endian == .Little) {
29 const s3 = @bitCast(S3Padded, @as(u64, 0xe952d5c71ff4)).s3;
30 try expectEqual(@as(u8, 0xf4), s3.x.a);
31 try expectEqual(@as(u8, 0x1f), s3.x.b);
32 try expectEqual(@as(u8, 0xc7), s3.x.c);
33 try expectEqual(@as(u8, 0xd5), s3.y.d);
34 try expectEqual(@as(u8, 0x52), s3.y.e);
35 try expectEqual(@as(u8, 0xe9), s3.y.f);
36 }
37
38 const S4 = packed struct { a: i32, b: i8 };
39 const S5 = packed struct(u80) { a: i32, b: i8, c: S4 };
40 const S6 = packed struct(i80) { a: i32, b: S4, c: i8 };
41
42 const expectedBitSize = 80;
43 const expectedByteSize = @sizeOf(u80);
44 try expectEqual(expectedBitSize, @bitSizeOf(S5));
45 try expectEqual(expectedByteSize, @sizeOf(S5));
46 try expectEqual(expectedBitSize, @bitSizeOf(S6));
47 try expectEqual(expectedByteSize, @sizeOf(S6));
48
49 try expectEqual(5, @offsetOf(S5, "c"));
50 try expectEqual(40, @bitOffsetOf(S5, "c"));
51 try expectEqual(9, @offsetOf(S6, "c"));
52 try expectEqual(72, @bitOffsetOf(S6, "c"));
53}
test/behavior/type_info.zig+3-1
......@@ -293,6 +293,7 @@ test "type info: struct info" {
293293fn testStruct() !void {
294294 const unpacked_struct_info = @typeInfo(TestStruct);
295295 try expect(unpacked_struct_info.Struct.is_tuple == false);
296 try expect(unpacked_struct_info.Struct.backing_integer == null);
296297 try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
297298 try expect(@ptrCast(*const u32, unpacked_struct_info.Struct.fields[0].default_value.?).* == 4);
298299 try expect(mem.eql(u8, "foobar", @ptrCast(*const *const [6:0]u8, unpacked_struct_info.Struct.fields[1].default_value.?).*));
......@@ -315,6 +316,7 @@ fn testPackedStruct() !void {
315316 try expect(struct_info == .Struct);
316317 try expect(struct_info.Struct.is_tuple == false);
317318 try expect(struct_info.Struct.layout == .Packed);
319 try expect(struct_info.Struct.backing_integer == u128);
318320 try expect(struct_info.Struct.fields.len == 4);
319321 try expect(struct_info.Struct.fields[0].alignment == 0);
320322 try expect(struct_info.Struct.fields[2].field_type == f32);
......@@ -326,7 +328,7 @@ fn testPackedStruct() !void {
326328}
327329
328330const TestPackedStruct = packed struct {
329 fieldA: usize,
331 fieldA: u64,
330332 fieldB: void,
331333 fieldC: f32,
332334 fieldD: u32 = 4,
test/cases/compile_errors/packed_struct_backing_int_wrong.zig created+55
......@@ -0,0 +1,55 @@
1export fn entry1() void {
2 _ = @sizeOf(packed struct(u32) {
3 x: u1,
4 y: u24,
5 z: u4,
6 });
7}
8export fn entry2() void {
9 _ = @sizeOf(packed struct(i31) {
10 x: u4,
11 y: u24,
12 z: u4,
13 });
14}
15
16export fn entry3() void {
17 _ = @sizeOf(packed struct(void) {
18 x: void,
19 });
20}
21
22export fn entry4() void {
23 _ = @sizeOf(packed struct(void) {});
24}
25
26export fn entry5() void {
27 _ = @sizeOf(packed struct(noreturn) {});
28}
29
30export fn entry6() void {
31 _ = @sizeOf(packed struct(f64) {
32 x: u32,
33 y: f32,
34 });
35}
36
37export fn entry7() void {
38 _ = @sizeOf(packed struct(*u32) {
39 x: u4,
40 y: u24,
41 z: u4,
42 });
43}
44
45// error
46// backend=llvm
47// target=native
48//
49// :2:31: error: backing integer type 'u32' has bit size 32 but the struct fields have a total bit size of 29
50// :9:31: error: backing integer type 'i31' has bit size 31 but the struct fields have a total bit size of 32
51// :17:31: error: expected backing integer type, found 'void'
52// :23:31: error: expected backing integer type, found 'void'
53// :27:31: error: expected backing integer type, found 'noreturn'
54// :31:31: error: expected backing integer type, found 'f64'
55// :38:31: error: expected backing integer type, found '*u32'