Skip to content

Commit f42725c

Browse files
authored
Merge pull request #9925 from mattbork/uniondecl-fixes
stage2: astgen unionDecl fixes
2 parents d1fd864 + ea45062 commit f42725c

File tree

4 files changed

+60
-4
lines changed

4 files changed

+60
-4
lines changed

src/AstGen.zig

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4134,7 +4134,7 @@ fn unionDeclInner(
41344134
if (member.comptime_token) |comptime_token| {
41354135
return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{});
41364136
}
4137-
try fields_data.ensureUnusedCapacity(gpa, if (node_tags[member.ast.type_expr] != .@"anytype") 4 else 3);
4137+
try fields_data.ensureUnusedCapacity(gpa, 4);
41384138

41394139
const field_name = try astgen.identAsString(member.ast.name_token);
41404140
fields_data.appendAssumeCapacity(field_name);
@@ -4149,9 +4149,14 @@ fn unionDeclInner(
41494149
(@as(u32, @boolToInt(have_value)) << 30) |
41504150
(@as(u32, @boolToInt(unused)) << 31);
41514151

4152-
if (have_type and node_tags[member.ast.type_expr] != .@"anytype") {
4153-
const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr);
4152+
if (have_type) {
4153+
const field_type: Zir.Inst.Ref = if (node_tags[member.ast.type_expr] == .@"anytype")
4154+
.none
4155+
else
4156+
try typeExpr(&block_scope, &namespace.base, member.ast.type_expr);
41544157
fields_data.appendAssumeCapacity(@enumToInt(field_type));
4158+
} else if (arg_inst == .none and !have_auto_enum) {
4159+
return astgen.failNode(member_node, "union field missing type", .{});
41554160
}
41564161
if (have_align) {
41574162
const align_inst = try expr(&block_scope, &block_scope.base, .{ .ty = .u32_type }, member.ast.align_expr);
@@ -4172,6 +4177,20 @@ fn unionDeclInner(
41724177
},
41734178
);
41744179
}
4180+
if (!have_auto_enum) {
4181+
return astgen.failNodeNotes(
4182+
node,
4183+
"explicitly valued tagged union requires inferred enum tag type",
4184+
.{},
4185+
&[_]u32{
4186+
try astgen.errNoteNode(
4187+
member.ast.value_expr,
4188+
"tag value specified here",
4189+
.{},
4190+
),
4191+
},
4192+
);
4193+
}
41754194
const tag_value = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr);
41764195
fields_data.appendAssumeCapacity(@enumToInt(tag_value));
41774196
}

src/Sema.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12629,8 +12629,10 @@ fn semaUnionFields(
1262912629
set.putAssumeCapacity(field_name, {});
1263012630
}
1263112631

12632-
const field_ty: Type = if (field_type_ref == .none)
12632+
const field_ty: Type = if (!has_type)
1263312633
Type.initTag(.void)
12634+
else if (field_type_ref == .none)
12635+
Type.initTag(.noreturn)
1263412636
else
1263512637
// TODO: if we need to report an error here, use a source location
1263612638
// that points to this type expression rather than the union.

src/Zir.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2686,6 +2686,7 @@ pub const Inst = struct {
26862686
/// 9. fields: { // for every fields_len
26872687
/// field_name: u32, // null terminated string index
26882688
/// field_type: Ref, // if corresponding bit is set
2689+
/// - if none, means `anytype`.
26892690
/// align: Ref, // if corresponding bit is set
26902691
/// tag_value: Ref, // if corresponding bit is set
26912692
/// }

test/stage2/cbe.zig

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,40 @@ pub fn addCases(ctx: *TestContext) !void {
570570
, "");
571571
}
572572

573+
{
574+
var case = ctx.exeFromCompiledC("unions", .{});
575+
576+
case.addError(
577+
\\const U = union {
578+
\\ a: u32,
579+
\\ b
580+
\\};
581+
, &.{
582+
":3:5: error: union field missing type",
583+
});
584+
585+
case.addError(
586+
\\const E = enum { a, b };
587+
\\const U = union(E) {
588+
\\ a: u32 = 1,
589+
\\ b: f32 = 2,
590+
\\};
591+
, &.{
592+
":2:11: error: explicitly valued tagged union requires inferred enum tag type",
593+
":3:14: note: tag value specified here",
594+
});
595+
596+
case.addError(
597+
\\const U = union(enum) {
598+
\\ a: u32 = 1,
599+
\\ b: f32 = 2,
600+
\\};
601+
, &.{
602+
":1:11: error: explicitly valued tagged union missing integer tag type",
603+
":2:14: note: tag value specified here",
604+
});
605+
}
606+
573607
{
574608
var case = ctx.exeFromCompiledC("enums", .{});
575609

0 commit comments

Comments
 (0)