Commit a5c6e51f03
Changed files (13)
src/codegen/llvm/bindings.zig
@@ -112,6 +112,9 @@ pub const Value = opaque {
ConstantIndices: [*]const *const Value,
NumIndices: c_uint,
) *const Value;
+
+ pub const constBitCast = LLVMConstBitCast;
+ extern fn LLVMConstBitCast(ConstantVal: *const Value, ToType: *const Type) *const Value;
};
pub const Type = opaque {
src/codegen/c.zig
@@ -283,22 +283,7 @@ pub const DeclGen = struct {
},
else => switch (t.ptrSize()) {
.Slice => unreachable,
- .Many => {
- if (val.castTag(.ref_val)) |ref_val_payload| {
- const sub_val = ref_val_payload.data;
- if (sub_val.castTag(.bytes)) |bytes_payload| {
- const bytes = bytes_payload.data;
- try writer.writeByte('(');
- try dg.renderType(writer, t);
- // TODO: make our own C string escape instead of using std.zig.fmtEscapes
- try writer.print(")\"{}\"", .{std.zig.fmtEscapes(bytes)});
- } else {
- unreachable;
- }
- } else {
- unreachable;
- }
- },
+ .Many => unreachable,
.One => {
var arena = std.heap.ArenaAllocator.init(dg.module.gpa);
defer arena.deinit();
@@ -934,10 +919,8 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
.br => try airBr(o, inst),
.switch_br => try airSwitchBr(o, inst),
.wrap_optional => try airWrapOptional(o, inst),
- .ref => try airRef(o, inst),
.struct_field_ptr => try airStructFieldPtr(o, inst),
.struct_field_val => try airStructFieldVal(o, inst),
- .varptr => try airVarPtr(o, inst),
.slice_ptr => try airSliceField(o, inst, ".ptr;\n"),
.slice_len => try airSliceField(o, inst, ".len;\n"),
@@ -996,12 +979,6 @@ fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue
return local;
}
-fn airVarPtr(o: *Object, inst: Air.Inst.Index) !CValue {
- const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
- const variable = o.air.variables[ty_pl.payload];
- return CValue{ .decl_ref = variable.owner_decl };
-}
-
fn airAlloc(o: *Object, inst: Air.Inst.Index) !CValue {
const writer = o.writer();
const inst_ty = o.air.typeOfIndex(inst);
@@ -1653,22 +1630,6 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {
return local;
}
-fn airRef(o: *Object, inst: Air.Inst.Index) !CValue {
- if (o.liveness.isUnused(inst))
- return CValue.none;
-
- const ty_op = o.air.instructions.items(.data)[inst].ty_op;
- const writer = o.writer();
- const operand = try o.resolveInst(ty_op.operand);
-
- const inst_ty = o.air.typeOfIndex(inst);
- const local = try o.allocLocal(inst_ty, .Const);
- try writer.writeAll(" = ");
- try o.writeCValue(writer, operand);
- try writer.writeAll(";\n");
- return local;
-}
-
fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
if (o.liveness.isUnused(inst))
return CValue.none;
src/codegen/llvm.zig
@@ -699,29 +699,12 @@ pub const DeclGen = struct {
.decl_ref => {
const decl = tv.val.castTag(.decl_ref).?.data;
const val = try self.resolveGlobalDecl(decl);
-
- const usize_type = try self.llvmType(Type.initTag(.usize));
-
- // TODO: second index should be the index into the memory!
- var indices: [2]*const llvm.Value = .{
- usize_type.constNull(),
- usize_type.constNull(),
- };
-
- return val.constInBoundsGEP(&indices, indices.len);
- },
- .ref_val => {
- //const elem_value = tv.val.castTag(.ref_val).?.data;
- //const elem_type = tv.ty.castPointer().?.data;
- //const alloca = fg.?.buildAlloca(try self.llvmType(elem_type));
- //_ = fg.?.builder.buildStore(try self.genTypedValue(.{ .ty = elem_type, .val = elem_value }, fg), alloca);
- //return alloca;
- // TODO eliminate the ref_val Value Tag
- return self.todo("implement const of pointer tag ref_val", .{});
+ return val.constBitCast(llvm_type);
},
.variable => {
const variable = tv.val.castTag(.variable).?.data;
- return self.resolveGlobalDecl(variable.owner_decl);
+ const val = try self.resolveGlobalDecl(variable.owner_decl);
+ return val.constBitCast(llvm_type);
},
.slice => {
const slice = tv.val.castTag(.slice).?.data;
@@ -977,7 +960,6 @@ pub const FuncGen = struct {
.ret => try self.airRet(inst),
.store => try self.airStore(inst),
.assembly => try self.airAssembly(inst),
- .varptr => try self.airVarPtr(inst),
.slice_ptr => try self.airSliceField(inst, 0),
.slice_len => try self.airSliceField(inst, 1),
@@ -1001,7 +983,6 @@ pub const FuncGen = struct {
.constant => unreachable,
.const_ty => unreachable,
- .ref => unreachable, // TODO eradicate this instruction
.unreach => self.airUnreach(inst),
.dbg_stmt => blk: {
// TODO: implement debug info
@@ -1180,16 +1161,6 @@ pub const FuncGen = struct {
return null;
}
- fn airVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
-
- const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
- const variable = self.air.variables[ty_pl.payload];
- const decl_llvm_value = self.dg.resolveGlobalDecl(variable.owner_decl);
- return decl_llvm_value;
- }
-
fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {
if (self.liveness.isUnused(inst))
return null;
src/codegen/wasm.zig
@@ -754,22 +754,21 @@ pub const Context = struct {
}
/// Generates the wasm bytecode for the declaration belonging to `Context`
- pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {
- switch (typed_value.ty.zigTypeTag()) {
+ pub fn gen(self: *Context, ty: Type, val: Value) InnerError!Result {
+ switch (ty.zigTypeTag()) {
.Fn => {
try self.genFunctype();
- if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions
+ if (val.tag() == .extern_fn) {
+ return Result.appended; // don't need code body for extern functions
+ }
return self.fail("TODO implement wasm codegen for function pointers", .{});
},
.Array => {
- if (typed_value.val.castTag(.bytes)) |payload| {
- if (typed_value.ty.sentinel()) |sentinel| {
+ if (val.castTag(.bytes)) |payload| {
+ if (ty.sentinel()) |sentinel| {
try self.code.appendSlice(payload.data);
- switch (try self.gen(.{
- .ty = typed_value.ty.elemType(),
- .val = sentinel,
- })) {
+ switch (try self.gen(ty.elemType(), sentinel)) {
.appended => return Result.appended,
.externally_managed => |data| {
try self.code.appendSlice(data);
@@ -781,13 +780,17 @@ pub const Context = struct {
} else return self.fail("TODO implement gen for more kinds of arrays", .{});
},
.Int => {
- const info = typed_value.ty.intInfo(self.target);
+ const info = ty.intInfo(self.target);
if (info.bits == 8 and info.signedness == .unsigned) {
- const int_byte = typed_value.val.toUnsignedInt();
+ const int_byte = val.toUnsignedInt();
try self.code.append(@intCast(u8, int_byte));
return Result.appended;
}
- return self.fail("TODO: Implement codegen for int type: '{}'", .{typed_value.ty});
+ return self.fail("TODO: Implement codegen for int type: '{}'", .{ty});
+ },
+ .Enum => {
+ try self.emitConstant(val, ty);
+ return Result.appended;
},
else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}),
}
@@ -969,7 +972,7 @@ pub const Context = struct {
return WValue{ .code_offset = offset };
}
- fn emitConstant(self: *Context, value: Value, ty: Type) InnerError!void {
+ fn emitConstant(self: *Context, val: Value, ty: Type) InnerError!void {
const writer = self.code.writer();
switch (ty.zigTypeTag()) {
.Int => {
@@ -982,10 +985,10 @@ pub const Context = struct {
const int_info = ty.intInfo(self.target);
// write constant
switch (int_info.signedness) {
- .signed => try leb.writeILEB128(writer, value.toSignedInt()),
+ .signed => try leb.writeILEB128(writer, val.toSignedInt()),
.unsigned => switch (int_info.bits) {
- 0...32 => try leb.writeILEB128(writer, @bitCast(i32, @intCast(u32, value.toUnsignedInt()))),
- 33...64 => try leb.writeILEB128(writer, @bitCast(i64, value.toUnsignedInt())),
+ 0...32 => try leb.writeILEB128(writer, @bitCast(i32, @intCast(u32, val.toUnsignedInt()))),
+ 33...64 => try leb.writeILEB128(writer, @bitCast(i64, val.toUnsignedInt())),
else => |bits| return self.fail("Wasm TODO: emitConstant for integer with {d} bits", .{bits}),
},
}
@@ -994,7 +997,7 @@ pub const Context = struct {
// write opcode
try writer.writeByte(wasm.opcode(.i32_const));
// write constant
- try leb.writeILEB128(writer, value.toSignedInt());
+ try leb.writeILEB128(writer, val.toSignedInt());
},
.Float => {
// write opcode
@@ -1005,13 +1008,13 @@ pub const Context = struct {
try writer.writeByte(wasm.opcode(opcode));
// write constant
switch (ty.floatBits(self.target)) {
- 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, value.toFloat(f32))),
- 64 => try writer.writeIntLittle(u64, @bitCast(u64, value.toFloat(f64))),
+ 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, val.toFloat(f32))),
+ 64 => try writer.writeIntLittle(u64, @bitCast(u64, val.toFloat(f64))),
else => |bits| return self.fail("Wasm TODO: emitConstant for float with {d} bits", .{bits}),
}
},
.Pointer => {
- if (value.castTag(.decl_ref)) |payload| {
+ if (val.castTag(.decl_ref)) |payload| {
const decl = payload.data;
// offset into the offset table within the 'data' section
@@ -1024,11 +1027,11 @@ pub const Context = struct {
try writer.writeByte(wasm.opcode(.i32_load));
try leb.writeULEB128(writer, @as(u32, 0));
try leb.writeULEB128(writer, @as(u32, 0));
- } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()});
+ } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()});
},
.Void => {},
.Enum => {
- if (value.castTag(.enum_field_index)) |field_index| {
+ if (val.castTag(.enum_field_index)) |field_index| {
switch (ty.tag()) {
.enum_simple => {
try writer.writeByte(wasm.opcode(.i32_const));
@@ -1049,20 +1052,20 @@ pub const Context = struct {
} else {
var int_tag_buffer: Type.Payload.Bits = undefined;
const int_tag_ty = ty.intTagType(&int_tag_buffer);
- try self.emitConstant(value, int_tag_ty);
+ try self.emitConstant(val, int_tag_ty);
}
},
.ErrorSet => {
- const error_index = self.global_error_set.get(value.getError().?).?;
+ const error_index = self.global_error_set.get(val.getError().?).?;
try writer.writeByte(wasm.opcode(.i32_const));
try leb.writeULEB128(writer, error_index);
},
.ErrorUnion => {
- const data = value.castTag(.error_union).?.data;
+ const data = val.castTag(.error_union).?.data;
const error_type = ty.errorUnionSet();
const payload_type = ty.errorUnionPayload();
- if (value.getError()) |_| {
- // write the error value
+ if (val.getError()) |_| {
+ // write the error val
try self.emitConstant(data, error_type);
// no payload, so write a '0' const
@@ -1085,7 +1088,7 @@ pub const Context = struct {
}
/// Returns a `Value` as a signed 32 bit value.
- /// It's illegale to provide a value with a type that cannot be represented
+ /// It's illegal to provide a value with a type that cannot be represented
/// as an integer value.
fn valueAsI32(self: Context, val: Value, ty: Type) i32 {
switch (ty.zigTypeTag()) {
src/link/Wasm.zig
@@ -275,7 +275,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
defer context.deinit();
// generate the 'code' section for the function declaration
- const result = context.gen(.{ .ty = decl.ty, .val = decl.val }) catch |err| switch (err) {
+ const result = context.gen(decl.ty, decl.val) catch |err| switch (err) {
error.CodegenFail => {
decl.analysis = .codegen_failure;
try module.failed_decls.put(module.gpa, decl, context.err_msg);
src/Air.zig
@@ -15,7 +15,6 @@ instructions: std.MultiArrayList(Inst).Slice,
/// The first few indexes are reserved. See `ExtraIndex` for the values.
extra: []const u32,
values: []const Value,
-variables: []const *Module.Var,
pub const ExtraIndex = enum(u32) {
/// Payload index of the main `Block` in the `extra` array.
@@ -193,20 +192,10 @@ pub const Inst = struct {
/// Result type is always `u1`.
/// Uses the `un_op` field.
bool_to_int,
- /// Stores a value onto the stack and returns a pointer to it.
- /// TODO audit where this AIR instruction is emitted, maybe it should instead be emitting
- /// alloca instruction and storing to the alloca.
- /// Uses the `ty_op` field.
- ref,
/// Return a value from a function.
/// Result type is always noreturn; no instructions in a block follow this one.
/// Uses the `un_op` field.
ret,
- /// Returns a pointer to a global variable.
- /// Uses the `ty_pl` field. Index is into the `variables` array.
- /// TODO this can be modeled simply as a constant with a decl ref and then
- /// the variables array can be removed from Air.
- varptr,
/// Write a value to a pointer. LHS is pointer, RHS is value.
/// Result type is always void.
/// Uses the `bin_op` field.
@@ -454,7 +443,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.assembly,
.block,
.constant,
- .varptr,
.struct_field_ptr,
.struct_field_val,
=> return air.getRefType(datas[inst].ty_pl.ty),
@@ -462,7 +450,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.not,
.bitcast,
.load,
- .ref,
.floatcast,
.intcast,
.optional_payload,
@@ -550,7 +537,6 @@ pub fn deinit(air: *Air, gpa: *std.mem.Allocator) void {
air.instructions.deinit(gpa);
gpa.free(air.extra);
gpa.free(air.values);
- gpa.free(air.variables);
air.* = undefined;
}
src/codegen.zig
@@ -848,13 +848,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.loop => try self.airLoop(inst),
.not => try self.airNot(inst),
.ptrtoint => try self.airPtrToInt(inst),
- .ref => try self.airRef(inst),
.ret => try self.airRet(inst),
.store => try self.airStore(inst),
.struct_field_ptr=> try self.airStructFieldPtr(inst),
.struct_field_val=> try self.airStructFieldVal(inst),
.switch_br => try self.airSwitch(inst),
- .varptr => try self.airVarPtr(inst),
.slice_ptr => try self.airSlicePtr(inst),
.slice_len => try self.airSliceLen(inst),
@@ -1340,13 +1338,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
- fn airVarPtr(self: *Self, inst: Air.Inst.Index) !void {
- const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
- else => return self.fail("TODO implement varptr for {}", .{self.target.cpu.arch}),
- };
- return self.finishAir(inst, result, .{ .none, .none, .none });
- }
-
fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
@@ -2833,38 +2824,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
return bt.finishAir(result);
}
- fn airRef(self: *Self, inst: Air.Inst.Index) !void {
- const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
- const operand_ty = self.air.typeOf(ty_op.operand);
- const operand = try self.resolveInst(ty_op.operand);
- switch (operand) {
- .unreach => unreachable,
- .dead => unreachable,
- .none => break :result MCValue{ .none = {} },
-
- .immediate,
- .register,
- .ptr_stack_offset,
- .ptr_embedded_in_code,
- .compare_flags_unsigned,
- .compare_flags_signed,
- => {
- const stack_offset = try self.allocMemPtr(inst);
- try self.genSetStack(operand_ty, stack_offset, operand);
- break :result MCValue{ .ptr_stack_offset = stack_offset };
- },
-
- .stack_offset => |offset| break :result MCValue{ .ptr_stack_offset = offset },
- .embedded_in_code => |offset| break :result MCValue{ .ptr_embedded_in_code = offset },
- .memory => |vaddr| break :result MCValue{ .immediate = vaddr },
-
- .undef => return self.fail("TODO implement ref on an undefined value", .{}),
- }
- };
- return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
- }
-
fn ret(self: *Self, mcv: MCValue) !void {
const ret_ty = self.fn_type.fnReturnType();
try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
src/Liveness.zig
@@ -256,14 +256,12 @@ fn analyzeInst(
.const_ty,
.breakpoint,
.dbg_stmt,
- .varptr,
.unreach,
=> return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),
.not,
.bitcast,
.load,
- .ref,
.floatcast,
.intcast,
.optional_payload,
src/Module.zig
@@ -1324,6 +1324,42 @@ pub const Scope = struct {
block.instructions.appendAssumeCapacity(result_index);
return result_index;
}
+
+ pub fn startAnonDecl(block: *Block) !WipAnonDecl {
+ return WipAnonDecl{
+ .block = block,
+ .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),
+ .finished = false,
+ };
+ }
+
+ pub const WipAnonDecl = struct {
+ block: *Scope.Block,
+ new_decl_arena: std.heap.ArenaAllocator,
+ finished: bool,
+
+ pub fn arena(wad: *WipAnonDecl) *Allocator {
+ return &wad.new_decl_arena.allocator;
+ }
+
+ pub fn deinit(wad: *WipAnonDecl) void {
+ if (!wad.finished) {
+ wad.new_decl_arena.deinit();
+ }
+ wad.* = undefined;
+ }
+
+ pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value) !*Decl {
+ const new_decl = try wad.block.sema.mod.createAnonymousDecl(&wad.block.base, .{
+ .ty = ty,
+ .val = val,
+ });
+ errdefer wad.block.sema.mod.deleteAnonDecl(&wad.block.base, new_decl);
+ try new_decl.finalizeNewArena(&wad.new_decl_arena);
+ wad.finished = true;
+ return new_decl;
+ }
+ };
};
};
@@ -1700,6 +1736,7 @@ pub const SrcLoc = struct {
.node_offset_fn_type_cc => |node_off| {
const tree = try src_loc.file_scope.getTree(gpa);
+ const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = src_loc.declRelativeToNodeIndex(node_off);
var params: [1]ast.Node.Index = undefined;
@@ -1708,6 +1745,13 @@ pub const SrcLoc = struct {
.fn_proto_multi => tree.fnProtoMulti(node),
.fn_proto_one => tree.fnProtoOne(¶ms, node),
.fn_proto => tree.fnProto(node),
+ .fn_decl => switch (node_tags[node_datas[node].lhs]) {
+ .fn_proto_simple => tree.fnProtoSimple(¶ms, node_datas[node].lhs),
+ .fn_proto_multi => tree.fnProtoMulti(node_datas[node].lhs),
+ .fn_proto_one => tree.fnProtoOne(¶ms, node_datas[node].lhs),
+ .fn_proto => tree.fnProto(node_datas[node].lhs),
+ else => unreachable,
+ },
else => unreachable,
};
const main_tokens = tree.nodes.items(.main_token);
@@ -2935,7 +2979,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
const break_index = try sema.analyzeBody(&block_scope, body);
const result_ref = zir_datas[break_index].@"break".operand;
const src: LazySrcLoc = .{ .node_offset = 0 };
- const decl_tv = try sema.resolveInstConst(&block_scope, src, result_ref);
+ const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref);
const align_val = blk: {
const align_ref = decl.zirAlignRef();
if (align_ref == .none) break :blk Value.initTag(.null_value);
@@ -3603,7 +3647,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
.instructions = sema.air_instructions.toOwnedSlice(),
.extra = sema.air_extra.toOwnedSlice(gpa),
.values = sema.air_values.toOwnedSlice(gpa),
- .variables = sema.air_variables.toOwnedSlice(gpa),
};
}
src/print_air.zig
@@ -15,12 +15,11 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {
(@sizeOf(Air.Inst.Tag) + 8);
const extra_bytes = air.extra.len * @sizeOf(u32);
const values_bytes = air.values.len * @sizeOf(Value);
- const variables_bytes = air.variables.len * @sizeOf(*Module.Var);
const tomb_bytes = liveness.tomb_bits.len * @sizeOf(usize);
const liveness_extra_bytes = liveness.extra.len * @sizeOf(u32);
const liveness_special_bytes = liveness.special.count() * 8;
const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
- values_bytes * variables_bytes + @sizeOf(Liveness) + liveness_extra_bytes +
+ values_bytes + @sizeOf(Liveness) + liveness_extra_bytes +
liveness_special_bytes + tomb_bytes;
// zig fmt: off
@@ -29,7 +28,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {
\\# AIR Instructions: {d} ({})
\\# AIR Extra Data: {d} ({})
\\# AIR Values Bytes: {d} ({})
- \\# AIR Variables Bytes: {d} ({})
\\# Liveness tomb_bits: {}
\\# Liveness Extra Data: {d} ({})
\\# Liveness special table: {d} ({})
@@ -39,7 +37,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {
air.instructions.len, fmtIntSizeBin(instruction_bytes),
air.extra.len, fmtIntSizeBin(extra_bytes),
air.values.len, fmtIntSizeBin(values_bytes),
- air.variables.len, fmtIntSizeBin(variables_bytes),
fmtIntSizeBin(tomb_bytes),
liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),
liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),
@@ -152,7 +149,6 @@ const Writer = struct {
.not,
.bitcast,
.load,
- .ref,
.floatcast,
.intcast,
.optional_payload,
@@ -174,7 +170,6 @@ const Writer = struct {
.struct_field_ptr => try w.writeStructField(s, inst),
.struct_field_val => try w.writeStructField(s, inst),
- .varptr => try w.writeVarPtr(s, inst),
.constant => try w.writeConstant(s, inst),
.assembly => try w.writeAssembly(s, inst),
.dbg_stmt => try w.writeDbgStmt(s, inst),
@@ -243,12 +238,6 @@ const Writer = struct {
try s.print(", {d}", .{extra.data.field_index});
}
- fn writeVarPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
- _ = w;
- _ = inst;
- try s.writeAll("TODO");
- }
-
fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
const val = w.air.values[ty_pl.payload];
src/Sema.zig
@@ -14,7 +14,6 @@ code: Zir,
air_instructions: std.MultiArrayList(Air.Inst) = .{},
air_extra: std.ArrayListUnmanaged(u32) = .{},
air_values: std.ArrayListUnmanaged(Value) = .{},
-air_variables: std.ArrayListUnmanaged(*Module.Var) = .{},
/// Maps ZIR to AIR.
inst_map: InstMap = .{},
/// When analyzing an inline function call, owner_decl is the Decl of the caller
@@ -76,7 +75,6 @@ pub fn deinit(sema: *Sema) void {
sema.air_instructions.deinit(gpa);
sema.air_extra.deinit(gpa);
sema.air_values.deinit(gpa);
- sema.air_variables.deinit(gpa);
sema.inst_map.deinit(gpa);
sema.decl_val_table.deinit(gpa);
sema.* = undefined;
@@ -639,16 +637,40 @@ fn analyzeAsType(
return val.toType(sema.arena);
}
+/// May return Value Tags: `variable`, `undef`.
+/// See `resolveConstValue` for an alternative.
+fn resolveValue(
+ sema: *Sema,
+ block: *Scope.Block,
+ src: LazySrcLoc,
+ air_ref: Air.Inst.Ref,
+) CompileError!Value {
+ if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
+ return val;
+ }
+ return sema.failWithNeededComptime(block, src);
+}
+
+/// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors.
+/// See `resolveValue` for an alternative.
fn resolveConstValue(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
air_ref: Air.Inst.Ref,
) CompileError!Value {
- return (try sema.resolveDefinedValue(block, src, air_ref)) orelse
- return sema.failWithNeededComptime(block, src);
+ if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
+ switch (val.tag()) {
+ .undef => return sema.failWithUseOfUndef(block, src),
+ .variable => return sema.failWithNeededComptime(block, src),
+ else => return val,
+ }
+ }
+ return sema.failWithNeededComptime(block, src);
}
+/// Value Tag `variable` causes this function to return `null`.
+/// Value Tag `undef` causes this function to return a compile error.
fn resolveDefinedValue(
sema: *Sema,
block: *Scope.Block,
@@ -664,11 +686,27 @@ fn resolveDefinedValue(
return null;
}
+/// Value Tag `variable` causes this function to return `null`.
+/// Value Tag `undef` causes this function to return the Value.
fn resolveMaybeUndefVal(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
inst: Air.Inst.Ref,
+) CompileError!?Value {
+ const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null;
+ if (val.tag() == .variable) {
+ return sema.failWithNeededComptime(block, src);
+ }
+ return val;
+}
+
+/// Returns all Value tags including `variable` and `undef`.
+fn resolveMaybeUndefValAllowVariables(
+ sema: *Sema,
+ block: *Scope.Block,
+ src: LazySrcLoc,
+ inst: Air.Inst.Ref,
) CompileError!?Value {
// First section of indexes correspond to a set number of constant values.
var i: usize = @enumToInt(inst);
@@ -734,6 +772,8 @@ fn resolveInt(
return val.toUnsignedInt();
}
+// Returns a compile error if the value has tag `variable`. See `resolveInstValue` for
+// a function that does not.
pub fn resolveInstConst(
sema: *Sema,
block: *Scope.Block,
@@ -748,6 +788,22 @@ pub fn resolveInstConst(
};
}
+// Value Tag may be `undef` or `variable`.
+// See `resolveInstConst` for an alternative.
+pub fn resolveInstValue(
+ sema: *Sema,
+ block: *Scope.Block,
+ src: LazySrcLoc,
+ zir_ref: Zir.Inst.Ref,
+) CompileError!TypedValue {
+ const air_ref = sema.resolveInst(zir_ref);
+ const val = try sema.resolveValue(block, src, air_ref);
+ return TypedValue{
+ .ty = sema.typeOf(air_ref),
+ .val = val,
+ };
+}
+
fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
@@ -1707,7 +1763,7 @@ fn zirStr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A
});
errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);
try new_decl.finalizeNewArena(&new_decl_arena);
- return sema.analyzeDeclRef(block, .unneeded, new_decl);
+ return sema.analyzeDeclRef(new_decl);
}
fn zirInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -2090,10 +2146,7 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro
const linkage_index = struct_obj.fields.getIndex("linkage").?;
const section_index = struct_obj.fields.getIndex("section").?;
const export_name = try fields[name_index].toAllocatedBytes(sema.arena);
- const linkage = fields[linkage_index].toEnum(
- struct_obj.fields.values()[linkage_index].ty,
- std.builtin.GlobalLinkage,
- );
+ const linkage = fields[linkage_index].toEnum(std.builtin.GlobalLinkage);
if (linkage != .Strong) {
return sema.mod.fail(&block.base, src, "TODO: implement exporting with non-strong linkage", .{});
@@ -2194,7 +2247,7 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
const src = inst_data.src();
const decl_name = inst_data.get(sema.code);
const decl = try sema.lookupIdentifier(block, src, decl_name);
- return sema.analyzeDeclRef(block, src, decl);
+ return sema.analyzeDeclRef(decl);
}
fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -2978,14 +3031,9 @@ fn zirErrUnionPayloadPtr(
if (val.getError()) |name| {
return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
}
- const data = val.castTag(.error_union).?.data;
- // The same Value represents the pointer to the error union and the payload.
return sema.addConstant(
operand_pointer_ty,
- try Value.Tag.ref_val.create(
- sema.arena,
- data,
- ),
+ try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val),
);
}
@@ -6296,7 +6344,7 @@ fn zirFuncExtended(
const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref);
- break :blk cc_tv.val.toEnum(cc_tv.ty, std.builtin.CallingConvention);
+ break :blk cc_tv.val.toEnum(std.builtin.CallingConvention);
} else .Unspecified;
const align_val: Value = if (small.has_align) blk: {
@@ -6554,7 +6602,7 @@ fn safetyPanic(
});
errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);
try new_decl.finalizeNewArena(&new_decl_arena);
- break :msg_inst try sema.analyzeDeclRef(block, .unneeded, new_decl);
+ break :msg_inst try sema.analyzeDeclRef(new_decl);
};
const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src);
@@ -6761,11 +6809,16 @@ fn fieldPtr(
switch (object_ty.zigTypeTag()) {
.Array => {
if (mem.eql(u8, field_name, "len")) {
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
return sema.addConstant(
Type.initTag(.single_const_pointer_to_comptime_int),
- try Value.Tag.ref_val.create(
+ try Value.Tag.decl_ref.create(
arena,
- try Value.Tag.int_u64.create(arena, object_ty.arrayLen()),
+ try anon_decl.finish(
+ Type.initTag(.comptime_int),
+ try Value.Tag.int_u64.create(anon_decl.arena(), object_ty.arrayLen()),
+ ),
),
);
} else {
@@ -6780,18 +6833,25 @@ fn fieldPtr(
.Pointer => {
const ptr_child = object_ty.elemType();
if (ptr_child.isSlice()) {
+ // Here for the ptr and len fields what we need to do is the situation
+ // when a temporary has its address taken, e.g. `&a[c..d].len`.
+ // This value may be known at compile-time or runtime. In the former
+ // case, it should create an anonymous Decl and return a decl_ref to it.
+ // In the latter case, it should add an `alloc` instruction, store
+ // the runtime value to it, and then return the `alloc`.
+ // In both cases the pointer should be const.
if (mem.eql(u8, field_name, "ptr")) {
return mod.fail(
&block.base,
field_name_src,
- "cannot obtain reference to pointer field of slice '{}'",
+ "TODO: implement reference to 'ptr' field of slice '{}'",
.{object_ty},
);
} else if (mem.eql(u8, field_name, "len")) {
return mod.fail(
&block.base,
field_name_src,
- "cannot obtain reference to length field of slice '{}'",
+ "TODO: implement reference to 'len' field of slice '{}'",
.{object_ty},
);
} else {
@@ -6805,11 +6865,16 @@ fn fieldPtr(
} else switch (ptr_child.zigTypeTag()) {
.Array => {
if (mem.eql(u8, field_name, "len")) {
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
return sema.addConstant(
Type.initTag(.single_const_pointer_to_comptime_int),
- try Value.Tag.ref_val.create(
+ try Value.Tag.decl_ref.create(
arena,
- try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),
+ try anon_decl.finish(
+ Type.initTag(.comptime_int),
+ try Value.Tag.int_u64.create(anon_decl.arena(), ptr_child.arrayLen()),
+ ),
),
);
} else {
@@ -6848,13 +6913,16 @@ fn fieldPtr(
});
} else (try mod.getErrorValue(field_name)).key;
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
return sema.addConstant(
try Module.simplePtrType(arena, child_type, false, .One),
- try Value.Tag.ref_val.create(
+ try Value.Tag.decl_ref.create(
arena,
- try Value.Tag.@"error".create(arena, .{
- .name = name,
- }),
+ try anon_decl.finish(
+ child_type,
+ try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),
+ ),
),
);
},
@@ -6901,10 +6969,17 @@ fn fieldPtr(
return mod.failWithOwnedErrorMsg(&block.base, msg);
};
const field_index_u32 = @intCast(u32, field_index);
- const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32);
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
return sema.addConstant(
try Module.simplePtrType(arena, child_type, false, .One),
- try Value.Tag.ref_val.create(arena, enum_val),
+ try Value.Tag.decl_ref.create(
+ arena,
+ try anon_decl.finish(
+ child_type,
+ try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
+ ),
+ ),
);
},
else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
@@ -6951,7 +7026,7 @@ fn namespaceLookupRef(
decl_name: []const u8,
) CompileError!?Air.Inst.Ref {
const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
- return try sema.analyzeDeclRef(block, src, decl);
+ return try sema.analyzeDeclRef(decl);
}
fn structFieldPtr(
@@ -7207,13 +7282,15 @@ fn elemPtrArray(
fn coerce(
sema: *Sema,
block: *Scope.Block,
- dest_type: Type,
+ dest_type_unresolved: Type,
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
- if (dest_type.tag() == .var_args_param) {
+ if (dest_type_unresolved.tag() == .var_args_param) {
return sema.coerceVarArgParam(block, inst, inst_src);
}
+ const dest_type_src = inst_src; // TODO better source location
+ const dest_type = try sema.resolveTypeFields(block, dest_type_src, dest_type_unresolved);
const inst_ty = sema.typeOf(inst);
// If the types are the same, we can return the operand.
@@ -7554,17 +7631,17 @@ fn analyzeDeclVal(
if (sema.decl_val_table.get(decl)) |result| {
return result;
}
- const decl_ref = try sema.analyzeDeclRef(block, src, decl);
+ const decl_ref = try sema.analyzeDeclRef(decl);
const result = try sema.analyzeLoad(block, src, decl_ref, src);
if (Air.refToIndex(result)) |index| {
if (sema.air_instructions.items(.tag)[index] == .constant) {
- sema.decl_val_table.put(sema.gpa, decl, result) catch {};
+ try sema.decl_val_table.put(sema.gpa, decl, result);
}
}
return result;
}
-fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) CompileError!Air.Inst.Ref {
+fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref {
try sema.mod.declareDeclDependency(sema.owner_decl, decl);
sema.mod.ensureDeclAnalyzed(decl) catch |err| {
if (sema.func) |func| {
@@ -7576,8 +7653,10 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
};
const decl_tv = try decl.typedValue();
- if (decl_tv.val.tag() == .variable) {
- return sema.analyzeVarRef(block, src, decl_tv);
+ if (decl_tv.val.castTag(.variable)) |payload| {
+ const variable = payload.data;
+ const ty = try Module.simplePtrType(sema.arena, decl_tv.ty, variable.is_mutable, .One);
+ return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl));
}
return sema.addConstant(
try Module.simplePtrType(sema.arena, decl_tv.ty, false, .One),
@@ -7585,26 +7664,6 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
);
}
-fn analyzeVarRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, tv: TypedValue) CompileError!Air.Inst.Ref {
- const variable = tv.val.castTag(.variable).?.data;
-
- const ty = try Module.simplePtrType(sema.arena, tv.ty, variable.is_mutable, .One);
- if (!variable.is_mutable and !variable.is_extern) {
- return sema.addConstant(ty, try Value.Tag.ref_val.create(sema.arena, variable.init));
- }
-
- const gpa = sema.gpa;
- try sema.requireRuntimeBlock(block, src);
- try sema.air_variables.append(gpa, variable);
- return block.addInst(.{
- .tag = .varptr,
- .data = .{ .ty_pl = .{
- .ty = try sema.addType(ty),
- .payload = @intCast(u32, sema.air_variables.items.len - 1),
- } },
- });
-}
-
fn analyzeRef(
sema: *Sema,
block: *Scope.Block,
@@ -7615,11 +7674,21 @@ fn analyzeRef(
const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One);
if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
- return sema.addConstant(ptr_type, try Value.Tag.ref_val.create(sema.arena, val));
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
+ return sema.addConstant(
+ ptr_type,
+ try Value.Tag.decl_ref.create(
+ sema.arena,
+ try anon_decl.finish(operand_ty, try val.copy(anon_decl.arena())),
+ ),
+ );
}
try sema.requireRuntimeBlock(block, src);
- return block.addTyOp(.ref, ptr_type, operand);
+ const alloc = try block.addTy(.alloc, ptr_type);
+ try sema.storePtr(block, src, alloc, operand);
+ return alloc;
}
fn analyzeLoad(
@@ -8447,12 +8516,12 @@ fn getTmpAir(sema: Sema) Air {
.instructions = sema.air_instructions.slice(),
.extra = sema.air_extra.items,
.values = sema.air_values.items,
- .variables = sema.air_variables.items,
};
}
pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
switch (ty.tag()) {
+ .u1 => return .u1_type,
.u8 => return .u8_type,
.i8 => return .i8_type,
.u16 => return .u16_type,
src/value.zig
@@ -100,8 +100,6 @@ pub const Value = extern union {
function,
extern_fn,
variable,
- /// Represents a pointer to another immutable value.
- ref_val,
/// Represents a comptime variables storage.
comptime_alloc,
/// Represents a pointer to a decl, not the value of the decl.
@@ -126,6 +124,8 @@ pub const Value = extern union {
enum_field_index,
@"error",
error_union,
+ /// A pointer to the payload of an error union, based on a pointer to an error union.
+ eu_payload_ptr,
/// An instance of a struct.
@"struct",
/// An instance of a union.
@@ -214,9 +214,9 @@ pub const Value = extern union {
.decl_ref,
=> Payload.Decl,
- .ref_val,
.repeated,
.error_union,
+ .eu_payload_ptr,
=> Payload.SubValue,
.bytes,
@@ -407,15 +407,6 @@ pub const Value = extern union {
.function => return self.copyPayloadShallow(allocator, Payload.Function),
.extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl),
.variable => return self.copyPayloadShallow(allocator, Payload.Variable),
- .ref_val => {
- const payload = self.castTag(.ref_val).?;
- const new_payload = try allocator.create(Payload.SubValue);
- new_payload.* = .{
- .base = payload.base,
- .data = try payload.data.copy(allocator),
- };
- return Value{ .ptr_otherwise = &new_payload.base };
- },
.comptime_alloc => return self.copyPayloadShallow(allocator, Payload.ComptimeAlloc),
.decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl),
.elem_ptr => {
@@ -443,8 +434,8 @@ pub const Value = extern union {
return Value{ .ptr_otherwise = &new_payload.base };
},
.bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
- .repeated => {
- const payload = self.castTag(.repeated).?;
+ .repeated, .error_union, .eu_payload_ptr => {
+ const payload = self.cast(Payload.SubValue).?;
const new_payload = try allocator.create(Payload.SubValue);
new_payload.* = .{
.base = payload.base,
@@ -489,15 +480,6 @@ pub const Value = extern union {
},
.enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),
.@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
- .error_union => {
- const payload = self.castTag(.error_union).?;
- const new_payload = try allocator.create(Payload.SubValue);
- new_payload.* = .{
- .base = payload.base,
- .data = try payload.data.copy(allocator),
- };
- return Value{ .ptr_otherwise = &new_payload.base };
- },
.@"struct" => @panic("TODO can't copy struct value without knowing the type"),
.@"union" => @panic("TODO can't copy union value without knowing the type"),
@@ -609,11 +591,6 @@ pub const Value = extern union {
.function => return out_stream.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}),
.extern_fn => return out_stream.writeAll("(extern function)"),
.variable => return out_stream.writeAll("(variable)"),
- .ref_val => {
- const ref_val = val.castTag(.ref_val).?.data;
- try out_stream.writeAll("&const ");
- val = ref_val;
- },
.comptime_alloc => {
const ref_val = val.castTag(.comptime_alloc).?.data.val;
try out_stream.writeAll("&");
@@ -648,6 +625,10 @@ pub const Value = extern union {
// TODO to print this it should be error{ Set, Items }!T(val), but we need the type for that
.error_union => return out_stream.print("error_union_val({})", .{val.castTag(.error_union).?.data}),
.inferred_alloc => return out_stream.writeAll("(inferred allocation value)"),
+ .eu_payload_ptr => {
+ try out_stream.writeAll("(eu_payload_ptr)");
+ val = val.castTag(.eu_payload_ptr).?.data;
+ },
};
}
@@ -758,7 +739,6 @@ pub const Value = extern union {
.function,
.extern_fn,
.variable,
- .ref_val,
.comptime_alloc,
.decl_ref,
.elem_ptr,
@@ -780,18 +760,21 @@ pub const Value = extern union {
.@"union",
.inferred_alloc,
.abi_align_default,
+ .eu_payload_ptr,
=> unreachable,
};
}
/// Asserts the type is an enum type.
- pub fn toEnum(val: Value, enum_ty: Type, comptime E: type) E {
- _ = enum_ty;
- // TODO this needs to resolve other kinds of Value tags rather than
- // assuming the tag will be .enum_field_index.
- const field_index = val.castTag(.enum_field_index).?.data;
- // TODO should `@intToEnum` do this `@intCast` for you?
- return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));
+ pub fn toEnum(val: Value, comptime E: type) E {
+ switch (val.tag()) {
+ .enum_field_index => {
+ const field_index = val.castTag(.enum_field_index).?.data;
+ // TODO should `@intToEnum` do this `@intCast` for you?
+ return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));
+ },
+ else => unreachable,
+ }
}
/// Asserts the value is an integer.
@@ -1255,6 +1238,9 @@ pub const Value = extern union {
.slice => {
@panic("TODO Value.hash for slice");
},
+ .eu_payload_ptr => {
+ @panic("TODO Value.hash for eu_payload_ptr");
+ },
.int_u64 => {
const payload = self.castTag(.int_u64).?;
std.hash.autoHash(&hasher, payload.data);
@@ -1263,10 +1249,6 @@ pub const Value = extern union {
const payload = self.castTag(.int_i64).?;
std.hash.autoHash(&hasher, payload.data);
},
- .ref_val => {
- const payload = self.castTag(.ref_val).?;
- std.hash.autoHash(&hasher, payload.data.hash());
- },
.comptime_alloc => {
const payload = self.castTag(.comptime_alloc).?;
std.hash.autoHash(&hasher, payload.data.val.hash());
@@ -1367,7 +1349,6 @@ pub const Value = extern union {
pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {
return switch (self.tag()) {
.comptime_alloc => self.castTag(.comptime_alloc).?.data.val,
- .ref_val => self.castTag(.ref_val).?.data,
.decl_ref => self.castTag(.decl_ref).?.data.value(),
.elem_ptr => {
const elem_ptr = self.castTag(.elem_ptr).?.data;
@@ -1379,6 +1360,11 @@ pub const Value = extern union {
const container_val = try field_ptr.container_ptr.pointerDeref(allocator);
return container_val.fieldValue(allocator, field_ptr.field_index);
},
+ .eu_payload_ptr => {
+ const err_union_ptr = self.castTag(.eu_payload_ptr).?.data;
+ const err_union_val = try err_union_ptr.pointerDeref(allocator);
+ return err_union_val.castTag(.error_union).?.data;
+ },
else => unreachable,
};
@@ -1390,7 +1376,6 @@ pub const Value = extern union {
.bytes => val.castTag(.bytes).?.data.len,
.array => val.castTag(.array).?.data.len,
.slice => val.castTag(.slice).?.data.len.toUnsignedInt(),
- .ref_val => sliceLen(val.castTag(.ref_val).?.data),
.decl_ref => {
const decl = val.castTag(.decl_ref).?.data;
if (decl.ty.zigTypeTag() == .Array) {
@@ -1576,7 +1561,6 @@ pub const Value = extern union {
.int_i64,
.int_big_positive,
.int_big_negative,
- .ref_val,
.comptime_alloc,
.decl_ref,
.elem_ptr,
@@ -1599,6 +1583,7 @@ pub const Value = extern union {
.@"union",
.null_value,
.abi_align_default,
+ .eu_payload_ptr,
=> false,
.undef => unreachable,
test/cases.zig
@@ -1182,10 +1182,11 @@ pub fn addCases(ctx: *TestContext) !void {
var case = ctx.obj("extern variable has no type", linux_x64);
case.addError(
\\comptime {
- \\ _ = foo;
+ \\ const x = foo + foo;
+ \\ _ = x;
\\}
\\extern var foo: i32;
- , &[_][]const u8{":2:9: error: unable to resolve comptime value"});
+ , &[_][]const u8{":2:15: error: unable to resolve comptime value"});
case.addError(
\\export fn entry() void {
\\ _ = foo;