Commit 13b917148e

Robin Voetter <robin@voetter.nl>
2021-09-01 17:33:45
Address Spaces: basic system to check for validity.
Validity checks are also based on context; whether the entity being validated is a mutable/constant value, a pointer (that is ascripted with an addrspace attribute) or a function with an addrspace attribute. Error messages are relatively simple for now.
1 parent 90a945b
Changed files (2)
src/Module.zig
@@ -3213,11 +3213,18 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
         break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val;
     };
     const address_space = blk: {
-        const addrspace_ref = decl.zirAddrspaceRef();
-        if (addrspace_ref == .none) break :blk .generic;
-        const addrspace_tv = try sema.resolveInstConst(&block_scope, src, addrspace_ref);
-        break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace);
+        const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) {
+            .function, .extern_fn => .function,
+            .variable => .variable,
+            else => .constant,
+        };
+
+        break :blk switch (decl.zirAddrspaceRef()) {
+            .none => .generic,
+            else => |addrspace_ref| try sema.analyzeAddrspace(&block_scope, src, addrspace_ref, addrspace_ctx),
+        };
     };
+
     // Note this resolves the type of the Decl, not the value; if this Decl
     // is a struct, for example, this resolves `type` (which needs no resolution),
     // not the struct itself.
src/Sema.zig
@@ -6932,8 +6932,7 @@ fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
     const address_space = if (inst_data.flags.has_addrspace) blk: {
         const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
         extra_i += 1;
-        const addrspace_tv = try sema.resolveInstConst(block, .unneeded, ref);
-        break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace);
+        break :blk try sema.analyzeAddrspace(block, .unneeded, ref, .pointer);
     } else .generic;
 
     const bit_start = if (inst_data.flags.has_bit_range) blk: {
@@ -8092,8 +8091,7 @@ fn zirFuncExtended(
     const address_space: std.builtin.AddressSpace = if (small.has_addrspace) blk: {
         const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
         extra_index += 1;
-        const addrspace_tv = try sema.resolveInstConst(block, addrspace_src, addrspace_ref);
-        break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace);
+        break :blk try sema.analyzeAddrspace(block, addrspace_src, addrspace_ref, .function);
     } else .generic;
 
     const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
@@ -10973,3 +10971,58 @@ fn analyzeComptimeAlloc(
         .decl = decl,
     }));
 }
+
+/// The places where a user can specify an address space attribute
+pub const AddressSpaceContext = enum {
+    /// A function is specificed to be placed in a certain address space.
+    function,
+
+    /// A (global) variable is specified to be placed in a certain address space.
+    /// In contrast to .constant, these values (and thus the address space they will be
+    /// placed in) are required to be mutable.
+    variable,
+
+    /// A (global) constant value is specified to be placed in a certain address space.
+    /// In contrast to .variable, values placed in this address space are not required to be mutable.
+    constant,
+
+    /// A pointer is ascripted to point into a certian address space.
+    pointer,
+};
+
+pub fn analyzeAddrspace(
+    sema: *Sema,
+    block: *Scope.Block,
+    src: LazySrcLoc,
+    zir_ref: Zir.Inst.Ref,
+    ctx: AddressSpaceContext,
+) !std.builtin.AddressSpace {
+    const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref);
+    const address_space = addrspace_tv.val.toEnum(std.builtin.AddressSpace);
+    const target = sema.mod.getTarget();
+    const arch = target.cpu.arch;
+
+    const supported = switch (address_space) {
+        .generic => true,
+        .gs, .fs, .ss => (arch == .i386 or arch == .x86_64) and ctx == .pointer,
+    };
+
+    if (!supported) {
+        // TODO error messages could be made more elaborate here
+        const entity = switch (ctx) {
+            .function => "functions",
+            .variable => "mutable values",
+            .constant => "constant values",
+            .pointer => "pointers",
+        };
+
+        return sema.mod.fail(
+            &block.base,
+            src,
+            "{s} with address space '{s}' are not supported on {s}",
+            .{ entity, @tagName(address_space), arch.genericName() },
+        );
+    }
+
+    return address_space;
+}