authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-19 01:25:10+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-21 12:21:30-07:00
log1705a21f804a79d5267a198dc28d8a91dc0dc201
treeb3877b15738f30261ee8a4255dfe5ad42f841568
parent8feb3987608945040c955bd7b24be3841ebf74ac

Sema: more union and enum tag type validation


17 files changed, 159 insertions(+), 96 deletions(-)

src/AstGen.zig+14-7
...@@ -4299,7 +4299,7 @@ fn unionDeclInner(...@@ -4299,7 +4299,7 @@ fn unionDeclInner(
4299 members: []const Ast.Node.Index,4299 members: []const Ast.Node.Index,
4300 layout: std.builtin.Type.ContainerLayout,4300 layout: std.builtin.Type.ContainerLayout,
4301 arg_node: Ast.Node.Index,4301 arg_node: Ast.Node.Index,
4302 have_auto_enum: bool,4302 auto_enum_tok: ?Ast.TokenIndex,
4303) InnerError!Zir.Inst.Ref {4303) InnerError!Zir.Inst.Ref {
4304 const decl_inst = try gz.reserveInstructionIndex();4304 const decl_inst = try gz.reserveInstructionIndex();
43054305
...@@ -4333,6 +4333,15 @@ fn unionDeclInner(...@@ -4333,6 +4333,15 @@ fn unionDeclInner(
4333 const decl_count = try astgen.scanDecls(&namespace, members);4333 const decl_count = try astgen.scanDecls(&namespace, members);
4334 const field_count = @intCast(u32, members.len - decl_count);4334 const field_count = @intCast(u32, members.len - decl_count);
43354335
4336 if (layout != .Auto and (auto_enum_tok != null or arg_node != 0)) {
4337 const layout_str = if (layout == .Extern) "extern" else "packed";
4338 if (arg_node != 0) {
4339 return astgen.failNode(arg_node, "{s} union does not support enum tag type", .{layout_str});
4340 } else {
4341 return astgen.failTok(auto_enum_tok.?, "{s} union does not support enum tag type", .{layout_str});
4342 }
4343 }
4344
4336 const arg_inst: Zir.Inst.Ref = if (arg_node != 0)4345 const arg_inst: Zir.Inst.Ref = if (arg_node != 0)
4337 try typeExpr(&block_scope, &namespace.base, arg_node)4346 try typeExpr(&block_scope, &namespace.base, arg_node)
4338 else4347 else
...@@ -4367,7 +4376,7 @@ fn unionDeclInner(...@@ -4367,7 +4376,7 @@ fn unionDeclInner(
4367 if (have_type) {4376 if (have_type) {
4368 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr);4377 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr);
4369 wip_members.appendToField(@enumToInt(field_type));4378 wip_members.appendToField(@enumToInt(field_type));
4370 } else if (arg_inst == .none and !have_auto_enum) {4379 } else if (arg_inst == .none and auto_enum_tok == null) {
4371 return astgen.failNode(member_node, "union field missing type", .{});4380 return astgen.failNode(member_node, "union field missing type", .{});
4372 }4381 }
4373 if (have_align) {4382 if (have_align) {
...@@ -4389,7 +4398,7 @@ fn unionDeclInner(...@@ -4389,7 +4398,7 @@ fn unionDeclInner(
4389 },4398 },
4390 );4399 );
4391 }4400 }
4392 if (!have_auto_enum) {4401 if (auto_enum_tok == null) {
4393 return astgen.failNodeNotes(4402 return astgen.failNodeNotes(
4394 node,4403 node,
4395 "explicitly valued tagged union requires inferred enum tag type",4404 "explicitly valued tagged union requires inferred enum tag type",
...@@ -4425,7 +4434,7 @@ fn unionDeclInner(...@@ -4425,7 +4434,7 @@ fn unionDeclInner(
4425 .body_len = body_len,4434 .body_len = body_len,
4426 .fields_len = field_count,4435 .fields_len = field_count,
4427 .decls_len = decl_count,4436 .decls_len = decl_count,
4428 .auto_enum_tag = have_auto_enum,4437 .auto_enum_tag = auto_enum_tok != null,
4429 });4438 });
44304439
4431 wip_members.finishBits(bits_per_field);4440 wip_members.finishBits(bits_per_field);
...@@ -4481,9 +4490,7 @@ fn containerDecl(...@@ -4481,9 +4490,7 @@ fn containerDecl(
4481 else => unreachable,4490 else => unreachable,
4482 } else std.builtin.Type.ContainerLayout.Auto;4491 } else std.builtin.Type.ContainerLayout.Auto;
44834492
4484 const have_auto_enum = container_decl.ast.enum_token != null;4493 const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, layout, container_decl.ast.arg, container_decl.ast.enum_token);
4485
4486 const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, layout, container_decl.ast.arg, have_auto_enum);
4487 return rvalue(gz, rl, result, node);4494 return rvalue(gz, rl, result, node);
4488 },4495 },
4489 .keyword_enum => {4496 .keyword_enum => {
src/Module.zig+29-2
...@@ -2626,6 +2626,29 @@ pub const SrcLoc = struct {...@@ -2626,6 +2626,29 @@ pub const SrcLoc = struct {
2626 };2626 };
2627 return nodeToSpan(tree, full.ast.bit_range_end);2627 return nodeToSpan(tree, full.ast.bit_range_end);
2628 },2628 },
2629 .node_offset_container_tag => |node_off| {
2630 const tree = try src_loc.file_scope.getTree(gpa);
2631 const node_tags = tree.nodes.items(.tag);
2632 const parent_node = src_loc.declRelativeToNodeIndex(node_off);
2633
2634 switch (node_tags[parent_node]) {
2635 .container_decl_arg, .container_decl_arg_trailing => {
2636 const full = tree.containerDeclArg(parent_node);
2637 return nodeToSpan(tree, full.ast.arg);
2638 },
2639 .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => {
2640 const full = tree.taggedUnionEnumTag(parent_node);
2641
2642 return tokensToSpan(
2643 tree,
2644 tree.firstToken(full.ast.arg) - 2,
2645 tree.lastToken(full.ast.arg) + 1,
2646 tree.nodes.items(.main_token)[full.ast.arg],
2647 );
2648 },
2649 else => unreachable,
2650 }
2651 },
2629 }2652 }
2630 }2653 }
26312654
...@@ -2935,6 +2958,9 @@ pub const LazySrcLoc = union(enum) {...@@ -2935,6 +2958,9 @@ pub const LazySrcLoc = union(enum) {
2935 /// The source location points to the host size of a pointer.2958 /// The source location points to the host size of a pointer.
2936 /// The Decl is determined contextually.2959 /// The Decl is determined contextually.
2937 node_offset_ptr_hostsize: i32,2960 node_offset_ptr_hostsize: i32,
2961 /// The source location points to the tag type of an union or an enum.
2962 /// The Decl is determined contextually.
2963 node_offset_container_tag: i32,
29382964
2939 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;2965 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
29402966
...@@ -3008,6 +3034,7 @@ pub const LazySrcLoc = union(enum) {...@@ -3008,6 +3034,7 @@ pub const LazySrcLoc = union(enum) {
3008 .node_offset_ptr_addrspace,3034 .node_offset_ptr_addrspace,
3009 .node_offset_ptr_bitoffset,3035 .node_offset_ptr_bitoffset,
3010 .node_offset_ptr_hostsize,3036 .node_offset_ptr_hostsize,
3037 .node_offset_container_tag,
3011 => .{3038 => .{
3012 .file_scope = decl.getFileScope(),3039 .file_scope = decl.getFileScope(),
3013 .parent_decl_node = decl.src_node,3040 .parent_decl_node = decl.src_node,
...@@ -4711,7 +4738,7 @@ pub fn scanNamespace(...@@ -4711,7 +4738,7 @@ pub fn scanNamespace(
4711 extra_start: usize,4738 extra_start: usize,
4712 decls_len: u32,4739 decls_len: u32,
4713 parent_decl: *Decl,4740 parent_decl: *Decl,
4714) SemaError!usize {4741) Allocator.Error!usize {
4715 const tracy = trace(@src());4742 const tracy = trace(@src());
4716 defer tracy.end();4743 defer tracy.end();
47174744
...@@ -4758,7 +4785,7 @@ const ScanDeclIter = struct {...@@ -4758,7 +4785,7 @@ const ScanDeclIter = struct {
4758 unnamed_test_index: usize = 0,4785 unnamed_test_index: usize = 0,
4759};4786};
47604787
4761fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!void {4788fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Error!void {
4762 const tracy = trace(@src());4789 const tracy = trace(@src());
4763 defer tracy.end();4790 defer tracy.end();
47644791
src/Sema.zig+50-34
...@@ -2344,6 +2344,7 @@ fn zirEnumDecl(...@@ -2344,6 +2344,7 @@ fn zirEnumDecl(
2344 extra_index += 1;2344 extra_index += 1;
2345 break :blk LazySrcLoc.nodeOffset(node_offset);2345 break :blk LazySrcLoc.nodeOffset(node_offset);
2346 } else sema.src;2346 } else sema.src;
2347 const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
23472348
2348 const tag_type_ref = if (small.has_tag_type) blk: {2349 const tag_type_ref = if (small.has_tag_type) blk: {
2349 const tag_type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);2350 const tag_type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
...@@ -2369,8 +2370,10 @@ fn zirEnumDecl(...@@ -2369,8 +2370,10 @@ fn zirEnumDecl(
2369 break :blk decls_len;2370 break :blk decls_len;
2370 } else 0;2371 } else 0;
23712372
2373 var done = false;
2374
2372 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);2375 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
2373 errdefer new_decl_arena.deinit();2376 errdefer if (!done) new_decl_arena.deinit();
2374 const new_decl_arena_allocator = new_decl_arena.allocator();2377 const new_decl_arena_allocator = new_decl_arena.allocator();
23752378
2376 const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull);2379 const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull);
...@@ -2387,7 +2390,7 @@ fn zirEnumDecl(...@@ -2387,7 +2390,7 @@ fn zirEnumDecl(
2387 }, small.name_strategy, "enum", inst);2390 }, small.name_strategy, "enum", inst);
2388 const new_decl = mod.declPtr(new_decl_index);2391 const new_decl = mod.declPtr(new_decl_index);
2389 new_decl.owns_tv = true;2392 new_decl.owns_tv = true;
2390 errdefer mod.abortAnonDecl(new_decl_index);2393 errdefer if (!done) mod.abortAnonDecl(new_decl_index);
23912394
2392 enum_obj.* = .{2395 enum_obj.* = .{
2393 .owner_decl = new_decl_index,2396 .owner_decl = new_decl_index,
...@@ -2406,19 +2409,28 @@ fn zirEnumDecl(...@@ -2406,19 +2409,28 @@ fn zirEnumDecl(
2406 &enum_obj.namespace, new_decl, new_decl.name,2409 &enum_obj.namespace, new_decl, new_decl.name,
2407 });2410 });
24082411
2412 try new_decl.finalizeNewArena(&new_decl_arena);
2413 const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);
2414 done = true;
2415
2416 var decl_arena = new_decl.value_arena.?.promote(gpa);
2417 defer new_decl.value_arena.?.* = decl_arena.state;
2418 const decl_arena_allocator = decl_arena.allocator();
2419
2409 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);2420 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
24102421
2411 const body = sema.code.extra[extra_index..][0..body_len];2422 const body = sema.code.extra[extra_index..][0..body_len];
2412 if (fields_len == 0) {2423 if (fields_len == 0) {
2413 assert(body.len == 0);2424 assert(body.len == 0);
2414 if (tag_type_ref != .none) {2425 if (tag_type_ref != .none) {
2415 // TODO better source location2426 const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
2416 const ty = try sema.resolveType(block, src, tag_type_ref);2427 if (ty.zigTypeTag() != .Int and ty.zigTypeTag() != .ComptimeInt) {
2428 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
2429 }
2417 enum_obj.tag_ty = try ty.copy(new_decl_arena_allocator);2430 enum_obj.tag_ty = try ty.copy(new_decl_arena_allocator);
2418 enum_obj.tag_ty_inferred = false;2431 enum_obj.tag_ty_inferred = false;
2419 }2432 }
2420 try new_decl.finalizeNewArena(&new_decl_arena);2433 return decl_val;
2421 return sema.analyzeDeclVal(block, src, new_decl_index);
2422 }2434 }
2423 extra_index += body.len;2435 extra_index += body.len;
24242436
...@@ -2471,13 +2483,15 @@ fn zirEnumDecl(...@@ -2471,13 +2483,15 @@ fn zirEnumDecl(
2471 try wip_captures.finalize();2483 try wip_captures.finalize();
24722484
2473 if (tag_type_ref != .none) {2485 if (tag_type_ref != .none) {
2474 // TODO better source location2486 const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
2475 const ty = try sema.resolveType(block, src, tag_type_ref);2487 if (ty.zigTypeTag() != .Int and ty.zigTypeTag() != .ComptimeInt) {
2476 enum_obj.tag_ty = try ty.copy(new_decl_arena_allocator);2488 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
2489 }
2490 enum_obj.tag_ty = try ty.copy(decl_arena_allocator);
2477 enum_obj.tag_ty_inferred = false;2491 enum_obj.tag_ty_inferred = false;
2478 } else {2492 } else {
2479 const bits = std.math.log2_int_ceil(usize, fields_len);2493 const bits = std.math.log2_int_ceil(usize, fields_len);
2480 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(new_decl_arena_allocator, bits);2494 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits);
2481 enum_obj.tag_ty_inferred = true;2495 enum_obj.tag_ty_inferred = true;
2482 }2496 }
2483 }2497 }
...@@ -2488,12 +2502,12 @@ fn zirEnumDecl(...@@ -2488,12 +2502,12 @@ fn zirEnumDecl(
2488 }2502 }
2489 }2503 }
24902504
2491 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);2505 try enum_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
2492 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {2506 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
2493 if (bag != 0) break true;2507 if (bag != 0) break true;
2494 } else false;2508 } else false;
2495 if (any_values) {2509 if (any_values) {
2496 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{2510 try enum_obj.values.ensureTotalCapacityContext(decl_arena_allocator, fields_len, .{
2497 .ty = enum_obj.tag_ty,2511 .ty = enum_obj.tag_ty,
2498 .mod = mod,2512 .mod = mod,
2499 });2513 });
...@@ -2518,7 +2532,7 @@ fn zirEnumDecl(...@@ -2518,7 +2532,7 @@ fn zirEnumDecl(
2518 extra_index += 1;2532 extra_index += 1;
25192533
2520 // This string needs to outlive the ZIR code.2534 // This string needs to outlive the ZIR code.
2521 const field_name = try new_decl_arena_allocator.dupe(u8, field_name_zir);2535 const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
25222536
2523 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);2537 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
2524 if (gop.found_existing) {2538 if (gop.found_existing) {
...@@ -2542,7 +2556,7 @@ fn zirEnumDecl(...@@ -2542,7 +2556,7 @@ fn zirEnumDecl(
2542 // But only resolve the source location if we need to emit a compile error.2556 // But only resolve the source location if we need to emit a compile error.
2543 const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref, "enum tag value must be comptime known")).val;2557 const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref, "enum tag value must be comptime known")).val;
2544 last_tag_val = tag_val;2558 last_tag_val = tag_val;
2545 const copied_tag_val = try tag_val.copy(new_decl_arena_allocator);2559 const copied_tag_val = try tag_val.copy(decl_arena_allocator);
2546 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{2560 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
2547 .ty = enum_obj.tag_ty,2561 .ty = enum_obj.tag_ty,
2548 .mod = mod,2562 .mod = mod,
...@@ -2553,16 +2567,14 @@ fn zirEnumDecl(...@@ -2553,16 +2567,14 @@ fn zirEnumDecl(
2553 else2567 else
2554 Value.zero;2568 Value.zero;
2555 last_tag_val = tag_val;2569 last_tag_val = tag_val;
2556 const copied_tag_val = try tag_val.copy(new_decl_arena_allocator);2570 const copied_tag_val = try tag_val.copy(decl_arena_allocator);
2557 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{2571 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
2558 .ty = enum_obj.tag_ty,2572 .ty = enum_obj.tag_ty,
2559 .mod = mod,2573 .mod = mod,
2560 });2574 });
2561 }2575 }
2562 }2576 }
25632577 return decl_val;
2564 try new_decl.finalizeNewArena(&new_decl_arena);
2565 return sema.analyzeDeclVal(block, src, new_decl_index);
2566}2578}
25672579
2568fn zirUnionDecl(2580fn zirUnionDecl(
...@@ -8551,11 +8563,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8551,11 +8563,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8551 if (seen_src != null) continue;8563 if (seen_src != null) continue;
85528564
8553 const field_name = operand_ty.enumFieldName(i);8565 const field_name = operand_ty.enumFieldName(i);
85548566 try sema.addFieldErrNote(
8555 const field_src = src; // TODO better source location
8556 try sema.errNote(
8557 block,8567 block,
8558 field_src,8568 operand_ty,
8569 i,
8559 msg,8570 msg,
8560 "unhandled enumeration value: '{s}'",8571 "unhandled enumeration value: '{s}'",
8561 .{field_name},8572 .{field_name},
...@@ -10587,7 +10598,7 @@ fn zirOverflowArithmetic(...@@ -10587,7 +10598,7 @@ fn zirOverflowArithmetic(
10587 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);10598 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
10588 const dest_ty = lhs_ty;10599 const dest_ty = lhs_ty;
10589 if (dest_ty.scalarType().zigTypeTag() != .Int) {10600 if (dest_ty.scalarType().zigTypeTag() != .Int) {
10590 return sema.fail(block, src, "expected vector of integers or integer type, found '{}'", .{dest_ty.fmt(mod)});10601 return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)});
10591 }10602 }
1059210603
10593 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);10604 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
...@@ -25175,7 +25186,7 @@ fn resolveTypeFieldsUnion(...@@ -25175,7 +25186,7 @@ fn resolveTypeFieldsUnion(
25175 }25186 }
2517625187
25177 union_obj.status = .field_types_wip;25188 union_obj.status = .field_types_wip;
25178 try semaUnionFields(block, sema.mod, union_obj);25189 try semaUnionFields(sema.mod, union_obj);
25179 union_obj.status = .have_field_types;25190 union_obj.status = .have_field_types;
25180}25191}
2518125192
...@@ -25462,7 +25473,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -25462,7 +25473,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
25462 struct_obj.have_field_inits = true;25473 struct_obj.have_field_inits = true;
25463}25474}
2546425475
25465fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) CompileError!void {25476fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
25466 const tracy = trace(@src());25477 const tracy = trace(@src());
25467 defer tracy.end();25478 defer tracy.end();
2546825479
...@@ -25567,10 +25578,14 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil...@@ -25567,10 +25578,14 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
25567 var enum_value_map: ?*Module.EnumNumbered.ValueMap = null;25578 var enum_value_map: ?*Module.EnumNumbered.ValueMap = null;
25568 var tag_ty_field_names: ?Module.EnumFull.NameMap = null;25579 var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
25569 if (tag_type_ref != .none) {25580 if (tag_type_ref != .none) {
25570 const provided_ty = try sema.resolveType(&block_scope, src, tag_type_ref);25581 const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
25582 const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref);
25571 if (small.auto_enum_tag) {25583 if (small.auto_enum_tag) {
25572 // The provided type is an integer type and we must construct the enum tag type here.25584 // The provided type is an integer type and we must construct the enum tag type here.
25573 int_tag_ty = provided_ty;25585 int_tag_ty = provided_ty;
25586 if (int_tag_ty.zigTypeTag() != .Int and int_tag_ty.zigTypeTag() != .ComptimeInt) {
25587 return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(sema.mod)});
25588 }
25574 union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty, union_obj);25589 union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty, union_obj);
25575 const enum_obj = union_obj.tag_ty.castTag(.enum_numbered).?.data;25590 const enum_obj = union_obj.tag_ty.castTag(.enum_numbered).?.data;
25576 enum_field_names = &enum_obj.fields;25591 enum_field_names = &enum_obj.fields;
...@@ -25579,8 +25594,7 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil...@@ -25579,8 +25594,7 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
25579 // The provided type is the enum tag type.25594 // The provided type is the enum tag type.
25580 union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator);25595 union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator);
25581 if (union_obj.tag_ty.zigTypeTag() != .Enum) {25596 if (union_obj.tag_ty.zigTypeTag() != .Enum) {
25582 const tag_ty_src = src; // TODO better source location25597 return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)});
25583 return sema.fail(block, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)});
25584 }25598 }
25585 // The fields of the union must match the enum exactly.25599 // The fields of the union must match the enum exactly.
25586 // Store a copy of the enum field names so we can check for25600 // Store a copy of the enum field names so we can check for
...@@ -25658,7 +25672,7 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil...@@ -25658,7 +25672,7 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
25658 });25672 });
25659 } else {25673 } else {
25660 const val = if (last_tag_val) |val|25674 const val = if (last_tag_val) |val|
25661 try sema.intAdd(block, src, val, Value.one, int_tag_ty)25675 try sema.intAdd(&block_scope, src, val, Value.one, int_tag_ty)
25662 else25676 else
25663 Value.zero;25677 Value.zero;
25664 last_tag_val = val;25678 last_tag_val = val;
...@@ -25712,12 +25726,14 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil...@@ -25712,12 +25726,14 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
25712 const enum_has_field = names.orderedRemove(field_name);25726 const enum_has_field = names.orderedRemove(field_name);
25713 if (!enum_has_field) {25727 if (!enum_has_field) {
25714 const msg = msg: {25728 const msg = msg: {
25715 const msg = try sema.errMsg(block, src, "enum '{}' has no field named '{s}'", .{ union_obj.tag_ty.fmt(sema.mod), field_name });25729 const tree = try sema.getAstTree(&block_scope);
25730 const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);
25731 const msg = try sema.errMsg(&block_scope, field_src, "enum '{}' has no field named '{s}'", .{ union_obj.tag_ty.fmt(sema.mod), field_name });
25716 errdefer msg.destroy(sema.gpa);25732 errdefer msg.destroy(sema.gpa);
25717 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);25733 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
25718 break :msg msg;25734 break :msg msg;
25719 };25735 };
25720 return sema.failWithOwnedErrorMsg(block, msg);25736 return sema.failWithOwnedErrorMsg(&block_scope, msg);
25721 }25737 }
25722 }25738 }
2572325739
...@@ -25739,18 +25755,18 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil...@@ -25739,18 +25755,18 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
25739 if (tag_ty_field_names) |names| {25755 if (tag_ty_field_names) |names| {
25740 if (names.count() > 0) {25756 if (names.count() > 0) {
25741 const msg = msg: {25757 const msg = msg: {
25742 const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});25758 const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});
25743 errdefer msg.destroy(sema.gpa);25759 errdefer msg.destroy(sema.gpa);
2574425760
25745 const enum_ty = union_obj.tag_ty;25761 const enum_ty = union_obj.tag_ty;
25746 for (names.keys()) |field_name| {25762 for (names.keys()) |field_name| {
25747 const field_index = enum_ty.enumFieldIndex(field_name).?;25763 const field_index = enum_ty.enumFieldIndex(field_name).?;
25748 try sema.addFieldErrNote(block, enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name});25764 try sema.addFieldErrNote(&block_scope, enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name});
25749 }25765 }
25750 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);25766 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
25751 break :msg msg;25767 break :msg msg;
25752 };25768 };
25753 return sema.failWithOwnedErrorMsg(block, msg);25769 return sema.failWithOwnedErrorMsg(&block_scope, msg);
25754 }25770 }
25755 }25771 }
25756}25772}
test/cases/compile_errors/extern_union_given_enum_tag_type.zig created+20
...@@ -0,0 +1,20 @@
1const Letter = enum {
2 A,
3 B,
4 C,
5};
6const Payload = extern union(Letter) {
7 A: i32,
8 B: f64,
9 C: bool,
10};
11export fn entry() void {
12 var a = Payload { .A = 1234 };
13 _ = a;
14}
15
16// error
17// backend=stage2
18// target=native
19//
20// :6:30: error: extern union does not support enum tag type
test/cases/compile_errors/non-enum_tag_type_passed_to_union.zig created+13
...@@ -0,0 +1,13 @@
1const Foo = union(u32) {
2 A: i32,
3};
4export fn entry() void {
5 const x = @typeInfo(Foo).Union.tag_type.?;
6 _ = x;
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :1:19: error: expected enum tag type, found 'u32'
test/cases/compile_errors/non-integer_tag_type_to_automatic_union_enum.zig created+13
...@@ -0,0 +1,13 @@
1const Foo = union(enum(f32)) {
2 A: i32,
3};
4export fn entry() void {
5 const x = @typeInfo(Foo).Union.tag_type.?;
6 _ = x;
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :1:24: error: expected integer tag type, found 'f32'
test/cases/compile_errors/non-integer_tag_type_to_enum.zig created+13
...@@ -0,0 +1,13 @@
1const Foo = enum(f32) {
2 A,
3};
4export fn entry() void {
5 var f: Foo = undefined;
6 _ = f;
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :1:18: error: expected integer tag type, found 'f32'
test/cases/compile_errors/stage1/obj/extern_union_given_enum_tag_type.zig deleted-20
...@@ -1,20 +0,0 @@
1const Letter = enum {
2 A,
3 B,
4 C,
5};
6const Payload = extern union(Letter) {
7 A: i32,
8 B: f64,
9 C: bool,
10};
11export fn entry() void {
12 var a = Payload { .A = 1234 };
13 _ = a;
14}
15
16// error
17// backend=stage1
18// target=native
19//
20// tmp.zig:6:30: error: extern union does not support enum tag type
test/cases/compile_errors/stage1/obj/non-enum_tag_type_passed_to_union.zig deleted-13
...@@ -1,13 +0,0 @@
1const Foo = union(u32) {
2 A: i32,
3};
4export fn entry() void {
5 const x = @typeInfo(Foo).Union.tag_type.?;
6 _ = x;
7}
8
9// error
10// backend=stage1
11// target=native
12//
13// tmp.zig:1:19: error: expected enum tag type, found 'u32'
test/cases/compile_errors/stage1/obj/non-integer_tag_type_to_automatic_union_enum.zig deleted-13
...@@ -1,13 +0,0 @@
1const Foo = union(enum(f32)) {
2 A: i32,
3};
4export fn entry() void {
5 const x = @typeInfo(Foo).Union.tag_type.?;
6 _ = x;
7}
8
9// error
10// backend=stage1
11// target=native
12//
13// tmp.zig:1:24: error: expected integer tag type, found 'f32'
test/cases/compile_errors/stage2/union_enum_field_missing.zig+1-1
...@@ -16,6 +16,6 @@ export fn entry() usize {...@@ -16,6 +16,6 @@ export fn entry() usize {
16// error16// error
17// target=native17// target=native
18//18//
19// :7:1: error: enum field(s) missing in union19// :7:11: error: enum field(s) missing in union
20// :4:5: note: field 'c' missing, declared here20// :4:5: note: field 'c' missing, declared here
21// :1:11: note: enum declared here21// :1:11: note: enum declared here
test/cases/compile_errors/stage2/union_extra_field.zig+1-1
...@@ -16,5 +16,5 @@ export fn entry() usize {...@@ -16,5 +16,5 @@ export fn entry() usize {
16// error16// error
17// target=native17// target=native
18//18//
19// :6:1: error: enum 'tmp.E' has no field named 'd'19// :10:5: error: enum 'tmp.E' has no field named 'd'
20// :1:11: note: enum declared here20// :1:11: note: enum declared here
test/cases/compile_errors/switch_expression-missing_enumeration_prong.zig+1-1
...@@ -19,5 +19,5 @@ export fn entry() usize { return @sizeOf(@TypeOf(&f)); }...@@ -19,5 +19,5 @@ export fn entry() usize { return @sizeOf(@TypeOf(&f)); }
19// target=native19// target=native
20//20//
21// :8:5: error: switch must handle all possibilities21// :8:5: error: switch must handle all possibilities
22// :8:5: note: unhandled enumeration value: 'Four'22// :5:5: note: unhandled enumeration value: 'Four'
23// :1:16: note: enum 'tmp.Number' declared here23// :1:16: note: enum 'tmp.Number' declared here
test/cases/compile_errors/switch_on_enum_with_1_field_with_no_prongs.zig+1-1
...@@ -10,5 +10,5 @@ export fn entry() void {...@@ -10,5 +10,5 @@ export fn entry() void {
10// target=native10// target=native
11//11//
12// :5:5: error: switch must handle all possibilities12// :5:5: error: switch must handle all possibilities
13// :5:5: note: unhandled enumeration value: 'M'13// :1:20: note: unhandled enumeration value: 'M'
14// :1:13: note: enum 'tmp.Foo' declared here14// :1:13: note: enum 'tmp.Foo' declared here
test/cases/compile_errors/switching_with_non-exhaustive_enums.zig+1-1
...@@ -35,7 +35,7 @@ pub export fn entry3() void {...@@ -35,7 +35,7 @@ pub export fn entry3() void {
35// target=native35// target=native
36//36//
37// :12:5: error: switch must handle all possibilities37// :12:5: error: switch must handle all possibilities
38// :12:5: note: unhandled enumeration value: 'b'38// :3:5: note: unhandled enumeration value: 'b'
39// :1:11: note: enum 'tmp.E' declared here39// :1:11: note: enum 'tmp.E' declared here
40// :19:5: error: switch on non-exhaustive enum must include 'else' or '_' prong40// :19:5: error: switch on non-exhaustive enum must include 'else' or '_' prong
41// :26:5: error: '_' prong only allowed when switching on non-exhaustive enums41// :26:5: error: '_' prong only allowed when switching on non-exhaustive enums
test/cases/compile_errors/union_with_specified_enum_omits_field.zig+1-1
...@@ -15,6 +15,6 @@ export fn entry() usize {...@@ -15,6 +15,6 @@ export fn entry() usize {
15// backend=stage215// backend=stage2
16// target=native16// target=native
17//17//
18// :6:1: error: enum field(s) missing in union18// :6:17: error: enum field(s) missing in union
19// :4:5: note: field 'C' missing, declared here19// :4:5: note: field 'C' missing, declared here
20// :1:16: note: enum declared here20// :1:16: note: enum declared here
test/stage2/cbe.zig+1-1
...@@ -772,7 +772,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -772,7 +772,7 @@ pub fn addCases(ctx: *TestContext) !void {
772 \\}772 \\}
773 , &.{773 , &.{
774 ":4:5: error: switch must handle all possibilities",774 ":4:5: error: switch must handle all possibilities",
775 ":4:5: note: unhandled enumeration value: 'b'",775 ":1:21: note: unhandled enumeration value: 'b'",
776 ":1:11: note: enum 'tmp.E' declared here",776 ":1:11: note: enum 'tmp.E' declared here",
777 });777 });
778778