From 6cc2b2616365c2a216f3dd73837f405df094daab Mon Sep 17 00:00:00 2001 From: John Schmidt Date: Sat, 24 Sep 2022 02:23:22 +0200 Subject: [PATCH 1/2] sema: load the correct AST in addFieldErrNote The enum we want to get the fields from might not be declared in the same file as the block we are analyzing, so we should get the AST from the decl's file instead. Closes #12950. --- src/Sema.zig | 33 ++++++++++--------- ...witch_with_enum_declared_in_other_file.zig | 16 +++++++++ 2 files changed, 33 insertions(+), 16 deletions(-) create mode 100644 test/cases/compile_errors/unhandled_enum_value_in_switch_with_enum_declared_in_other_file.zig diff --git a/src/Sema.zig b/src/Sema.zig index a36e1d9a02..a358870656 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1908,7 +1908,6 @@ fn errNote( fn addFieldErrNote( sema: *Sema, - block: *Block, container_ty: Type, field_index: usize, parent: *Module.ErrorMsg, @@ -1918,7 +1917,10 @@ fn addFieldErrNote( const mod = sema.mod; const decl_index = container_ty.getOwnerDecl(); const decl = mod.declPtr(decl_index); - const tree = try sema.getAstTree(block); + const tree = decl.getFileScope().getTree(sema.gpa) catch |err| { + log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); + return error.AnalysisFail; + }; const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index); try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args); } @@ -9371,7 +9373,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const field_name = operand_ty.enumFieldName(i); try sema.addFieldErrNote( - block, operand_ty, i, msg, @@ -17379,7 +17380,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in const enum_ty = union_obj.tag_ty; for (names.keys()) |field_name| { const field_index = enum_ty.enumFieldIndex(field_name).?; - try sema.addFieldErrNote(block, enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); + try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); } try sema.addDeclaredHereNote(msg, union_obj.tag_ty); break :msg msg; @@ -17667,7 +17668,7 @@ fn reifyStruct( sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) { error.AnalysisFail => { const msg = sema.err orelse return err; - try sema.addFieldErrNote(block, struct_ty, index, msg, "while checking this field", .{}); + try sema.addFieldErrNote(struct_ty, index, msg, "while checking this field", .{}); return err; }, else => return err, @@ -22270,7 +22271,7 @@ fn unionFieldPtr( const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{}); errdefer msg.destroy(sema.gpa); - try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); try sema.addDeclaredHereNote(msg, union_ty); break :msg msg; }; @@ -25748,7 +25749,7 @@ fn coerceEnumToUnion( errdefer msg.destroy(sema.gpa); const field_name = union_obj.fields.keys()[field_index]; - try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); try sema.addDeclaredHereNote(msg, union_ty); break :msg msg; }; @@ -25762,7 +25763,7 @@ fn coerceEnumToUnion( }); errdefer msg.destroy(sema.gpa); - try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); try sema.addDeclaredHereNote(msg, union_ty); break :msg msg; }; @@ -25804,7 +25805,7 @@ fn coerceEnumToUnion( ); msg = err_msg; - try sema.addFieldErrNote(block, union_ty, i, err_msg, "'noreturn' field here", .{}); + try sema.addFieldErrNote(union_ty, i, err_msg, "'noreturn' field here", .{}); } } if (msg) |some| { @@ -25834,7 +25835,7 @@ fn coerceEnumToUnion( const field_name = field.key_ptr.*; const field_ty = field.value_ptr.ty; if (!field_ty.hasRuntimeBits()) continue; - try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) }); + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) }); } try sema.addDeclaredHereNote(msg, union_ty); break :msg msg; @@ -28056,7 +28057,7 @@ fn resolveStructLayout( sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) { error.AnalysisFail => { const msg = sema.err orelse return err; - try sema.addFieldErrNote(block, ty, i, msg, "while checking this field", .{}); + try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); return err; }, else => return err, @@ -28076,7 +28077,7 @@ fn resolveStructLayout( _ = sema.typeRequiresComptime(field.ty) catch |err| switch (err) { error.AnalysisFail => { const msg = sema.err orelse return err; - try sema.addFieldErrNote(block, ty, i, msg, "while checking this field", .{}); + try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); return err; }, else => return err, @@ -28215,7 +28216,7 @@ fn resolveUnionLayout( sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) { error.AnalysisFail => { const msg = sema.err orelse return err; - try sema.addFieldErrNote(block, ty, i, msg, "while checking this field", .{}); + try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); return err; }, else => return err, @@ -29101,7 +29102,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { const enum_ty = union_obj.tag_ty; for (names.keys()) |field_name| { const field_index = enum_ty.enumFieldIndex(field_name).?; - try sema.addFieldErrNote(&block_scope, enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); + try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); } try sema.addDeclaredHereNote(msg, union_obj.tag_ty); break :msg msg; @@ -29376,7 +29377,7 @@ pub fn typeHasOnePossibleValue( "struct '{}' depends on itself", .{ty.fmt(sema.mod)}, ); - try sema.addFieldErrNote(block, resolved_ty, i, msg, "while checking this field", .{}); + try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{}); return sema.failWithOwnedErrorMsg(msg); } if ((try sema.typeHasOnePossibleValue(block, src, field.ty)) == null) { @@ -29462,7 +29463,7 @@ pub fn typeHasOnePossibleValue( "union '{}' depends on itself", .{ty.fmt(sema.mod)}, ); - try sema.addFieldErrNote(block, resolved_ty, 0, msg, "while checking this field", .{}); + try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{}); return sema.failWithOwnedErrorMsg(msg); } const val_val = (try sema.typeHasOnePossibleValue(block, src, only_field.ty)) orelse diff --git a/test/cases/compile_errors/unhandled_enum_value_in_switch_with_enum_declared_in_other_file.zig b/test/cases/compile_errors/unhandled_enum_value_in_switch_with_enum_declared_in_other_file.zig new file mode 100644 index 0000000000..d64127a9d5 --- /dev/null +++ b/test/cases/compile_errors/unhandled_enum_value_in_switch_with_enum_declared_in_other_file.zig @@ -0,0 +1,16 @@ +const std = @import("std"); + +pub export fn entry1() void { + const order: std.math.Order = .lt; + switch (order) {} +} + +// error +// backend=stage2 +// target=native +// +// :5:5: error: switch must handle all possibilities +// :?:?: note: unhandled enumeration value: 'lt' +// :?:?: note: unhandled enumeration value: 'eq' +// :?:?: note: unhandled enumeration value: 'gt' +// :?:?: note: enum 'math.Order' declared here From b6bda5183e44e88b53d3e51c3599d8889fb1bdb8 Mon Sep 17 00:00:00 2001 From: John Schmidt Date: Sun, 25 Sep 2022 00:30:15 +0200 Subject: [PATCH 2/2] sema: load the correct AST in failWithInvalidComptimeFieldStore The container we want to get the fields from might not be declared in the same file as the block we are analyzing, so we should get the AST from the decl's file instead. --- src/Sema.zig | 6 ++++-- test/compile_errors.zig | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index a358870656..72a5cb518f 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1868,9 +1868,11 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS errdefer msg.destroy(sema.gpa); const decl_index = container_ty.getOwnerDeclOrNull() orelse break :msg msg; - - const tree = try sema.getAstTree(block); const decl = sema.mod.declPtr(decl_index); + const tree = decl.getFileScope().getTree(sema.gpa) catch |err| { + log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); + return error.AnalysisFail; + }; const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index); const default_value_src: LazySrcLoc = .{ .node_offset_field_default = field_src.node_offset.x }; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 60de07d1e3..96df66d081 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -225,6 +225,32 @@ pub fn addCases(ctx: *TestContext) !void { }); } + { + const case = ctx.obj("invalid store to comptime field", .{}); + case.backend = .stage2; + + case.addSourceFile("a.zig", + \\pub const S = struct { + \\ comptime foo: u32 = 1, + \\ bar: u32, + \\ pub fn foo(x: @This()) void { + \\ _ = x; + \\ } + \\}; + ); + + case.addError( + \\const a = @import("a.zig"); + \\ + \\export fn entry() void { + \\ _ = a.S.foo(a.S{ .foo = 2, .bar = 2 }); + \\} + , &[_][]const u8{ + ":4:23: error: value stored in comptime field does not match the default value of the field", + ":2:25: note: default value set here", + }); + } + // TODO test this in stage2, but we won't even try in stage1 //ctx.objErrStage1("inline fn calls itself indirectly", // \\export fn foo() void {