Commit b5d3db5fc6

mlugg <mlugg@mlugg.co.uk>
2024-12-15 12:07:22
Sema: do not allow coercing undefined to opaque types
1 parent af89bb0
Changed files (1)
src/Sema.zig
@@ -30675,6 +30675,18 @@ fn coerceExtra(
         else => {},
     }
 
+    const can_coerce_to = switch (dest_ty.zigTypeTag(zcu)) {
+        .noreturn, .@"opaque" => false,
+        else => true,
+    };
+
+    if (can_coerce_to) {
+        // undefined to anything. We do this after the big switch above so that
+        // special logic has a chance to run first, such as `*[N]T` to `[]T` which
+        // should initialize the length field of the slice.
+        if (maybe_inst_val) |val| if (val.toIntern() == .undef) return pt.undefRef(dest_ty);
+    }
+
     if (!opts.report_err) return error.NotCoercible;
 
     if (opts.is_ret and dest_ty.zigTypeTag(zcu) == .noreturn) {
@@ -30692,15 +30704,14 @@ fn coerceExtra(
         return sema.failWithOwnedErrorMsg(block, msg);
     }
 
-    // undefined to anything. We do this after the big switch above so that
-    // special logic has a chance to run first, such as `*[N]T` to `[]T` which
-    // should initialize the length field of the slice.
-    if (maybe_inst_val) |val| if (val.toIntern() == .undef) return pt.undefRef(dest_ty);
-
     const msg = msg: {
         const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt) });
         errdefer msg.destroy(sema.gpa);
 
+        if (!can_coerce_to) {
+            try sema.errNote(inst_src, msg, "cannot coerce to '{}'", .{dest_ty.fmt(pt)});
+        }
+
         // E!T to T
         if (inst_ty.zigTypeTag(zcu) == .error_union and
             (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(zcu), dest_ty, false, target, dest_ty_src, inst_src, maybe_inst_val)) == .ok)