authorgravatar for 36753247+AdamGoertz@users.noreply.github.comAdamGoertz <36753247+AdamGoertz@users.noreply.github.com> 2023-07-29 12:45:01-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-29 12:45:01-04:00
log796927b900ad4b774c30d1cb545d606f23040d2f
tree7fd53185ae5dfadce29a8ab95f27d5bade0ae05c
parent8d1805f81c97a0b773772e86aa39f26c894b7985
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Allow zero-sized fields in extern structs (#16404)

This change allows the following types to appear in extern structs: * Zero-bit integers * void * zero-sized structs and packed structs * enums with zero-bit backing integers * arrays of any length with zero-size elements

8 files changed, 33 insertions(+), 12 deletions(-)

src/Sema.zig+6-6
......@@ -24590,7 +24590,7 @@ fn validateExternType(
2459024590 .ErrorSet,
2459124591 .Frame,
2459224592 => return false,
24593 .Void => return position == .union_field or position == .ret_ty,
24593 .Void => return position == .union_field or position == .ret_ty or position == .struct_field or position == .element,
2459424594 .NoReturn => return position == .ret_ty,
2459524595 .Opaque,
2459624596 .Bool,
......@@ -24599,7 +24599,7 @@ fn validateExternType(
2459924599 => return true,
2460024600 .Pointer => return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty)),
2460124601 .Int => switch (ty.intInfo(mod).bits) {
24602 8, 16, 32, 64, 128 => return true,
24602 0, 8, 16, 32, 64, 128 => return true,
2460324603 else => return false,
2460424604 },
2460524605 .Fn => {
......@@ -24620,11 +24620,11 @@ fn validateExternType(
2462024620 .Packed => {
2462124621 const bit_size = try ty.bitSizeAdvanced(mod, sema);
2462224622 switch (bit_size) {
24623 8, 16, 32, 64, 128 => return true,
24623 0, 8, 16, 32, 64, 128 => return true,
2462424624 else => return false,
2462524625 }
2462624626 },
24627 .Auto => return false,
24627 .Auto => return !(try sema.typeHasRuntimeBits(ty)),
2462824628 },
2462924629 .Array => {
2463024630 if (position == .ret_ty or position == .param_ty) return false;
......@@ -24673,9 +24673,9 @@ fn explainWhyTypeIsNotExtern(
2467324673 .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
2467424674 .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
2467524675 .Int => if (!std.math.isPowerOfTwo(ty.intInfo(mod).bits)) {
24676 try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{});
24676 try mod.errNoteNonLazy(src_loc, msg, "only integers with 0 or power of two bits are extern compatible", .{});
2467724677 } else {
24678 try mod.errNoteNonLazy(src_loc, msg, "only integers with 8, 16, 32, 64 and 128 bits are extern compatible", .{});
24678 try mod.errNoteNonLazy(src_loc, msg, "only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible", .{});
2467924679 },
2468024680 .Fn => {
2468124681 if (position != .other) {
test/behavior/extern_struct_zero_size_fields.zig created+21
......@@ -0,0 +1,21 @@
1const E = enum(u0) {
2 the_only_possible_value,
3};
4
5const S = struct {};
6
7const T = extern struct {
8 foo: u0 = 0,
9 bar: void = {},
10 baz: struct {} = .{},
11 ayy: E = .the_only_possible_value,
12 arr: [0]u0 = .{},
13 matey: [128]void = [_]void{{}} ** 128,
14 running_out_of_ideas: packed struct {} = .{},
15 one_more: [256]S = [_]S{.{}} ** 256,
16};
17
18test {
19 var t: T = .{};
20 _ = t;
21}
test/cases/compile_errors/exported_enum_without_explicit_integer_tag_type.zig+1-1
......@@ -14,5 +14,5 @@ comptime {
1414// :3:5: error: unable to export type 'type'
1515// :7:5: error: unable to export type 'tmp.E'
1616// :7:5: note: enum tag type 'u1' is not extern compatible
17// :7:5: note: only integers with 8, 16, 32, 64 and 128 bits are extern compatible
17// :7:5: note: only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible
1818// :1:11: note: enum declared here
test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig+1-1
......@@ -43,5 +43,5 @@ export fn entry() void {
4343//
4444// :33:8: error: extern structs cannot contain fields of type 'tmp.E'
4545// :33:8: note: enum tag type 'u9' is not extern compatible
46// :33:8: note: only integers with power of two bits are extern compatible
46// :33:8: note: only integers with 0 or power of two bits are extern compatible
4747// :2:15: note: enum declared here
test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig+1-1
......@@ -13,5 +13,5 @@ export fn entry() void {
1313//
1414// :3:8: error: extern structs cannot contain fields of type 'tmp.E'
1515// :3:8: note: enum tag type 'u31' is not extern compatible
16// :3:8: note: only integers with power of two bits are extern compatible
16// :3:8: note: only integers with 0 or power of two bits are extern compatible
1717// :1:15: note: enum declared here
test/cases/compile_errors/extern_variable_has_non_extern_type.zig+1-1
......@@ -8,4 +8,4 @@ pub export fn entry() void {
88// target=native
99//
1010// :1:17: error: extern variable cannot have type 'u3'
11// :1:17: note: only integers with power of two bits are extern compatible
11// :1:17: note: only integers with 0 or power of two bits are extern compatible
test/cases/compile_errors/function_with_non-extern_non-packed_enum_parameter.zig+1-1
......@@ -9,5 +9,5 @@ export fn entry(foo: Foo) void {
99//
1010// :2:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C'
1111// :2:17: note: enum tag type 'u2' is not extern compatible
12// :2:17: note: only integers with 8, 16, 32, 64 and 128 bits are extern compatible
12// :2:17: note: only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible
1313// :1:13: note: enum declared here
test/cases/compile_errors/variadic_arg_validation.zig+1-1
......@@ -24,6 +24,6 @@ pub export fn entry3() void {
2424// :4:33: error: integer and float literals passed to variadic function must be casted to a fixed-size number type
2525// :9:24: error: arrays must be passed by reference to variadic function
2626// :13:24: error: cannot pass 'u48' to variadic function
27// :13:24: note: only integers with power of two bits are extern compatible
27// :13:24: note: only integers with 0 or power of two bits are extern compatible
2828// :17:24: error: cannot pass 'void' to variadic function
2929// :17:24: note: 'void' is a zero bit type; for C 'void' use 'anyopaque'