change unreachable{} to @unreachable()

instead of a container init expression, it's a builtin
function call.
This commit is contained in:
Andrew Kelley 2016-09-13 16:46:27 -04:00
parent ea2f6594ce
commit 06f2f4d64b
13 changed files with 89 additions and 81 deletions

View File

@ -1174,6 +1174,7 @@ enum BuiltinFnId {
BuiltinFnIdDivExact,
BuiltinFnIdTruncate,
BuiltinFnIdIntType,
BuiltinFnIdUnreachable,
};
struct BuiltinFnEntry {

View File

@ -2677,13 +2677,6 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
} else {
return resolve_expr_const_val_as_void(g, node);
}
} else if (container_type->id == TypeTableEntryIdUnreachable) {
if (container_init_expr->entries.length != 0) {
add_node_error(g, node, buf_sprintf("unreachable expression expects no arguments"));
return g->builtin_types.entry_invalid;
} else {
return container_type;
}
} else {
add_node_error(g, node,
buf_sprintf("type '%s' does not support %s initialization syntax",
@ -5435,6 +5428,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
return analyze_compile_err(g, import, context, node);
case BuiltinFnIdIntType:
return analyze_int_type(g, import, context, node);
case BuiltinFnIdUnreachable:
return g->builtin_types.entry_unreachable;
}
zig_unreachable();
}

View File

@ -497,6 +497,20 @@ static LLVMValueRef gen_truncate(CodeGen *g, AstNode *node) {
return LLVMBuildTrunc(g->builder, src_val, dest_type->type_ref, "");
}
static LLVMValueRef gen_unreachable(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr);
set_debug_source_node(g, node);
if (want_debug_safety(g, node) || g->is_test_build) {
gen_debug_safety_crash(g);
} else {
LLVMBuildUnreachable(g->builder);
}
return nullptr;
}
static LLVMValueRef gen_shl_with_overflow(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr);
@ -689,6 +703,8 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
return gen_div_exact(g, node);
case BuiltinFnIdTruncate:
return gen_truncate(g, node);
case BuiltinFnIdUnreachable:
return gen_unreachable(g, node);
}
zig_unreachable();
}
@ -2949,15 +2965,6 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
}
return tmp_struct_ptr;
} else if (type_entry->id == TypeTableEntryIdUnreachable) {
assert(node->data.container_init_expr.entries.length == 0);
set_debug_source_node(g, node);
if (want_debug_safety(g, node) || g->is_test_build) {
gen_debug_safety_crash(g);
} else {
LLVMBuildUnreachable(g->builder);
}
return nullptr;
} else if (type_entry->id == TypeTableEntryIdVoid) {
assert(node->data.container_init_expr.entries.length == 0);
return nullptr;
@ -4859,6 +4866,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn_with_arg_count(g, BuiltinFnIdTruncate, "truncate", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdCompileErr, "compileError", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdIntType, "intType", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdUnreachable, "unreachable", 0);
}
static void init(CodeGen *g, Buf *source_path) {

View File

@ -491,13 +491,6 @@ static bool eval_container_init_expr(EvalFn *ef, AstNode *node, ConstExprValue *
}
} else if (container_type->id == TypeTableEntryIdVoid) {
return false;
} else if (container_type->id == TypeTableEntryIdUnreachable) {
ef->root->abort = true;
ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node,
buf_sprintf("function evaluation reached unreachable expression"));
add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here"));
add_error_note(ef->root->codegen, msg, node, buf_sprintf("unreachable expression here"));
return true;
} else if (container_type->id == TypeTableEntryIdStruct &&
container_type->data.structure.is_slice &&
kind == ContainerInitKindArray)
@ -791,6 +784,15 @@ static bool eval_div_exact(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
return false;
}
static bool eval_unreachable(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
ef->root->abort = true;
ErrorMsg *msg = add_node_error(ef->root->codegen, ef->root->fn->fn_def_node,
buf_sprintf("function evaluation reached unreachable expression"));
add_error_note(ef->root->codegen, msg, ef->root->call_node, buf_sprintf("called from here"));
add_error_note(ef->root->codegen, msg, node, buf_sprintf("unreachable expression here"));
return true;
}
static bool eval_fn_with_overflow(EvalFn *ef, AstNode *node, ConstExprValue *out_val,
bool (*bignum_fn)(BigNum *dest, BigNum *op1, BigNum *op2))
{
@ -851,6 +853,8 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_
return false;
case BuiltinFnIdDivExact:
return eval_div_exact(ef, node, out_val);
case BuiltinFnIdUnreachable:
return eval_unreachable(ef, node, out_val);
case BuiltinFnIdMemcpy:
case BuiltinFnIdMemset:
case BuiltinFnIdSizeof:

View File

@ -266,5 +266,5 @@ fn test_one_udivmoddi4(a: du_int, b: du_int, expected_q: du_int, expected_r: du_
}
fn assert(b: bool) {
if (!b) unreachable{};
if (!b) @unreachable();
}

View File

@ -9,7 +9,7 @@ pub error InvalidDebugInfo;
pub error UnsupportedDebugInfo;
pub fn assert(b: bool) {
if (!b) unreachable{}
if (!b) @unreachable()
}
pub fn printStackTrace() -> %void {

View File

@ -55,7 +55,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
return entry;
}
}
unreachable{} // no next item
@unreachable() // no next item
}
}
@ -137,9 +137,9 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
entry.distance_from_start_index -= 1;
entry = next_entry;
}
unreachable{} // shifting everything in the table
@unreachable() // shifting everything in the table
}}
unreachable{} // key not found
@unreachable() // key not found
}
pub fn entryIterator(hm: &Self) -> Iterator {
@ -210,7 +210,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
};
return;
}
unreachable{} // put into a full map
@unreachable() // put into a full map
}
fn internalGet(hm: &Self, key: K) -> ?&Entry {

View File

@ -116,7 +116,7 @@ pub struct OutStream {
return switch (write_err) {
errno.EINTR => continue,
errno.EINVAL => unreachable{},
errno.EINVAL => @unreachable(),
errno.EDQUOT => error.DiskQuota,
errno.EFBIG => error.FileTooBig,
errno.EIO => error.Io,
@ -165,8 +165,8 @@ pub struct InStream {
return switch (err) {
errno.EINTR => continue,
errno.EFAULT => unreachable{},
errno.EINVAL => unreachable{},
errno.EFAULT => @unreachable(),
errno.EINVAL => @unreachable(),
errno.EACCES => error.BadPerm,
errno.EFBIG, errno.EOVERFLOW => error.FileTooBig,
errno.EISDIR => error.IsDir,
@ -228,8 +228,8 @@ pub struct InStream {
switch (read_err) {
errno.EINTR => continue,
errno.EINVAL => unreachable{},
errno.EFAULT => unreachable{},
errno.EINVAL => @unreachable(),
errno.EFAULT => @unreachable(),
errno.EBADF => return error.BadFd,
errno.EIO => return error.Io,
else => return error.Unexpected,
@ -426,9 +426,9 @@ fn bufPrintUnsigned(inline T: type, out_buf: []u8, x: T) -> usize {
fn parseU64DigitTooBig() {
parseUnsigned(u64, "123a", 10) %% |err| {
if (err == error.InvalidChar) return;
unreachable{};
@unreachable();
};
unreachable{};
@unreachable();
}
pub fn openSelfExe(stream: &InStream) -> %void {

View File

@ -299,7 +299,7 @@ pub fn lseek(fd: i32, offset: usize, ref_pos: usize) -> usize {
pub fn exit(status: i32) -> unreachable {
arch.syscall1(arch.SYS_exit, usize(status));
unreachable{}
@unreachable()
}
pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize {

View File

@ -21,8 +21,8 @@ struct Connection {
const send_err = linux.getErrno(send_ret);
switch (send_err) {
0 => return send_ret,
errno.EINVAL => unreachable{},
errno.EFAULT => unreachable{},
errno.EINVAL => @unreachable(),
errno.EFAULT => @unreachable(),
errno.ECONNRESET => return error.ConnectionReset,
errno.EINTR => return error.SigInterrupt,
// TODO there are more possible errors
@ -35,8 +35,8 @@ struct Connection {
const recv_err = linux.getErrno(recv_ret);
switch (recv_err) {
0 => return buf[0...recv_ret],
errno.EINVAL => unreachable{},
errno.EFAULT => unreachable{},
errno.EINVAL => @unreachable(),
errno.EFAULT => @unreachable(),
errno.ENOTSOCK => return error.NotSocket,
errno.EINTR => return error.SigInterrupt,
errno.ENOMEM => return error.NoMem,
@ -50,7 +50,7 @@ struct Connection {
pub fn close(c: Connection) -> %void {
switch (linux.getErrno(linux.close(c.socket_fd))) {
0 => return,
errno.EBADF => unreachable{},
errno.EBADF => @unreachable(),
errno.EINTR => return error.SigInterrupt,
errno.EIO => return error.Io,
else => return error.Unexpected,
@ -74,7 +74,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address {
// if (family != AF_INET)
// buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
//
unreachable{} // TODO
@unreachable() // TODO
}
switch (parseIpLiteral(hostname)) {
@ -85,7 +85,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address {
else => {},
};
unreachable{} // TODO
@unreachable() // TODO
}
pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
@ -113,7 +113,7 @@ pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
@memcpy(&os_addr.addr[0], &addr.addr[0], 16);
linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6))
} else {
unreachable{}
@unreachable()
};
const connect_err = linux.getErrno(connect_ret);
if (connect_err > 0) {
@ -321,11 +321,11 @@ fn parseIp4(buf: []const u8) -> %u32 {
#attribute("test")
fn testParseIp4() {
assert(%%parseIp4("127.0.0.1") == endian.swapIfLe(u32, 0x7f000001));
switch (parseIp4("256.0.0.1")) { Overflow => {}, else => unreachable {}, }
switch (parseIp4("x.0.0.1")) { InvalidChar => {}, else => unreachable {}, }
switch (parseIp4("127.0.0.1.1")) { JunkAtEnd => {}, else => unreachable {}, }
switch (parseIp4("127.0.0.")) { Incomplete => {}, else => unreachable {}, }
switch (parseIp4("100..0.1")) { InvalidChar => {}, else => unreachable {}, }
switch (parseIp4("256.0.0.1")) { Overflow => {}, else => @unreachable(), }
switch (parseIp4("x.0.0.1")) { InvalidChar => {}, else => @unreachable(), }
switch (parseIp4("127.0.0.1.1")) { JunkAtEnd => {}, else => @unreachable(), }
switch (parseIp4("127.0.0.")) { Incomplete => {}, else => @unreachable(), }
switch (parseIp4("100..0.1")) { InvalidChar => {}, else => @unreachable(), }
}
#attribute("test")

View File

@ -11,8 +11,8 @@ pub fn getRandomBytes(buf: []u8) -> %void {
const err = linux.getErrno(ret);
if (err > 0) {
return switch (err) {
errno.EINVAL => unreachable{},
errno.EFAULT => unreachable{},
errno.EINVAL => @unreachable(),
errno.EFAULT => @unreachable(),
errno.EINTR => error.SigInterrupt,
else => error.Unexpected,
}

View File

@ -485,8 +485,8 @@ pub fn main(args: [][]u8) -> %void {
const c = @cImport(@cInclude("stdlib.h"));
export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int {
const a_int = (&i32)(a ?? unreachable{});
const b_int = (&i32)(b ?? unreachable{});
const a_int = (&i32)(a ?? @unreachable());
const b_int = (&i32)(b ?? @unreachable());
if (*a_int < *b_int) {
-1
} else if (*a_int > *b_int) {

View File

@ -25,20 +25,20 @@ fn ifStatements() {
}
fn shouldBeEqual(a: i32, b: i32) {
if (a != b) {
unreachable{};
@unreachable();
} else {
return;
}
}
fn firstEqlThird(a: i32, b: i32, c: i32) {
if (a == b) {
unreachable{};
@unreachable();
} else if (b == c) {
unreachable{};
@unreachable();
} else if (a == c) {
return;
} else {
unreachable{};
@unreachable();
}
}
@ -58,7 +58,7 @@ fn localVariables() {
}
fn testLocVars(b: i32) {
const a: i32 = 1;
if (a + b != 3) unreachable{};
if (a + b != 3) @unreachable();
}
#attribute("test")
@ -145,7 +145,7 @@ fn shortCircuit() {
#static_eval_enable(false)
fn assertRuntime(b: bool) {
if (!b) unreachable{}
if (!b) @unreachable()
}
#attribute("test")
@ -328,10 +328,10 @@ fn maybeType() {
if (y) {
// OK
} else {
unreachable{};
@unreachable();
}
} else {
unreachable{};
@unreachable();
}
const next_x : ?i32 = null;
@ -342,7 +342,7 @@ fn maybeType() {
const final_x : ?i32 = 13;
const num = final_x ?? unreachable{};
const num = final_x ?? @unreachable();
assert(num == 13);
}
@ -360,7 +360,7 @@ fn enumType() {
const expected_foo_size = switch (@compileVar("arch")) {
i386 => 20,
x86_64 => 24,
else => unreachable{},
else => @unreachable(),
};
assert(@sizeOf(EnumTypeFoo) == expected_foo_size);
assert(@sizeOf(EnumTypeBar) == 1);
@ -437,7 +437,7 @@ error AnError;
error AnError;
error SecondError;
fn shouldBeNotEqual(a: error, b: error) {
if (a == b) unreachable{}
if (a == b) @unreachable()
}
@ -454,13 +454,13 @@ fn constantEnumWithPayload() {
fn shouldBeEmpty(x: AnEnumWithPayload) {
switch (x) {
Empty => {},
else => unreachable{},
else => @unreachable(),
}
}
fn shouldBeNotEmpty(x: AnEnumWithPayload) {
switch (x) {
Empty => unreachable{},
Empty => @unreachable(),
else => {},
}
}
@ -482,7 +482,7 @@ fn continueInForLoop() {
}
break;
}
if (sum != 6) unreachable{}
if (sum != 6) @unreachable()
}
@ -514,9 +514,9 @@ enum Fruit {
#static_eval_enable(false)
fn nonConstSwitchOnEnum(fruit: Fruit) {
switch (fruit) {
Apple => unreachable{},
Apple => @unreachable(),
Orange => {},
Banana => unreachable{},
Banana => @unreachable(),
}
}
@ -532,7 +532,7 @@ fn nonConstSwitch(foo: SwitchStatmentFoo) {
C => 3,
D => 4,
};
if (val != 3) unreachable{};
if (val != 3) @unreachable();
}
enum SwitchStatmentFoo {
A,
@ -557,10 +557,10 @@ enum SwitchProngWithVarEnum {
fn switchProngWithVarFn(a: SwitchProngWithVarEnum) {
switch(a) {
One => |x| {
if (x != 13) unreachable{};
if (x != 13) @unreachable();
},
Two => |x| {
if (x != 13.0) unreachable{};
if (x != 13.0) @unreachable();
},
Meh => |x| {
const v: void = x;
@ -601,7 +601,7 @@ fn implicitCastFnUnreachableReturn() {
fn wantsFnWithVoid(f: fn()) { }
fn fnWithUnreachable() -> unreachable {
unreachable {}
@unreachable()
}
@ -644,13 +644,13 @@ fn slicing() {
var slice = array[5...10];
if (slice.len != 5) unreachable{};
if (slice.len != 5) @unreachable();
const ptr = &slice[0];
if (ptr[0] != 1234) unreachable{};
if (ptr[0] != 1234) @unreachable();
var slice_rest = array[10...];
if (slice_rest.len != 10) unreachable{};
if (slice_rest.len != 10) @unreachable();
}
@ -662,7 +662,7 @@ fn memcpyAndMemsetIntrinsics() {
@memset(&foo[0], 'A', foo.len);
@memcpy(&bar[0], &foo[0], bar.len);
if (bar[11] != 'A') unreachable{};
if (bar[11] != 'A') @unreachable();
}
@ -807,7 +807,7 @@ exit:
if (it_worked) {
return;
}
unreachable{};
@unreachable();
entry:
defer it_worked = true;
if (b) goto exit;
@ -1221,7 +1221,7 @@ fn test3_1(f: Test3Foo) {
assert(pt.x == 3);
assert(pt.y == 4);
},
else => unreachable{},
else => @unreachable(),
}
}
#static_eval_enable(false)
@ -1230,7 +1230,7 @@ fn test3_2(f: Test3Foo) {
Two => |x| {
assert(x == 13);
},
else => unreachable{},
else => @unreachable(),
}
}