From 784be05a1abd94da96cce7c6381395f4f7b1ab5f Mon Sep 17 00:00:00 2001 From: Matthew Borkowski Date: Sat, 9 Oct 2021 18:16:43 -0400 Subject: [PATCH 1/2] stage2: fix astgen for anytype union fields and differentiate anytype vs inferred void in semaUnionFields --- src/AstGen.zig | 9 ++++++--- src/Sema.zig | 4 +++- src/Zir.zig | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/AstGen.zig b/src/AstGen.zig index a3a39c1b57..d7130b2888 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -4134,7 +4134,7 @@ fn unionDeclInner( if (member.comptime_token) |comptime_token| { return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{}); } - try fields_data.ensureUnusedCapacity(gpa, if (node_tags[member.ast.type_expr] != .@"anytype") 4 else 3); + try fields_data.ensureUnusedCapacity(gpa, 4); const field_name = try astgen.identAsString(member.ast.name_token); fields_data.appendAssumeCapacity(field_name); @@ -4149,8 +4149,11 @@ fn unionDeclInner( (@as(u32, @boolToInt(have_value)) << 30) | (@as(u32, @boolToInt(unused)) << 31); - if (have_type and node_tags[member.ast.type_expr] != .@"anytype") { - const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); + if (have_type) { + const field_type: Zir.Inst.Ref = if (node_tags[member.ast.type_expr] == .@"anytype") + .none + else + try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); fields_data.appendAssumeCapacity(@enumToInt(field_type)); } if (have_align) { diff --git a/src/Sema.zig b/src/Sema.zig index 31846a0f91..33251c939d 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -12629,8 +12629,10 @@ fn semaUnionFields( set.putAssumeCapacity(field_name, {}); } - const field_ty: Type = if (field_type_ref == .none) + const field_ty: Type = if (!has_type) Type.initTag(.void) + else if (field_type_ref == .none) + Type.initTag(.noreturn) else // TODO: if we need to report an error here, use a source location // that points to this type expression rather than the union. diff --git a/src/Zir.zig b/src/Zir.zig index cc2c028345..3b21a24cc6 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -2686,6 +2686,7 @@ pub const Inst = struct { /// 9. fields: { // for every fields_len /// field_name: u32, // null terminated string index /// field_type: Ref, // if corresponding bit is set + /// - if none, means `anytype`. /// align: Ref, // if corresponding bit is set /// tag_value: Ref, // if corresponding bit is set /// } From ea45062d8227f9f9f1356c78eac5a0daa578f97e Mon Sep 17 00:00:00 2001 From: Matthew Borkowski Date: Sat, 9 Oct 2021 18:50:44 -0400 Subject: [PATCH 2/2] stage2: add astgen errors for untyped union fields and union field values without inferred tag type --- src/AstGen.zig | 16 ++++++++++++++++ test/stage2/cbe.zig | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/AstGen.zig b/src/AstGen.zig index d7130b2888..f846dd1c8c 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -4155,6 +4155,8 @@ fn unionDeclInner( else try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); fields_data.appendAssumeCapacity(@enumToInt(field_type)); + } else if (arg_inst == .none and !have_auto_enum) { + return astgen.failNode(member_node, "union field missing type", .{}); } if (have_align) { const align_inst = try expr(&block_scope, &block_scope.base, .{ .ty = .u32_type }, member.ast.align_expr); @@ -4175,6 +4177,20 @@ fn unionDeclInner( }, ); } + if (!have_auto_enum) { + return astgen.failNodeNotes( + node, + "explicitly valued tagged union requires inferred enum tag type", + .{}, + &[_]u32{ + try astgen.errNoteNode( + member.ast.value_expr, + "tag value specified here", + .{}, + ), + }, + ); + } const tag_value = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr); fields_data.appendAssumeCapacity(@enumToInt(tag_value)); } diff --git a/test/stage2/cbe.zig b/test/stage2/cbe.zig index 12bc21b741..a6e81a5f5c 100644 --- a/test/stage2/cbe.zig +++ b/test/stage2/cbe.zig @@ -570,6 +570,40 @@ pub fn addCases(ctx: *TestContext) !void { , ""); } + { + var case = ctx.exeFromCompiledC("unions", .{}); + + case.addError( + \\const U = union { + \\ a: u32, + \\ b + \\}; + , &.{ + ":3:5: error: union field missing type", + }); + + case.addError( + \\const E = enum { a, b }; + \\const U = union(E) { + \\ a: u32 = 1, + \\ b: f32 = 2, + \\}; + , &.{ + ":2:11: error: explicitly valued tagged union requires inferred enum tag type", + ":3:14: note: tag value specified here", + }); + + case.addError( + \\const U = union(enum) { + \\ a: u32 = 1, + \\ b: f32 = 2, + \\}; + , &.{ + ":1:11: error: explicitly valued tagged union missing integer tag type", + ":2:14: note: tag value specified here", + }); + } + { var case = ctx.exeFromCompiledC("enums", .{});