Commit a6bf8c2593

Veikka Tuominen <git@vexu.eu>
2022-06-30 21:57:20
Sema: add more validation to zirFieldParentPtr
1 parent e6ebf56
src/Sema.zig
@@ -8378,19 +8378,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
                             block,
                             src,
                             msg,
-                            "unhandled error value: error.{s}",
+                            "unhandled error value: 'error.{s}'",
                             .{error_name},
                         );
                     }
                 }
 
                 if (maybe_msg) |msg| {
-                    try sema.mod.errNoteNonLazy(
-                        operand_ty.declSrcLoc(sema.mod),
-                        msg,
-                        "error set '{}' declared here",
-                        .{operand_ty.fmt(sema.mod)},
-                    );
+                    maybe_msg = null;
+                    try sema.addDeclaredHereNote(msg, operand_ty);
                     return sema.failWithOwnedErrorMsg(block, msg);
                 }
 
@@ -17143,9 +17139,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
     const field_index = struct_obj.fields.getIndex(field_name) orelse
         return sema.failWithBadStructFieldAccess(block, struct_obj, name_src, field_name);
 
-    if (field_ptr_ty.zigTypeTag() != .Pointer) {
-        return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{field_ptr_ty.fmt(sema.mod)});
-    }
+    try sema.checkPtrOperand(block, ptr_src, field_ptr_ty);
     const field = struct_obj.fields.values()[field_index];
     const field_ptr_ty_info = field_ptr_ty.ptrInfo().data;
 
@@ -17168,8 +17162,29 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
     const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
 
     if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
-        const payload = field_ptr_val.castTag(.field_ptr).?.data;
-        return sema.addConstant(result_ptr, payload.container_ptr);
+        const payload = field_ptr_val.castTag(.field_ptr) orelse {
+            return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{});
+        };
+        if (payload.data.field_index != field_index) {
+            const msg = msg: {
+                const msg = try sema.errMsg(
+                    block,
+                    src,
+                    "field '{s}' has index '{d}' but pointer value is index '{d}' of struct '{}'",
+                    .{
+                        field_name,
+                        field_index,
+                        payload.data.field_index,
+                        struct_ty.fmt(sema.mod),
+                    },
+                );
+                errdefer msg.destroy(sema.gpa);
+                try sema.addDeclaredHereNote(msg, struct_ty);
+                break :msg msg;
+            };
+            return sema.failWithOwnedErrorMsg(block, msg);
+        }
+        return sema.addConstant(result_ptr, payload.data.container_ptr);
     }
 
     try sema.requireRuntimeBlock(block, src);
@@ -18515,7 +18530,16 @@ fn fieldVal(
                         kw_name, child_type.fmt(sema.mod), field_name,
                     });
                 },
-                else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)}),
+                else => {
+                    const msg = msg: {
+                        const msg = try sema.errMsg(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)});
+                        errdefer msg.destroy(sema.gpa);
+                        if (child_type.isSlice()) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{});
+                        if (child_type.zigTypeTag() == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{});
+                        break :msg msg;
+                    };
+                    return sema.failWithOwnedErrorMsg(block, msg);
+                },
             }
         },
         .Struct => if (is_pointer_to) {
@@ -18739,7 +18763,7 @@ fn fieldPtr(
         },
         else => {},
     }
