Commit 6b2ce9d1e9
Changed files (8)
test
stage2
src-self-hosted/astgen.zig
@@ -311,7 +311,7 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si
const src = tree.token_locs[node.rtoken].start;
const operand = try expr(mod, scope, .lvalue, node.lhs);
- const unwrapped_ptr = try addZIRInst(mod, scope, src, zir.Inst.UnwrapOptional, .{ .operand = operand }, .{});
+ const unwrapped_ptr = try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand);
if (rl == .lvalue) return unwrapped_ptr;
return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));
src-self-hosted/codegen.zig
@@ -668,7 +668,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.store => return self.genStore(inst.castTag(.store).?),
.sub => return self.genSub(inst.castTag(.sub).?),
.unreach => return MCValue{ .unreach = {} },
- .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
+ .unwrap_optional_safe => return self.genUnwrapOptional(inst.castTag(.unwrap_optional_safe).?, true),
+ .unwrap_optional_unsafe => return self.genUnwrapOptional(inst.castTag(.unwrap_optional_unsafe).?, false),
}
}
@@ -818,7 +819,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}
}
- fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnwrapOptional) !MCValue {
+ fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnOp, safety_check: bool) !MCValue {
// No side effects, so if it's unreferenced, do nothing.
if (inst.base.isUnused())
return MCValue.dead;
src-self-hosted/ir.zig
@@ -82,7 +82,8 @@ pub const Inst = struct {
not,
floatcast,
intcast,
- unwrap_optional,
+ unwrap_optional_safe,
+ unwrap_optional_unsafe,
pub fn Type(tag: Tag) type {
return switch (tag) {
@@ -103,6 +104,8 @@ pub const Inst = struct {
.floatcast,
.intcast,
.load,
+ .unwrap_optional_safe,
+ .unwrap_optional_unsafe,
=> UnOp,
.add,
@@ -125,7 +128,6 @@ pub const Inst = struct {
.condbr => CondBr,
.constant => Constant,
.loop => Loop,
- .unwrap_optional => UnwrapOptional,
};
}
@@ -421,27 +423,6 @@ pub const Inst = struct {
return null;
}
};
-
- pub const UnwrapOptional = struct {
- pub const base_tag = Tag.unwrap_optional;
- base: Inst,
-
- operand: *Inst,
- safety_check: bool,
-
- pub fn operandCount(self: *const UnwrapOptional) usize {
- return 1;
- }
- pub fn getOperand(self: *const UnwrapOptional, index: usize) ?*Inst {
- var i = index;
-
- if (i < 1)
- return self.operand;
- i -= 1;
-
- return null;
- }
- };
};
pub const Body = struct {
src-self-hosted/Module.zig
@@ -2016,28 +2016,6 @@ pub fn addCall(
return &inst.base;
}
-pub fn addUnwrapOptional(
- self: *Module,
- block: *Scope.Block,
- src: usize,
- ty: Type,
- operand: *Inst,
- safety_check: bool,
-) !*Inst {
- const inst = try block.arena.create(Inst.UnwrapOptional);
- inst.* = .{
- .base = .{
- .tag = .unwrap_optional,
- .ty = ty,
- .src = src,
- },
- .operand = operand,
- .safety_check = safety_check,
- };
- try block.instructions.append(self.gpa, &inst.base);
- return &inst.base;
-}
-
pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {
const const_inst = try scope.arena().create(Inst.Constant);
const_inst.* = .{
@@ -2500,7 +2478,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
// null to ?T
if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) {
- return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = inst.ty.onePossibleValue().? });
+ return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
}
// T to ?T
src-self-hosted/type.zig
@@ -185,8 +185,6 @@ pub const Type = extern union {
return true;
},
.Optional => {
- if (a.tag() != b.tag())
- return false;
return a.elemType().eql(b.elemType());
},
.Float,
@@ -662,6 +660,10 @@ pub const Type = extern union {
.optional => {
const child_type = self.cast(Payload.Optional).?.child_type;
if (!child_type.hasCodeGenBits()) return 1;
+
+ if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
+ return @divExact(target.cpu.arch.ptrBitWidth(), 8);
+
return child_type.abiAlignment(target);
},
@@ -750,6 +752,10 @@ pub const Type = extern union {
.optional => {
const child_type = self.cast(Payload.Optional).?.child_type;
if (!child_type.hasCodeGenBits()) return 1;
+
+ if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
+ return @divExact(target.cpu.arch.ptrBitWidth(), 8);
+
// Optional types are represented as a struct with the child type as the first
// field and a boolean as the second. Since the child type's abi alignment is
// guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
src-self-hosted/zir.zig
@@ -215,7 +215,9 @@ pub const Inst = struct {
/// Create an optional type '?T'
optional_type,
/// Unwraps an optional value 'lhs.?'
- unwrap_optional,
+ unwrap_optional_safe,
+ /// Same as previous, but without safety checks. Used for orelse, if and while
+ unwrap_optional_unsafe,
pub fn Type(tag: Tag) type {
return switch (tag) {
@@ -245,6 +247,8 @@ pub const Inst = struct {
.single_const_ptr_type,
.single_mut_ptr_type,
.optional_type,
+ .unwrap_optional_safe,
+ .unwrap_optional_unsafe,
=> UnOp,
.add,
@@ -303,7 +307,6 @@ pub const Inst = struct {
.fntype => FnType,
.elemptr => ElemPtr,
.condbr => CondBr,
- .unwrap_optional => UnwrapOptional,
};
}
@@ -379,7 +382,8 @@ pub const Inst = struct {
.typeof,
.xor,
.optional_type,
- .unwrap_optional,
+ .unwrap_optional_safe,
+ .unwrap_optional_unsafe,
=> false,
.@"break",
@@ -820,18 +824,6 @@ pub const Inst = struct {
},
kw_args: struct {},
};
-
- pub const UnwrapOptional = struct {
- pub const base_tag = Tag.unwrap_optional;
- base: Inst,
-
- positionals: struct {
- operand: *Inst,
- },
- kw_args: struct {
- safety_check: bool = true,
- },
- };
};
pub const ErrorMsg = struct {
@@ -1935,6 +1927,8 @@ const EmitZIR = struct {
.isnonnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnonnull).?, .isnonnull),
.load => try self.emitUnOp(inst.src, new_body, inst.castTag(.load).?, .deref),
.ref => try self.emitUnOp(inst.src, new_body, inst.castTag(.ref).?, .ref),
+ .unwrap_optional_safe => try self.emitUnOp(inst.src, new_body, inst.castTag(.unwrap_optional_safe).?, .unwrap_optional_safe),
+ .unwrap_optional_unsafe => try self.emitUnOp(inst.src, new_body, inst.castTag(.unwrap_optional_unsafe).?, .unwrap_optional_unsafe),
.add => try self.emitBinOp(inst.src, new_body, inst.castTag(.add).?, .add),
.sub => try self.emitBinOp(inst.src, new_body, inst.castTag(.sub).?, .sub),
@@ -2157,25 +2151,6 @@ const EmitZIR = struct {
};
break :blk &new_inst.base;
},
-
- .unwrap_optional => blk: {
- const old_inst = inst.castTag(.unwrap_optional).?;
-
- const new_inst = try self.arena.allocator.create(Inst.UnwrapOptional);
- new_inst.* = .{
- .base = .{
- .src = inst.src,
- .tag = Inst.UnwrapOptional.base_tag,
- },
- .positionals = .{
- .operand = try self.resolveInst(new_body, old_inst.operand),
- },
- .kw_args = .{
- .safety_check = old_inst.safety_check,
- },
- };
- break :blk &new_inst.base;
- },
};
try instructions.append(new_inst);
try inst_table.put(inst, new_inst);
src-self-hosted/zir_sema.zig
@@ -107,7 +107,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
.boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?),
.typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?),
.optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?),
- .unwrap_optional => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional).?),
+ .unwrap_optional_safe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_safe).?, true),
+ .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),
}
}
@@ -661,7 +662,7 @@ fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp
}));
}
-fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnwrapOptional) InnerError!*Inst {
+fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {
const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
assert(operand.ty.zigTypeTag() == .Pointer);
@@ -686,7 +687,10 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.Unwr
}
const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);
- return mod.addUnwrapOptional(b, unwrap.base.src, child_pointer, operand, unwrap.kw_args.safety_check);
+ return if (safety_check)
+ mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional_safe, operand)
+ else
+ mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional_unsafe, operand);
}
fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
test/stage2/compare_output.zig
@@ -31,11 +31,6 @@ pub fn addCases(ctx: *TestContext) !void {
\\export fn _start() noreturn {
\\ print();
\\
- \\ const a: u32 = 2;
- \\ const b: ?u32 = a;
- \\ const c = b.?;
- \\ if (c != 2) unreachable;
- \\
\\ exit();
\\}
\\
@@ -446,5 +441,29 @@ pub fn addCases(ctx: *TestContext) !void {
,
"",
);
+
+ // Optionals
+ case.addCompareOutput(
+ \\export fn _start() noreturn {
+ \\ const a: u32 = 2;
+ \\ const b: ?u32 = a;
+ \\ const c = b.?;
+ \\ if (c != 2) unreachable;
+ \\
+ \\ exit();
+ \\}
+ \\
+ \\fn exit() noreturn {
+ \\ asm volatile ("syscall"
+ \\ :
+ \\ : [number] "{rax}" (231),
+ \\ [arg1] "{rdi}" (0)
+ \\ : "rcx", "r11", "memory"
+ \\ );
+ \\ unreachable;
+ \\}
+ ,
+ "",
+ );
}
}