Commit 122c76a167

Veikka Tuominen <git@vexu.eu>
2022-07-11 18:57:41
Sema: allow `void` as an extern union field & fix invalid extern unions
1 parent d00da05
Changed files (5)
lib
src
test
behavior
lib/compiler_rt/multi3.zig
@@ -59,12 +59,12 @@ const twords = extern union {
     s: S,
 
     const S = if (native_endian == .Little)
-        struct {
+        extern struct {
             low: u64,
             high: u64,
         }
     else
-        struct {
+        extern struct {
             high: u64,
             low: u64,
         };
lib/compiler_rt/shift.zig
@@ -31,9 +31,9 @@ fn Dwords(comptime T: type, comptime signed_half: bool) type {
 
         all: T,
         s: if (native_endian == .Little)
-            struct { low: HalfT, high: HalfT }
+            extern struct { low: HalfT, high: HalfT }
         else
-            struct { high: HalfT, low: HalfT },
+            extern struct { high: HalfT, low: HalfT },
     };
 }
 
lib/std/c/haiku.zig
@@ -30,8 +30,8 @@ pub extern "c" fn _kern_get_current_team() i32;
 pub const sem_t = extern struct {
     type: i32,
     u: extern union {
-        named_sem_id: ?i32,
-        unnamed_sem: ?i32,
+        named_sem_id: i32,
+        unnamed_sem: i32,
     },
     padding: [2]i32,
 };
src/Sema.zig
@@ -18192,6 +18192,7 @@ fn explainWhyTypeIsComptime(
 const ExternPosition = enum {
     ret_ty,
     param_ty,
+    union_field,
     other,
 };
 
@@ -18206,9 +18207,9 @@ fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) CompileEr
         .ErrorUnion,
         .ErrorSet,
         .BoundFn,
-        .Void,
         .Frame,
         => return false,
+        .Void => return position == .union_field,
         .NoReturn => return position == .ret_ty,
         .Opaque,
         .Bool,
@@ -24193,13 +24194,13 @@ fn resolveUnionFully(
         for (union_obj.fields.values()) |field| {
             try sema.resolveTypeFully(block, src, field.ty);
 
-            if (union_obj.layout == .Extern and !(try sema.validateExternType(field.ty, .other))) {
+            if (union_obj.layout == .Extern and !(try sema.validateExternType(field.ty, .union_field))) {
                 const msg = msg: {
                     const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
                     errdefer msg.destroy(sema.gpa);
 
                     const src_decl = sema.mod.declPtr(block.src_decl);
-                    try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), field.ty, .other);
+                    try sema.explainWhyTypeIsNotExtern(block, src, msg, src.toSrcLoc(src_decl), field.ty, .union_field);
 
                     try sema.addDeclaredHereNote(msg, field.ty);
                     break :msg msg;
test/behavior/union.zig
@@ -84,18 +84,19 @@ test "comptime union field access" {
 
 const FooExtern = extern union {
     int: i32,
-    str: struct {
-        slice: []const u8,
+    str: extern struct {
+        slice: [*:0]const u8,
     },
 };
 
 test "basic extern unions" {
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
 
     var foo = FooExtern{ .int = 1 };
     try expect(foo.int == 1);
     foo.str.slice = "Well";
-    try expect(std.mem.eql(u8, foo.str.slice, "Well"));
+    try expect(std.mem.eql(u8, std.mem.sliceTo(foo.str.slice, 0), "Well"));
 }
 
 const ExternPtrOrInt = extern union {