-    return sema.fail(block, src, "type '{}' does not support field access (fieldPtr, {}.{s})", .{ object_ty.fmt(sema.mod), object_ptr_ty.fmt(sema.mod), field_name });
+    return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
 }
 
 fn fieldCallBind(
test/cases/compile_errors/stage1/obj/error_equality_but_sets_have_no_common_members.zig → test/cases/compile_errors/stage1/error_equality_but_sets_have_no_common_members.zig
File renamed without changes
test/cases/compile_errors/stage1/obj/division_by_zero.zig → test/cases/compile_errors/division_by_zero.zig
@@ -6,13 +6,12 @@ const float_x = @as(f32, 1.0) / @as(f32, 0.0);
 export fn entry1() usize { return @sizeOf(@TypeOf(lit_int_x)); }
 export fn entry2() usize { return @sizeOf(@TypeOf(lit_float_x)); }
 export fn entry3() usize { return @sizeOf(@TypeOf(int_x)); }
-export fn entry4() usize { return @sizeOf(@TypeOf(float_x)); }
+export fn entry4() usize { return @sizeOf(@TypeOf(float_x)); } // no error on purpose
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:1:21: error: division by zero
-// tmp.zig:2:25: error: division by zero
-// tmp.zig:3:27: error: division by zero
-// tmp.zig:4:31: error: division by zero
+// :1:23: error: division by zero here causes undefined behavior
+// :2:27: error: division by zero here causes undefined behavior
+// :3:29: error: division by zero here causes undefined behavior
test/cases/compile_errors/stage1/obj/error_not_handled_in_switch.zig → test/cases/compile_errors/error_not_handled_in_switch.zig
@@ -13,8 +13,9 @@ fn foo(x: i32) !void {
 }
 
 // error
-// backend=stage1
+// backend=llvm
 // target=native
 //
-// tmp.zig:2:26: error: error.Baz not handled in switch
-// tmp.zig:2:26: error: error.Bar not handled in switch
+// :2:26: error: switch must handle all possibilities
+// :2:26: note: unhandled error value: 'error.Bar'
+// :2:26: note: unhandled error value: 'error.Baz'
test/cases/compile_errors/stage1/obj/field_access_of_opaque_type.zig → test/cases/compile_errors/field_access_of_opaque_type.zig
@@ -10,7 +10,7 @@ fn bar(x: *MyType) bool {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:9:13: error: no member named 'blah' in opaque type 'MyType'
+// :9:13: error: type '*tmp.MyType' does not support field access
test/cases/compile_errors/stage1/obj/field_access_of_slices.zig → test/cases/compile_errors/field_access_of_slices.zig
@@ -5,7 +5,8 @@ export fn entry() void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:3:32: error: type 'type' does not support field access
+// :3:32: error: type '[]i32' has no members
+// :3:32: note: slice values have 'len' and 'ptr' members
test/cases/compile_errors/stage1/obj/field_access_of_unknown_length_pointer.zig → test/cases/compile_errors/field_access_of_unknown_length_pointer.zig
@@ -7,7 +7,7 @@ export fn entry(foo: [*]Foo) void {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:6:8: error: type '[*]Foo' does not support field access
+// :6:8: error: type '[*]tmp.Foo' does not support field access
test/cases/compile_errors/stage1/obj/fieldParentPtr-comptime_field_ptr_not_based_on_struct.zig → test/cases/compile_errors/fieldParentPtr-comptime_field_ptr_not_based_on_struct.zig
@@ -11,7 +11,7 @@ comptime {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:9:55: error: pointer value not based on parent struct
+// :9:55: error: pointer value not based on parent struct
test/cases/compile_errors/stage1/obj/fieldParentPtr-comptime_wrong_field_index.zig → test/cases/compile_errors/fieldParentPtr-comptime_wrong_field_index.zig
@@ -10,7 +10,8 @@ comptime {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:8:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'
+// :8:29: error: field 'b' has index '1' but pointer value is index '0' of struct 'tmp.Foo'
+// :1:13: note: struct declared here
test/cases/compile_errors/stage1/obj/fieldParentPtr-field_pointer_is_not_pointer.zig → test/cases/compile_errors/fieldParentPtr-field_pointer_is_not_pointer.zig
@@ -6,7 +6,7 @@ export fn foo(a: i32) *Foo {
 }
 
 // error
-// backend=stage1
+// backend=stage2
 // target=native
 //
-// tmp.zig:5:38: error: expected pointer, found 'i32'
+// :5:38: error: expected pointer type, found 'i32'