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(...@@ -24590,7 +24590,7 @@ fn validateExternType(
24590 .ErrorSet,24590 .ErrorSet,
24591 .Frame,24591 .Frame,
24592 => return false,24592 => 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,
24594 .NoReturn => return position == .ret_ty,24594 .NoReturn => return position == .ret_ty,
24595 .Opaque,24595 .Opaque,
24596 .Bool,24596 .Bool,
...@@ -24599,7 +24599,7 @@ fn validateExternType(...@@ -24599,7 +24599,7 @@ fn validateExternType(
24599 => return true,24599 => return true,
24600 .Pointer => return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty)),24600 .Pointer => return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty)),
24601 .Int => switch (ty.intInfo(mod).bits) {24601 .Int => switch (ty.intInfo(mod).bits) {
24602 8, 16, 32, 64, 128 => return true,24602 0, 8, 16, 32, 64, 128 => return true,
24603 else => return false,24603 else => return false,
24604 },24604 },
24605 .Fn => {24605 .Fn => {
...@@ -24620,11 +24620,11 @@ fn validateExternType(...@@ -24620,11 +24620,11 @@ fn validateExternType(
24620 .Packed => {24620 .Packed => {
24621 const bit_size = try ty.bitSizeAdvanced(mod, sema);24621 const bit_size = try ty.bitSizeAdvanced(mod, sema);
24622 switch (bit_size) {24622 switch (bit_size) {
24623 8, 16, 32, 64, 128 => return true,24623 0, 8, 16, 32, 64, 128 => return true,
24624 else => return false,24624 else => return false,
24625 }24625 }
24626 },24626 },
24627 .Auto => return false,24627 .Auto => return !(try sema.typeHasRuntimeBits(ty)),
24628 },24628 },
24629 .Array => {24629 .Array => {
24630 if (position == .ret_ty or position == .param_ty) return false;24630 if (position == .ret_ty or position == .param_ty) return false;
...@@ -24673,9 +24673,9 @@ fn explainWhyTypeIsNotExtern(...@@ -24673,9 +24673,9 @@ fn explainWhyTypeIsNotExtern(
24673 .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),24673 .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
24674 .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),24674 .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
24675 .Int => if (!std.math.isPowerOfTwo(ty.intInfo(mod).bits)) {24675 .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", .{});
24677 } else {24677 } 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", .{});
24679 },24679 },
24680 .Fn => {24680 .Fn => {
24681 if (position != .other) {24681 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 {...@@ -14,5 +14,5 @@ comptime {
14// :3:5: error: unable to export type 'type'14// :3:5: error: unable to export type 'type'
15// :7:5: error: unable to export type 'tmp.E'15// :7:5: error: unable to export type 'tmp.E'
16// :7:5: note: enum tag type 'u1' is not extern compatible16// :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 compatible17// :7:5: note: only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible
18// :1:11: note: enum declared here18// :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 {...@@ -43,5 +43,5 @@ export fn entry() void {
43//43//
44// :33:8: error: extern structs cannot contain fields of type 'tmp.E'44// :33:8: error: extern structs cannot contain fields of type 'tmp.E'
45// :33:8: note: enum tag type 'u9' is not extern compatible45// :33:8: note: enum tag type 'u9' is not extern compatible
46// :33:8: note: only integers with power of two bits are extern compatible46// :33:8: note: only integers with 0 or power of two bits are extern compatible
47// :2:15: note: enum declared here47// :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 {...@@ -13,5 +13,5 @@ export fn entry() void {
13//13//
14// :3:8: error: extern structs cannot contain fields of type 'tmp.E'14// :3:8: error: extern structs cannot contain fields of type 'tmp.E'
15// :3:8: note: enum tag type 'u31' is not extern compatible15// :3:8: note: enum tag type 'u31' is not extern compatible
16// :3:8: note: only integers with power of two bits are extern compatible16// :3:8: note: only integers with 0 or power of two bits are extern compatible
17// :1:15: note: enum declared here17// :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 {...@@ -8,4 +8,4 @@ pub export fn entry() void {
8// target=native8// target=native
9//9//
10// :1:17: error: extern variable cannot have type 'u3'10// :1:17: error: extern variable cannot have type 'u3'
11// :1:17: note: only integers with power of two bits are extern compatible11// :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 {...@@ -9,5 +9,5 @@ export fn entry(foo: Foo) void {
9//9//
10// :2:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C'10// :2:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C'
11// :2:17: note: enum tag type 'u2' is not extern compatible11// :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 compatible12// :2:17: note: only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible
13// :1:13: note: enum declared here13// :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 {...@@ -24,6 +24,6 @@ pub export fn entry3() void {
24// :4:33: error: integer and float literals passed to variadic function must be casted to a fixed-size number type24// :4:33: error: integer and float literals passed to variadic function must be casted to a fixed-size number type
25// :9:24: error: arrays must be passed by reference to variadic function25// :9:24: error: arrays must be passed by reference to variadic function
26// :13:24: error: cannot pass 'u48' to variadic function26// :13:24: error: cannot pass 'u48' to variadic function
27// :13:24: note: only integers with power of two bits are extern compatible27// :13:24: note: only integers with 0 or power of two bits are extern compatible
28// :17:24: error: cannot pass 'void' to variadic function28// :17:24: error: cannot pass 'void' to variadic function
29// :17:24: note: 'void' is a zero bit type; for C 'void' use 'anyopaque'29// :17:24: note: 'void' is a zero bit type; for C 'void' use 'anyopaque'