Commit 9f14681473

Robin Voetter <robin@voetter.nl>
2022-08-27 12:55:28
stage2: check address space cast validity
1 parent 5d429b0
Changed files (3)
lib/std/target.zig
@@ -1157,6 +1157,17 @@ pub const Target = struct {
                 };
             }
 
+            /// Returns whether this architecture supporst the address space
+            pub fn supportsAddressSpace(arch: Arch, address_space: std.builtin.AddressSpace) bool {
+                const is_nvptx = arch == .nvptx or arch == .nvptx64;
+                return switch (address_space) {
+                    .generic => true,
+                    .fs, .gs, .ss => arch == .x86_64 or arch == .i386,
+                    .global, .constant, .local, .shared => arch == .amdgcn or is_nvptx,
+                    .param => is_nvptx,
+                };
+            }
+
             pub fn ptrBitWidth(arch: Arch) u16 {
                 switch (arch) {
                     .avr,
src/Sema.zig
@@ -18181,13 +18181,21 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
     const ptr = try sema.resolveInst(extra.rhs);
     const ptr_ty = sema.typeOf(ptr);
 
+
     // TODO in addition to pointers, this instruction is supposed to work for
     // pointer-like optionals and slices.
     try sema.checkPtrOperand(block, ptr_src, ptr_ty);
 
-    // TODO check address space cast validity.
     const src_addrspace = ptr_ty.ptrAddressSpace();
-    _ = src_addrspace;
+    if (!target_util.addrSpaceCastIsValid(sema.mod.getTarget(), src_addrspace, dest_addrspace)) {
+        const msg = msg: {
+            const msg = try sema.errMsg(block, src, "invalid address space cast", .{});
+            errdefer msg.destroy(sema.gpa);
+            try sema.errNote(block, src, msg, "address space '{s}' is not compatible with address space '{s}'", .{ @tagName(src_addrspace), @tagName(dest_addrspace) });
+            break :msg msg;
+        };
+        return sema.failWithOwnedErrorMsg(msg);
+    }
 
     const ptr_info = ptr_ty.ptrInfo().data;
     const dest_ty = try Type.ptr(sema.arena, sema.mod, .{
src/target.zig
@@ -1,5 +1,6 @@
 const std = @import("std");
 const Type = @import("type.zig").Type;
+const AddressSpace = std.builtin.AddressSpace;
 
 pub const ArchOsAbi = struct {
     arch: std.Target.Cpu.Arch,
@@ -635,12 +636,30 @@ pub fn defaultAddressSpace(
         /// Query the default address space for functions themselves.
         function,
     },
-) std.builtin.AddressSpace {
+) AddressSpace {
     _ = target;
     _ = context;
     return .generic;
 }
 
+/// Returns true if pointers in `from` can be converted to a pointer in `to`.
+pub fn addrSpaceCastIsValid(
+    target: std.Target,
+    from: AddressSpace,
+    to: AddressSpace,
+) bool {
+    const arch = target.cpu.arch;
+    switch (arch) {
+        .x86_64, .i386 => return arch.supportsAddressSpace(from) and arch.supportsAddressSpace(to),
+        .amdgcn => {
+            const to_generic = arch.supportsAddressSpace(from) and to == .generic;
+            const from_generic = arch.supportsAddressSpace(to) and from == .generic;
+            return to_generic or from_generic;
+        },
+        else => return from == .generic and to == .generic,
+    }
+}
+
 pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {
     const have_float = switch (target.abi) {
         .gnuilp32 => return "ilp32",