Commit aa78ebaf95
Changed files (8)
src
test
cases
compile_errors
src/Sema.zig
@@ -26629,21 +26629,41 @@ fn resolveStructLayout(
switch (struct_obj.status) {
.none, .have_field_types => {},
.field_types_wip, .layout_wip => {
- return sema.fail(block, src, "struct '{}' depends on itself", .{ty.fmt(sema.mod)});
+ const msg = try Module.ErrorMsg.create(
+ sema.gpa,
+ struct_obj.srcLoc(sema.mod),
+ "struct '{}' depends on itself",
+ .{ty.fmt(sema.mod)},
+ );
+ return sema.failWithOwnedErrorMsg(msg);
},
.have_layout, .fully_resolved_wip, .fully_resolved => return,
}
struct_obj.status = .layout_wip;
- for (struct_obj.fields.values()) |field| {
- try sema.resolveTypeLayout(block, src, field.ty);
+ for (struct_obj.fields.values()) |field, i| {
+ 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", .{});
+ return err;
+ },
+ else => return err,
+ };
}
struct_obj.status = .have_layout;
// In case of querying the ABI alignment of this struct, we will ask
// for hasRuntimeBits() of each field, so we need "requires comptime"
// to be known already before this function returns.
- for (struct_obj.fields.values()) |field| {
- _ = try sema.typeRequiresComptime(block, src, field.ty);
+ for (struct_obj.fields.values()) |field, i| {
+ _ = sema.typeRequiresComptime(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", .{});
+ return err;
+ },
+ else => return err,
+ };
}
}
// otherwise it's a tuple; no need to resolve anything
@@ -26660,13 +26680,26 @@ fn resolveUnionLayout(
switch (union_obj.status) {
.none, .have_field_types => {},
.field_types_wip, .layout_wip => {
- return sema.fail(block, src, "union '{}' depends on itself", .{ty.fmt(sema.mod)});
+ const msg = try Module.ErrorMsg.create(
+ sema.gpa,
+ union_obj.srcLoc(sema.mod),
+ "union '{}' depends on itself",
+ .{ty.fmt(sema.mod)},
+ );
+ return sema.failWithOwnedErrorMsg(msg);
},
.have_layout, .fully_resolved_wip, .fully_resolved => return,
}
union_obj.status = .layout_wip;
- for (union_obj.fields.values()) |field| {
- try sema.resolveTypeLayout(block, src, field.ty);
+ for (union_obj.fields.values()) |field, i| {
+ 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", .{});
+ return err;
+ },
+ else => return err,
+ };
}
union_obj.status = .have_layout;
}
@@ -26794,12 +26827,12 @@ pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type)
switch (ty.tag()) {
.@"struct" => {
const struct_obj = ty.castTag(.@"struct").?.data;
- try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
+ try sema.resolveTypeFieldsStruct(ty, struct_obj);
return ty;
},
.@"union", .union_safety_tagged, .union_tagged => {
const union_obj = ty.cast(Type.Payload.Union).?.data;
- try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
+ try sema.resolveTypeFieldsUnion(ty, union_obj);
return ty;
},
.type_info => return sema.resolveBuiltinTypeFields(block, src, "Type"),
@@ -26820,15 +26853,19 @@ pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type)
fn resolveTypeFieldsStruct(
sema: *Sema,
- block: *Block,
- src: LazySrcLoc,
ty: Type,
struct_obj: *Module.Struct,
) CompileError!void {
switch (struct_obj.status) {
.none => {},
.field_types_wip => {
- return sema.fail(block, src, "struct '{}' depends on itself", .{ty.fmt(sema.mod)});
+ const msg = try Module.ErrorMsg.create(
+ sema.gpa,
+ struct_obj.srcLoc(sema.mod),
+ "struct '{}' depends on itself",
+ .{ty.fmt(sema.mod)},
+ );
+ return sema.failWithOwnedErrorMsg(msg);
},
.have_field_types,
.have_layout,
@@ -26842,17 +26879,17 @@ fn resolveTypeFieldsStruct(
try semaStructFields(sema.mod, struct_obj);
}
-fn resolveTypeFieldsUnion(
- sema: *Sema,
- block: *Block,
- src: LazySrcLoc,
- ty: Type,
- union_obj: *Module.Union,
-) CompileError!void {
+fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_obj: *Module.Union) CompileError!void {
switch (union_obj.status) {
.none => {},
.field_types_wip => {
- return sema.fail(block, src, "union '{}' depends on itself", .{ty.fmt(sema.mod)});
+ const msg = try Module.ErrorMsg.create(
+ sema.gpa,
+ union_obj.srcLoc(sema.mod),
+ "union '{}' depends on itself",
+ .{ty.fmt(sema.mod)},
+ );
+ return sema.failWithOwnedErrorMsg(msg);
},
.have_field_types,
.have_layout,
@@ -27786,9 +27823,19 @@ pub fn typeHasOnePossibleValue(
.@"struct" => {
const resolved_ty = try sema.resolveTypeFields(block, src, ty);
const s = resolved_ty.castTag(.@"struct").?.data;
- for (s.fields.values()) |value| {
- if (value.is_comptime) continue;
- if ((try sema.typeHasOnePossibleValue(block, src, value.ty)) == null) {
+ for (s.fields.values()) |field, i| {
+ if (field.is_comptime) continue;
+ if (field.ty.eql(resolved_ty, sema.mod)) {
+ const msg = try Module.ErrorMsg.create(
+ sema.gpa,
+ s.srcLoc(sema.mod),
+ "struct '{}' depends on itself",
+ .{ty.fmt(sema.mod)},
+ );
+ try sema.addFieldErrNote(block, resolved_ty, i, msg, "while checking this field", .{});
+ return sema.failWithOwnedErrorMsg(msg);
+ }
+ if ((try sema.typeHasOnePossibleValue(block, src, field.ty)) == null) {
return null;
}
}
@@ -27854,6 +27901,16 @@ pub fn typeHasOnePossibleValue(
const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
return null;
const only_field = union_obj.fields.values()[0];
+ if (only_field.ty.eql(resolved_ty, sema.mod)) {
+ const msg = try Module.ErrorMsg.create(
+ sema.gpa,
+ union_obj.srcLoc(sema.mod),
+ "union '{}' depends on itself",
+ .{ty.fmt(sema.mod)},
+ );
+ try sema.addFieldErrNote(block, resolved_ty, 0, msg, "while checking this field", .{});
+ return sema.failWithOwnedErrorMsg(msg);
+ }
const val_val = (try sema.typeHasOnePossibleValue(block, src, only_field.ty)) orelse
return null;
// TODO make this not allocate. The function in `Type.onePossibleValue`
@@ -28493,7 +28550,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
if (struct_obj.status == .field_types_wip)
return false;
- try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
+ try sema.resolveTypeFieldsStruct(ty, struct_obj);
struct_obj.requires_comptime = .wip;
for (struct_obj.fields.values()) |field| {
@@ -28518,7 +28575,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
if (union_obj.status == .field_types_wip)
return false;
- try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
+ try sema.resolveTypeFieldsUnion(ty, union_obj);
union_obj.requires_comptime = .wip;
for (union_obj.fields.values()) |field| {
test/cases/compile_errors/stage1/obj/direct_struct_loop.zig
@@ -1,8 +0,0 @@
-const A = struct { a : A, };
-export fn entry() usize { return @sizeOf(A); }
-
-// error
-// backend=stage1
-// target=native
-//
-// tmp.zig:1:11: error: struct 'A' depends on itself
test/cases/compile_errors/stage1/obj/indirect_struct_loop.zig
@@ -1,10 +0,0 @@
-const A = struct { b : B, };
-const B = struct { c : C, };
-const C = struct { a : A, };
-export fn entry() usize { return @sizeOf(A); }
-
-// error
-// backend=stage1
-// target=native
-//
-// tmp.zig:1:11: error: struct 'A' depends on itself
test/cases/compile_errors/direct_struct_loop.zig
@@ -0,0 +1,9 @@
+const A = struct { a : A, };
+export fn entry() usize { return @sizeOf(A); }
+
+// error
+// backend=stage2
+// target=native
+//
+// :1:11: error: struct 'tmp.A' depends on itself
+// :1:20: note: while checking this field
test/cases/compile_errors/indirect_struct_loop.zig
@@ -0,0 +1,13 @@
+const A = struct { b : B, };
+const B = struct { c : C, };
+const C = struct { a : A, };
+export fn entry() usize { return @sizeOf(A); }
+
+// error
+// backend=stage2
+// target=native
+//
+// :1:11: error: struct 'tmp.A' depends on itself
+// :3:20: note: while checking this field
+// :2:20: note: while checking this field
+// :1:20: note: while checking this field
test/cases/compile_errors/stage1/obj/instantiating_an_undefined_value_for_an_invalid_struct_that_contains_itself.zig → test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_struct_that_contains_itself.zig
@@ -9,7 +9,8 @@ export fn entry() usize {
}
// error
-// backend=stage1
+// backend=stage2
// target=native
//
-// tmp.zig:1:13: error: struct 'Foo' depends on itself
+// :1:13: error: struct 'tmp.Foo' depends on itself
+// :2:5: note: while checking this field
test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_union_that_contains_itself.zig
@@ -0,0 +1,16 @@
+const Foo = union {
+ x: Foo,
+};
+
+var foo: Foo = undefined;
+
+export fn entry() usize {
+ return @sizeOf(@TypeOf(foo.x));
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :1:13: error: union 'tmp.Foo' depends on itself
+// :2:5: note: while checking this field
test/cases/compile_errors/stage1/obj/struct_depends_on_itself_via_optional_field.zig → test/cases/compile_errors/struct_depends_on_itself_via_optional_field.zig
@@ -11,9 +11,9 @@ export fn entry() void {
}
// error
-// backend=stage1
+// backend=stage2
// target=native
//
-// tmp.zig:1:17: error: struct 'LhsExpr' depends on itself
-// tmp.zig:5:5: note: while checking this field
-// tmp.zig:2:5: note: while checking this field
+// :1:17: error: struct 'tmp.LhsExpr' depends on itself
+// :5:5: note: while checking this field
+// :2:5: note: while checking this field