| author | |
| committer | |
| log | 796927b900ad4b774c30d1cb545d606f23040d2f |
| tree | 7fd53185ae5dfadce29a8ab95f27d5bade0ae05c |
| parent | 8d1805f81c97a0b773772e86aa39f26c894b7985 |
| signature |
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 elements8 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 @@ | ||
| 1 | const E = enum(u0) { | ||
| 2 | the_only_possible_value, | ||
| 3 | }; | ||
| 4 | |||
| 5 | const S = struct {}; | ||
| 6 | |||
| 7 | const 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 | |||
| 18 | test { | ||
| 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 compatible | 16 | // :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 |
| 18 | // :1:11: note: enum declared here | 18 | // :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 compatible | 45 | // :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 |
| 47 | // :2:15: note: enum declared here | 47 | // :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 compatible | 15 | // :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 |
| 17 | // :1:15: note: enum declared here | 17 | // :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=native | 8 | // 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 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 { | ... | @@ -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 compatible | 11 | // :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 |
| 13 | // :1:13: note: enum declared here | 13 | // :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 type | 24 | // :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 function | 25 | // :9:24: error: arrays must be passed by reference to variadic function |
| 26 | // :13:24: error: cannot pass 'u48' to variadic function | 26 | // :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 |
| 28 | // :17:24: error: cannot pass 'void' to variadic function | 28 | // :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' |