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
This commit is contained in:
AdamGoertz
2023-07-29 12:45:01 -04:00
committed by GitHub
parent 8d1805f81c
commit 796927b900
8 changed files with 33 additions and 12 deletions

View File

@@ -24590,7 +24590,7 @@ fn validateExternType(
.ErrorSet,
.Frame,
=> return false,
.Void => return position == .union_field or position == .ret_ty,
.Void => return position == .union_field or position == .ret_ty or position == .struct_field or position == .element,
.NoReturn => return position == .ret_ty,
.Opaque,
.Bool,
@@ -24599,7 +24599,7 @@ fn validateExternType(
=> return true,
.Pointer => return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty)),
.Int => switch (ty.intInfo(mod).bits) {
8, 16, 32, 64, 128 => return true,
0, 8, 16, 32, 64, 128 => return true,
else => return false,
},
.Fn => {
@@ -24620,11 +24620,11 @@ fn validateExternType(
.Packed => {
const bit_size = try ty.bitSizeAdvanced(mod, sema);
switch (bit_size) {
8, 16, 32, 64, 128 => return true,
0, 8, 16, 32, 64, 128 => return true,
else => return false,
}
},
.Auto => return false,
.Auto => return !(try sema.typeHasRuntimeBits(ty)),
},
.Array => {
if (position == .ret_ty or position == .param_ty) return false;
@@ -24673,9 +24673,9 @@ fn explainWhyTypeIsNotExtern(
.Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
.NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
.Int => if (!std.math.isPowerOfTwo(ty.intInfo(mod).bits)) {
try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{});
try mod.errNoteNonLazy(src_loc, msg, "only integers with 0 or power of two bits are extern compatible", .{});
} else {
try mod.errNoteNonLazy(src_loc, msg, "only integers with 8, 16, 32, 64 and 128 bits are extern compatible", .{});
try mod.errNoteNonLazy(src_loc, msg, "only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible", .{});
},
.Fn => {
if (position != .other) {

View File

@@ -0,0 +1,21 @@
const E = enum(u0) {
the_only_possible_value,
};
const S = struct {};
const T = extern struct {
foo: u0 = 0,
bar: void = {},
baz: struct {} = .{},
ayy: E = .the_only_possible_value,
arr: [0]u0 = .{},
matey: [128]void = [_]void{{}} ** 128,
running_out_of_ideas: packed struct {} = .{},
one_more: [256]S = [_]S{.{}} ** 256,
};
test {
var t: T = .{};
_ = t;
}

View File

@@ -14,5 +14,5 @@ comptime {
// :3:5: error: unable to export type 'type'
// :7:5: error: unable to export type 'tmp.E'
// :7:5: note: enum tag type 'u1' is not extern compatible
// :7:5: note: only integers with 8, 16, 32, 64 and 128 bits are extern compatible
// :7:5: note: only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible
// :1:11: note: enum declared here

View File

@@ -43,5 +43,5 @@ export fn entry() void {
//
// :33:8: error: extern structs cannot contain fields of type 'tmp.E'
// :33:8: note: enum tag type 'u9' is not extern compatible
// :33:8: note: only integers with power of two bits are extern compatible
// :33:8: note: only integers with 0 or power of two bits are extern compatible
// :2:15: note: enum declared here

View File

@@ -13,5 +13,5 @@ export fn entry() void {
//
// :3:8: error: extern structs cannot contain fields of type 'tmp.E'
// :3:8: note: enum tag type 'u31' is not extern compatible
// :3:8: note: only integers with power of two bits are extern compatible
// :3:8: note: only integers with 0 or power of two bits are extern compatible
// :1:15: note: enum declared here

View File

@@ -8,4 +8,4 @@ pub export fn entry() void {
// target=native
//
// :1:17: error: extern variable cannot have type 'u3'
// :1:17: note: only integers with power of two bits are extern compatible
// :1:17: note: only integers with 0 or power of two bits are extern compatible

View File

@@ -9,5 +9,5 @@ export fn entry(foo: Foo) void {
//
// :2:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C'
// :2:17: note: enum tag type 'u2' is not extern compatible
// :2:17: note: only integers with 8, 16, 32, 64 and 128 bits are extern compatible
// :2:17: note: only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible
// :1:13: note: enum declared here

View File

@@ -24,6 +24,6 @@ pub export fn entry3() void {
// :4:33: error: integer and float literals passed to variadic function must be casted to a fixed-size number type
// :9:24: error: arrays must be passed by reference to variadic function
// :13:24: error: cannot pass 'u48' to variadic function
// :13:24: note: only integers with power of two bits are extern compatible
// :13:24: note: only integers with 0 or power of two bits are extern compatible
// :17:24: error: cannot pass 'void' to variadic function
// :17:24: note: 'void' is a zero bit type; for C 'void' use 'anyopaque'