Commit d7314555f2

Veikka Tuominen <git@vexu.eu>
2022-10-28 15:37:02
Sema: improve compile error for casting double pointer to anyopaque pointer
Closes #12042
1 parent 9607bd9
lib/std/meta.zig
@@ -302,7 +302,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type {
                             .Array = .{
                                 .len = array_info.len,
                                 .child = array_info.child,
-                                .sentinel = &sentinel_val,
+                                .sentinel = @ptrCast(?*const anyopaque, &sentinel_val),
                             },
                         }),
                         .is_allowzero = info.is_allowzero,
@@ -320,7 +320,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type {
                     .address_space = info.address_space,
                     .child = info.child,
                     .is_allowzero = info.is_allowzero,
-                    .sentinel = &sentinel_val,
+                    .sentinel = @ptrCast(?*const anyopaque, &sentinel_val),
                 },
             }),
             else => {},
@@ -338,7 +338,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type {
                                 .address_space = ptr_info.address_space,
                                 .child = ptr_info.child,
                                 .is_allowzero = ptr_info.is_allowzero,
-                                .sentinel = &sentinel_val,
+                                .sentinel = @ptrCast(?*const anyopaque, &sentinel_val),
                             },
                         }),
                     },
lib/std/start_windows_tls.zig
@@ -42,7 +42,7 @@ export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{
     .StartAddressOfRawData = &_tls_start,
     .EndAddressOfRawData = &_tls_end,
     .AddressOfIndex = &_tls_index,
-    .AddressOfCallBacks = &__xl_a,
+    .AddressOfCallBacks = @ptrCast(*anyopaque, &__xl_a),
     .SizeOfZeroFill = 0,
     .Characteristics = 0,
 };
src/Sema.zig
@@ -23928,9 +23928,20 @@ fn coerceExtra(
             // cast from ?*T and ?[*]T to ?*anyopaque
             // but don't do it if the source type is a double pointer
             if (dest_ty.isPtrLikeOptional() and dest_ty.elemType2().tag() == .anyopaque and
-                inst_ty.isPtrLikeOptional() and inst_ty.elemType2().zigTypeTag() != .Pointer)
-            {
+                inst_ty.isPtrAtRuntime())
+            anyopaque_check: {
                 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;
+                const elem_ty = inst_ty.elemType2(); 
+                if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) {
+                    in_memory_result = .{ .double_ptr_to_anyopaque = .{
+                        .actual = inst_ty,
+                        .wanted = dest_ty,
+                    } };
+                    break :optional;
+                }
+                // Let the logic below handle wrapping the optional now that
+                // it has been checked to correctly coerce.
+                if (!inst_ty.isPtrLikeOptional()) break: anyopaque_check;
                 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
             }
 
@@ -24053,9 +24064,16 @@ fn coerceExtra(
 
             // cast from *T and [*]T to *anyopaque
             // but don't do it if the source type is a double pointer
-            if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer and
-                inst_ty.childType().zigTypeTag() != .Pointer and sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
-            {
+            if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer) {
+                if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
+                const elem_ty = inst_ty.elemType2(); 
+                if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) {
+                    in_memory_result = .{ .double_ptr_to_anyopaque = .{
+                        .actual = inst_ty,
+                        .wanted = dest_ty,
+                    } };
+                    break :pointer;
+                }
                 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
             }
 
@@ -24537,6 +24555,7 @@ const InMemoryCoercionResult = union(enum) {
     ptr_allowzero: Pair,
     ptr_bit_range: BitRange,
     ptr_alignment: IntPair,
+    double_ptr_to_anyopaque: Pair,
 
     const Pair = struct {
         actual: Type,
@@ -24829,6 +24848,12 @@ const InMemoryCoercionResult = union(enum) {
                 });
                 break;
             },
+            .double_ptr_to_anyopaque => |pair| {
+                try sema.errNote(block, src, msg, "cannot implicitly cast double pointer '{}' to anyopaque pointer '{}'", .{
+                    pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+                });
+                break;
+            },
         };
     }
 };
src/type.zig
@@ -3941,10 +3941,7 @@ pub const Type = extern union {
             .optional => {
                 var buf: Payload.ElemType = undefined;
                 const child_type = self.optionalChild(&buf);
-                // optionals of zero sized pointers behave like bools
-                if (!child_type.hasRuntimeBits()) return false;
                 if (child_type.zigTypeTag() != .Pointer) return false;
-
                 const info = child_type.ptrInfo().data;
                 switch (info.size) {
                     .Slice, .C => return false,
test/cases/compile_errors/dont_implicit_cast_double_pointer_to_anyopaque.zig
@@ -1,14 +0,0 @@
-export fn entry() void {
-    var a: u32 = 1;
-    var ptr: *align(@alignOf(u32)) anyopaque = &a;
-    var b: *u32 = @ptrCast(*u32, ptr);
-    var ptr2: *anyopaque = &b;
-    _ = ptr2;
-}
-
-// error
-// backend=stage2
-// target=native
-//
-// :5:28: error: expected type '*anyopaque', found '**u32'
-// :5:28: note: pointer type child '*u32' cannot cast into pointer type child 'anyopaque'
test/cases/compile_errors/double_pointer_to_anyopaque_pointer.zig
@@ -0,0 +1,28 @@
+pub export fn entry1() void {
+    const x: usize = 5;
+
+    const ptr: *const anyopaque = &(&x);
+    _ = ptr;
+}
+pub export fn entry2() void {
+    var val: [*:0]u8 = undefined;
+    func(&val);
+}
+fn func(_: ?*anyopaque) void {}
+pub export fn entry3() void {
+    var x: *?*usize = undefined;
+
+    const ptr: *const anyopaque = x;
+    _ = ptr;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :4:35: error: expected type '*const anyopaque', found '*const *const usize'
+// :4:35: note: cannot implicitly cast double pointer '*const *const usize' to anyopaque pointer '*const anyopaque'
+// :9:10: error: expected type '?*anyopaque', found '*[*:0]u8'
+// :9:10: note: cannot implicitly cast double pointer '*[*:0]u8' to anyopaque pointer '?*anyopaque'
+// :15:35: error: expected type '*const anyopaque', found '*?*usize'
+// :15:35: note: cannot implicitly cast double pointer '*?*usize' to anyopaque pointer '*const anyopaque'