Commit 451ce09067

Andrew Kelley <superjoe30@gmail.com>
2017-03-26 10:58:48
new unreachable syntax
* `noreturn` is the primitive type. * `unreachable` is a control flow keyword. * `@unreachable()` builtin function is deleted. closes #214
1 parent 22e6bfc
doc/vim/syntax/zig.vim
@@ -16,7 +16,7 @@ syn keyword zigRepeat while for
 
 syn keyword zigConstant null undefined this
 syn keyword zigKeyword fn use test
-syn keyword zigType bool f32 f64 void Unreachable type error
+syn keyword zigType bool f32 f64 void noreturn type error
 syn keyword zigType i8  u8  i16  u16  i32  u32  i64  u64  isize  usize
 syn keyword zigType c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong c_long_double
 
doc/langref.md
@@ -155,7 +155,7 @@ GotoExpression = "goto" Symbol
 
 GroupedExpression = "(" Expression ")"
 
-KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this"
+KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this" | "unreachable"
 
 ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"
 
@@ -213,60 +213,6 @@ f32             float               32-bit floating point
 f64             double              64-bit floating point
 ```
 
-### Boolean Type
-
-The boolean type has the name `bool` and represents either true or false.
-
-### Function Type
-
-TODO
-
-### Fixed-Size Array Type
-
-Example: The string `"aoeu"` has type `[4]u8`.
-
-The size is known at compile time and is part of the type.
-
-### Slice Type
-
-A slice can be obtained with the slicing syntax: `array[start...end]`
-
-Example: `"aoeu"[0...2]` has type `[]u8`.
-
-### Struct Type
-
-TODO
-
-### Enum Type
-
-TODO
-
-### Maybe Type
-
-TODO
-
-### Pure Error Type
-
-TODO
-
-### Error Union Type
-
-TODO
-
-### Pointer Type
-
-TODO
-
-### Unreachable Type
-
-The unreachable type has the name `unreachable`. TODO explanation
-
-### Void Type
-
-The void type has the name `void`. void types are zero bits and are omitted
-from codegen.
-
-
 ## Expressions
 
 ### Literals
@@ -347,31 +293,6 @@ has a terminating null byte.
  Floating point     | 123.0E+77   | Optional
  Hex floating point | 0x103.70p-5 | Optional
 
-### Identifiers
-
-TODO
-
-### Declarations
-
-Declarations have type `void`.
-
-#### Function Declarations
-
-TODO
-
-#### Variable Declarations
-
-TODO
-
-#### Struct Declarations
-
-TODO
-
-#### Enum Declarations
-
-TODO
-
-
 ## Built-in Functions
 
 Built-in functions are prefixed with `@`. Remember that the `comptime` keyword on
@@ -682,10 +603,6 @@ code.
 
 This function returns an integer type with the given signness and bit count.
 
-### @setFnTest(func)
-
-Makes the target function a test function.
-
 ### @setDebugSafety(scope, safety_on: bool)
 
 Sets a whether we want debug safety checks on for a given scope.
src/all_types.hpp
@@ -334,6 +334,7 @@ enum NodeType {
     NodeTypeNullLiteral,
     NodeTypeUndefinedLiteral,
     NodeTypeThisLiteral,
+    NodeTypeUnreachable,
     NodeTypeIfBoolExpr,
     NodeTypeIfVarExpr,
     NodeTypeWhileExpr,
@@ -758,6 +759,9 @@ struct AstNodeBreakExpr {
 
 struct AstNodeContinueExpr {
 };
+struct AstNodeUnreachableExpr {
+};
+
 
 struct AstNodeArrayType {
     AstNode *size;
@@ -827,6 +831,7 @@ struct AstNode {
         AstNodeBoolLiteral bool_literal;
         AstNodeBreakExpr break_expr;
         AstNodeContinueExpr continue_expr;
+        AstNodeUnreachableExpr unreachable_expr;
         AstNodeArrayType array_type;
         AstNodeErrorType error_type;
         AstNodeTypeLiteral type_literal;
@@ -1173,7 +1178,6 @@ enum BuiltinFnId {
     BuiltinFnIdDivExact,
     BuiltinFnIdTruncate,
     BuiltinFnIdIntType,
-    BuiltinFnIdUnreachable,
     BuiltinFnIdSetFnVisible,
     BuiltinFnIdSetDebugSafety,
     BuiltinFnIdAlloca,
src/analyze.cpp
@@ -2110,6 +2110,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
         case NodeTypeGoto:
         case NodeTypeBreak:
         case NodeTypeContinue:
+        case NodeTypeUnreachable:
         case NodeTypeAsmExpr:
         case NodeTypeFieldAccessExpr:
         case NodeTypeStructField:
src/ast_render.cpp
@@ -216,6 +216,8 @@ static const char *node_type_str(NodeType node_type) {
             return "Break";
         case NodeTypeContinue:
             return "Continue";
+        case NodeTypeUnreachable:
+            return "Unreachable";
         case NodeTypeAsmExpr:
             return "AsmExpr";
         case NodeTypeFieldAccessExpr:
@@ -890,6 +892,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
                 fprintf(ar->f, "continue");
                 break;
             }
+        case NodeTypeUnreachable:
+            {
+                fprintf(ar->f, "unreachable");
+                break;
+            }
         case NodeTypeSliceExpr:
             {
                 render_node_ungrouped(ar, node->data.slice_expr.array_ref_expr);
src/codegen.cpp
@@ -3786,7 +3786,7 @@ static void define_builtin_types(CodeGen *g) {
         TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable);
         entry->type_ref = LLVMVoidType();
         entry->zero_bits = true;
-        buf_init_from_str(&entry->name, "unreachable");
+        buf_init_from_str(&entry->name, "noreturn");
         entry->di_type = g->builtin_types.entry_void->di_type;
         g->builtin_types.entry_unreachable = entry;
         g->primitive_type_table.put(&entry->name, entry);
@@ -4096,7 +4096,6 @@ static void define_builtin_fns(CodeGen *g) {
     create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
     create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
     create_builtin_fn(g, BuiltinFnIdIntType, "intType", 2);
-    create_builtin_fn(g, BuiltinFnIdUnreachable, "unreachable", 0);
     create_builtin_fn(g, BuiltinFnIdSetFnVisible, "setFnVisible", 2);
     create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
     create_builtin_fn(g, BuiltinFnIdAlloca, "alloca", 2);
src/ir.cpp
@@ -3751,8 +3751,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
     switch (builtin_fn->id) {
         case BuiltinFnIdInvalid:
             zig_unreachable();
-        case BuiltinFnIdUnreachable:
-            return ir_build_unreachable(irb, scope, node);
         case BuiltinFnIdTypeof:
             {
                 AstNode *arg_node = node->data.fn_call_expr.params.at(0);
@@ -5467,6 +5465,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
             return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval);
         case NodeTypeContinue:
             return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval);
+        case NodeTypeUnreachable:
+            return ir_lval_wrap(irb, scope, ir_build_unreachable(irb, scope, node), lval);
         case NodeTypeDefer:
             return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval);
         case NodeTypeSliceExpr:
src/parser.cpp
@@ -705,7 +705,7 @@ static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index, bool m
 
 /*
 PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
-KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this"
+KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this" | "unreachable"
 */
 static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
     Token *token = &pc->tokens->at(*token_index);
@@ -757,6 +757,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
         AstNode *node = ast_create_node(pc, NodeTypeThisLiteral, token);
         *token_index += 1;
         return node;
+    } else if (token->id == TokenIdKeywordUnreachable) {
+        AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token);
+        *token_index += 1;
+        return node;
     } else if (token->id == TokenIdKeywordType) {
         AstNode *node = ast_create_node(pc, NodeTypeTypeLiteral, token);
         *token_index += 1;
@@ -2728,6 +2732,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
         case NodeTypeContinue:
             // none
             break;
+        case NodeTypeUnreachable:
+            // none
+            break;
         case NodeTypeAsmExpr:
             for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
                 AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
src/tokenizer.cpp
@@ -140,6 +140,7 @@ static const struct ZigKeyword zig_keywords[] = {
     {"type", TokenIdKeywordType},
     {"undefined", TokenIdKeywordUndefined},
     {"union", TokenIdKeywordUnion},
+    {"unreachable", TokenIdKeywordUnreachable},
     {"use", TokenIdKeywordUse},
     {"var", TokenIdKeywordVar},
     {"volatile", TokenIdKeywordVolatile},
@@ -1516,6 +1517,7 @@ const char * token_name(TokenId id) {
         case TokenIdKeywordType: return "type";
         case TokenIdKeywordUndefined: return "undefined";
         case TokenIdKeywordUnion: return "union";
+        case TokenIdKeywordUnreachable: return "unreachable";
         case TokenIdKeywordUse: return "use";
         case TokenIdKeywordVar: return "var";
         case TokenIdKeywordVolatile: return "volatile";
src/tokenizer.hpp
@@ -81,6 +81,7 @@ enum TokenId {
     TokenIdKeywordType,
     TokenIdKeywordUndefined,
     TokenIdKeywordUnion,
+    TokenIdKeywordUnreachable,
     TokenIdKeywordUse,
     TokenIdKeywordVar,
     TokenIdKeywordVolatile,
std/c/index.zig
@@ -7,7 +7,7 @@ pub use switch(@compileVar("os")) {
     else => empty_import,
 };
 
-pub extern fn abort() -> unreachable;
+pub extern fn abort() -> noreturn;
 
 
 const empty_import = @import("empty.zig");
std/bootstrap.zig
@@ -16,10 +16,10 @@ const exit = switch(@compileVar("os")) {
 var argc: usize = undefined;
 var argv: &&u8 = undefined;
 
-export nakedcc fn _start() -> unreachable {
+export nakedcc fn _start() -> noreturn {
     @setFnVisible(this, want_start_symbol);
     if (!want_start_symbol) {
-        @unreachable();
+        unreachable;
     }
 
     switch (@compileVar("arch")) {
@@ -45,7 +45,7 @@ fn callMain() -> %void {
     return root.main(args);
 }
 
-fn callMainAndExit() -> unreachable {
+fn callMainAndExit() -> noreturn {
     callMain() %% exit(1);
     exit(0);
 }
@@ -53,7 +53,7 @@ fn callMainAndExit() -> unreachable {
 export fn main(c_argc: i32, c_argv: &&u8) -> i32 {
     @setFnVisible(this, want_main_symbol);
     if (!want_main_symbol) {
-        @unreachable();
+        unreachable;
     }
 
     argc = usize(c_argc);
std/builtin.zig
@@ -31,6 +31,6 @@ export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) {
 }
 
 // Avoid dragging in the debug safety mechanisms into this .o file.
-pub fn panic(message: []const u8) -> unreachable {
-    @unreachable();
+pub fn panic(message: []const u8) -> noreturn {
+    unreachable;
 }
std/compiler_rt.zig
@@ -1,10 +1,10 @@
 // Avoid dragging in the debug safety mechanisms into this .o file,
 // unless we're trying to test this file.
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     if (@compileVar("is_test")) {
         @import("std").debug.panic(message);
     } else {
-        @unreachable();
+        unreachable;
     }
 }
 
@@ -259,7 +259,7 @@ export nakedcc fn __aeabi_uidivmod() {
             \\ add     sp, sp, #4
             \\ pop     { pc }
         ::: "r2", "r1");
-        @unreachable();
+        unreachable;
     }
 
     @setFnVisible(this, false);
@@ -511,5 +511,5 @@ fn test_one_udivsi3(a: su_int, b: su_int, expected_q: su_int) {
 
 
 fn assert(ok: bool) {
-    if (!ok) @unreachable();
+    if (!ok) unreachable;
 }
std/darwin.zig
@@ -48,9 +48,9 @@ pub const SIGPWR    = 30;
 pub const SIGSYS    = 31;
 pub const SIGUNUSED = SIGSYS;
 
-pub fn exit(status: usize) -> unreachable {
+pub fn exit(status: usize) -> noreturn {
     _ = arch.syscall1(arch.SYS_exit, status);
-    @unreachable()
+    unreachable
 }
 
 /// Get the errno from a syscall return value, or 0 for no error.
std/debug.zig
@@ -10,12 +10,12 @@ error InvalidDebugInfo;
 error UnsupportedDebugInfo;
 
 pub fn assert(ok: bool) {
-    if (!ok) @unreachable()
+    if (!ok) unreachable
 }
 
 var panicking = false;
 /// This is the default panic implementation.
-pub coldcc fn panic(message: []const u8) -> unreachable {
+pub coldcc fn panic(message: []const u8) -> noreturn {
     // TODO
     // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
     if (panicking) {
@@ -252,7 +252,7 @@ fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
     } else if (@sizeOf(usize) == 8) {
         %return in_stream.readIntLe(u64)
     } else {
-        @unreachable();
+        unreachable;
     };
 }
 
std/fmt.zig
@@ -287,7 +287,7 @@ fn digitToChar(digit: u8, uppercase: bool) -> u8 {
     return switch (digit) {
         0 ... 9 => digit + '0',
         10 ... 35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
-        else => @unreachable(),
+        else => unreachable,
     };
 }
 
@@ -316,9 +316,9 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: u
 test "testParseU64DigitTooBig" {
     parseUnsigned(u64, "123a", 10) %% |err| {
         if (err == error.InvalidChar) return;
-        @unreachable();
+        unreachable;
     };
-    @unreachable();
+    unreachable;
 }
 
 test "testParseUnsignedComptime" {
std/hash_map.zig
@@ -50,7 +50,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
                         return entry;
                     }
                 }
-                @unreachable() // no next item
+                unreachable // no next item
             }
         };
 
@@ -125,9 +125,9 @@ pub fn HashMap(comptime K: type, comptime V: type,
                     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 {
@@ -198,7 +198,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
                 };
                 return;
             }
-            @unreachable() // put into a full map
+            unreachable // put into a full map
         }
 
         fn internalGet(hm: &Self, key: K) -> ?&Entry {
std/io.zig
@@ -129,7 +129,7 @@ pub const OutStream = struct {
             if (write_err > 0) {
                 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,
@@ -171,8 +171,8 @@ pub const InStream = struct {
                         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,
@@ -235,8 +235,8 @@ pub const InStream = struct {
                         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,
std/linux.zig
@@ -297,9 +297,9 @@ pub fn lseek(fd: i32, offset: usize, ref_pos: usize) -> usize {
     arch.syscall3(arch.SYS_lseek, usize(fd), offset, ref_pos)
 }
 
-pub fn exit(status: i32) -> unreachable {
+pub fn exit(status: i32) -> noreturn {
     _ = arch.syscall1(arch.SYS_exit, usize(status));
-    @unreachable()
+    unreachable
 }
 
 pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize {
std/math.zig
@@ -57,7 +57,7 @@ pub fn abs(x: var) -> @typeOf(x) {
     } else if (@isFloat(T)) {
         @compileError("TODO implement abs for floats");
     } else {
-        @unreachable();
+        unreachable;
     }
 }
 fn getReturnTypeForAbs(comptime T: type) -> type {
std/net.zig
@@ -21,8 +21,8 @@ const Connection = struct {
         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 @@ const Connection = struct {
         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 @@ const Connection = struct {
     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
     }
 
     // TODO
@@ -86,7 +86,7 @@ pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address {
     //    else => {},
     //};
 
-    @unreachable() // TODO
+    unreachable // TODO
 }
 
 pub fn connectAddr(addr: &Address, port: u16) -> %Connection {
@@ -114,7 +114,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) {
@@ -324,11 +324,11 @@ fn parseIp4(buf: []const u8) -> %u32 {
 //    @setFnTest(this);
 //
 //    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, }
 //}
 //
 //fn testParseIp6() {
std/os.zig
@@ -46,8 +46,8 @@ pub fn getRandomBytes(buf: []u8) -> %void {
         };
         if (err > 0) {
             return switch (err) {
-                errno.EINVAL => @unreachable(),
-                errno.EFAULT => @unreachable(),
+                errno.EINVAL => unreachable,
+                errno.EFAULT => unreachable,
                 errno.EINTR  => continue,
                 else         => error.Unexpected,
             }
@@ -59,7 +59,7 @@ pub fn getRandomBytes(buf: []u8) -> %void {
 /// Raises a signal in the current kernel thread, ending its execution.
 /// If linking against libc, this calls the abort() libc function. Otherwise
 /// it uses the zig standard library implementation.
-pub coldcc fn abort() -> unreachable {
+pub coldcc fn abort() -> noreturn {
     if (linking_libc) {
         c.abort();
     }
std/panic.zig
@@ -3,7 +3,7 @@
 // If this file wants to import other files *by name*, support for that would
 // have to be added in the compiler.
 
-pub coldcc fn panic(message: []const u8) -> unreachable {
+pub coldcc fn panic(message: []const u8) -> noreturn {
     if (@compileVar("os") == Os.freestanding) {
         while (true) {}
     } else {
test/cases/enum.zig
@@ -16,7 +16,7 @@ test "enumType" {
 test "enumAsReturnValue" {
     switch (returnAnInt(13)) {
         Foo.One => |value| assert(value == 13),
-        else => @unreachable(),
+        else => unreachable,
     }
 }
 
@@ -51,13 +51,13 @@ test "constantEnumWithPayload" {
 fn shouldBeEmpty(x: &const AnEnumWithPayload) {
     switch (*x) {
         AnEnumWithPayload.Empty => {},
-        else => @unreachable(),
+        else => unreachable,
     }
 }
 
 fn shouldBeNotEmpty(x: &const AnEnumWithPayload) {
     switch (*x) {
-        AnEnumWithPayload.Empty => @unreachable(),
+        AnEnumWithPayload.Empty => unreachable,
         else => {},
     }
 }
test/cases/error.zig
@@ -48,7 +48,7 @@ error AnError;
 error AnError;
 error SecondError;
 fn shouldBeNotEqual(a: error, b: error) {
-    if (a == b) @unreachable()
+    if (a == b) unreachable
 }
 
 
test/cases/fn.zig
@@ -13,7 +13,7 @@ test "localVariables" {
 }
 fn testLocVars(b: i32) {
     const a: i32 = 1;
-    if (a + b != 3) @unreachable();
+    if (a + b != 3) unreachable;
 }
 
 
@@ -72,8 +72,8 @@ test "implicitCastFnUnreachableReturn" {
 
 fn wantsFnWithVoid(f: fn()) { }
 
-fn fnWithUnreachable() -> unreachable {
-    @unreachable()
+fn fnWithUnreachable() -> noreturn {
+    unreachable
 }
 
 
test/cases/for.zig
@@ -12,7 +12,7 @@ test "continueInForLoop" {
         }
         break;
     }
-    if (sum != 6) @unreachable()
+    if (sum != 6) unreachable
 }
 
 test "forLoopWithPointerElemVar" {
test/cases/goto.zig
@@ -30,7 +30,7 @@ exit:
     if (it_worked) {
         return;
     }
-    @unreachable();
+    unreachable;
 entry:
     defer it_worked = true;
     if (b) goto exit;
test/cases/if.zig
@@ -6,20 +6,20 @@ test "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;
     }
 }
 
test/cases/misc.zig
@@ -163,7 +163,7 @@ test "memcpyAndMemsetIntrinsics" {
     @memset(&foo[0], 'A', foo.len);
     @memcpy(&bar[0], &foo[0], bar.len);
 
-    if (bar[11] != 'A') @unreachable();
+    if (bar[11] != 'A') unreachable;
 }
 
 test "builtinStaticEval" {
@@ -178,13 +178,13 @@ test "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;
 }
 
 
@@ -344,7 +344,7 @@ fn test3_1(f: &const Test3Foo) {
             assert(pt.x == 3);
             assert(pt.y == 4);
         },
-        else => @unreachable(),
+        else => unreachable,
     }
 }
 fn test3_2(f: &const Test3Foo) {
@@ -352,7 +352,7 @@ fn test3_2(f: &const Test3Foo) {
         Test3Foo.Two => |x| {
             assert(x == 13);
         },
-        else => @unreachable(),
+        else => unreachable,
     }
 }
 
test/cases/null.zig
@@ -7,10 +7,10 @@ test "nullableType" {
         if (y) {
             // OK
         } else {
-            @unreachable();
+            unreachable;
         }
     } else {
-        @unreachable();
+        unreachable;
     }
 
     const next_x : ?i32 = @generatedCode(null);
@@ -21,7 +21,7 @@ test "nullableType" {
 
     const final_x : ?i32 = @generatedCode(13);
 
-    const num = final_x ?? @unreachable();
+    const num = final_x ?? unreachable;
 
     assert(num == 13);
 }
test/cases/switch.zig
@@ -55,9 +55,9 @@ const Fruit = enum {
 };
 fn nonConstSwitchOnEnum(fruit: Fruit) {
     switch (fruit) {
-        Fruit.Apple => @unreachable(),
+        Fruit.Apple => unreachable,
         Fruit.Orange => {},
-        Fruit.Banana => @unreachable(),
+        Fruit.Banana => unreachable,
     }
 }
 
@@ -72,7 +72,7 @@ fn nonConstSwitch(foo: SwitchStatmentFoo) {
         SwitchStatmentFoo.C => 3,
         SwitchStatmentFoo.D => 4,
     };
-    if (val != 3) @unreachable();
+    if (val != 3) unreachable;
 }
 const SwitchStatmentFoo = enum {
     A,
@@ -95,10 +95,10 @@ const SwitchProngWithVarEnum = enum {
 fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) {
     switch(*a) {
         SwitchProngWithVarEnum.One => |x| {
-            if (x != 13) @unreachable();
+            if (x != 13) unreachable;
         },
         SwitchProngWithVarEnum.Two => |x| {
-            if (x != 13.0) @unreachable();
+            if (x != 13.0) unreachable;
         },
         SwitchProngWithVarEnum.Meh => |x| {
             const v: void = x;
test/cases/try.zig
@@ -52,7 +52,7 @@ fn failIfTrue(ok: bool) -> %void {
 //    @setFnTest(this);
 //
 //    try (_ = failIfTrue(true)) {
-//        @unreachable();
+//        unreachable;
 //    } else |err| {
 //        assert(err == error.ItBroke);
 //    }
test/run_tests.cpp
@@ -471,8 +471,8 @@ const foo : i32 = 0;
 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) {
@@ -628,9 +628,9 @@ export fn entry() { a(); }
     )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'a'");
 
     add_compile_fail_case("unreachable with return", R"SOURCE(
-fn a() -> unreachable {return;}
+fn a() -> noreturn {return;}
 export fn entry() { a(); }
-    )SOURCE", 1, ".tmp_source.zig:2:24: error: expected type 'unreachable', found 'void'");
+    )SOURCE", 1, ".tmp_source.zig:2:21: error: expected type 'noreturn', found 'void'");
 
     add_compile_fail_case("control reaches end of non-void function", R"SOURCE(
 fn a() -> i32 {}
@@ -656,7 +656,7 @@ export fn entry() { _ = a(); }
     )SOURCE", 1, ".tmp_source.zig:2:11: error: use of undeclared identifier 'bogus'");
 
     add_compile_fail_case("pointer to unreachable", R"SOURCE(
-fn a() -> &unreachable {}
+fn a() -> &noreturn {}
 export fn entry() { _ = a(); }
     )SOURCE", 1, ".tmp_source.zig:2:12: error: pointer to unreachable not allowed");
 
@@ -724,14 +724,14 @@ export fn f() {
 
     add_compile_fail_case("unreachable variable", R"SOURCE(
 export fn f() {
-    const a : unreachable = {};
+    const a: noreturn = {};
 }
-    )SOURCE", 1, ".tmp_source.zig:3:15: error: variable of type 'unreachable' not allowed");
+    )SOURCE", 1, ".tmp_source.zig:3:14: error: variable of type 'noreturn' not allowed");
 
     add_compile_fail_case("unreachable parameter", R"SOURCE(
-fn f(a : unreachable) {}
+fn f(a: noreturn) {}
 export fn entry() { f(); }
-    )SOURCE", 1, ".tmp_source.zig:2:10: error: parameter of type 'unreachable' not allowed");
+    )SOURCE", 1, ".tmp_source.zig:2:9: error: parameter of type 'noreturn' not allowed");
 
     add_compile_fail_case("bad assignment target", R"SOURCE(
 export fn f() {
@@ -1737,7 +1737,7 @@ export fn foo() {
 }
 
 fn assert(ok: bool) {
-    if (!ok) @unreachable();
+    if (!ok) unreachable;
 }
     )SOURCE", 2,
             ".tmp_source.zig:11:14: error: unable to evaluate constant expression",
@@ -1830,7 +1830,7 @@ export fn entry() {
 
 static void add_debug_safety_test_cases(void) {
     add_debug_safety_case("out of bounds slice access", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -1845,7 +1845,7 @@ fn baz(a: i32) { }
     )SOURCE");
 
     add_debug_safety_case("integer addition overflow", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -1860,7 +1860,7 @@ fn add(a: u16, b: u16) -> u16 {
     )SOURCE");
 
     add_debug_safety_case("integer subtraction overflow", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -1875,7 +1875,7 @@ fn sub(a: u16, b: u16) -> u16 {
     )SOURCE");
 
     add_debug_safety_case("integer multiplication overflow", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -1890,7 +1890,7 @@ fn mul(a: u16, b: u16) -> u16 {
     )SOURCE");
 
     add_debug_safety_case("integer negation overflow", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -1905,7 +1905,7 @@ fn neg(a: i16) -> i16 {
     )SOURCE");
 
     add_debug_safety_case("signed integer division overflow", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -1920,7 +1920,7 @@ fn div(a: i16, b: i16) -> i16 {
     )SOURCE");
 
     add_debug_safety_case("signed shift left overflow", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -1935,7 +1935,7 @@ fn shl(a: i16, b: i16) -> i16 {
     )SOURCE");
 
     add_debug_safety_case("unsigned shift left overflow", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -1950,7 +1950,7 @@ fn shl(a: u16, b: u16) -> u16 {
     )SOURCE");
 
     add_debug_safety_case("integer division by zero", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -1964,7 +1964,7 @@ fn div0(a: i32, b: i32) -> i32 {
     )SOURCE");
 
     add_debug_safety_case("exact division failure", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -1979,7 +1979,7 @@ fn divExact(a: i32, b: i32) -> i32 {
     )SOURCE");
 
     add_debug_safety_case("cast []u8 to bigger slice of wrong size", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -1994,7 +1994,7 @@ fn widenSlice(slice: []const u8) -> []const i32 {
     )SOURCE");
 
     add_debug_safety_case("value does not fit in shortening cast", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -2009,7 +2009,7 @@ fn shorten_cast(x: i32) -> i8 {
     )SOURCE");
 
     add_debug_safety_case("signed integer not fitting in cast to unsigned integer", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -2024,7 +2024,7 @@ fn unsigned_cast(x: i32) -> u32 {
     )SOURCE");
 
     add_debug_safety_case("unwrap error", R"SOURCE(
-pub fn panic(message: []const u8) -> unreachable {
+pub fn panic(message: []const u8) -> noreturn {
     @breakpoint();
     while (true) {}
 }
@@ -2055,7 +2055,7 @@ void baz(int8_t a, int16_t b, int32_t c, int64_t d);
 
     add_parseh_case("noreturn attribute", AllowWarningsNo, R"SOURCE(
 void foo(void) __attribute__((noreturn));
-    )SOURCE", 1, R"OUTPUT(pub extern fn foo() -> unreachable;)OUTPUT");
+    )SOURCE", 1, R"OUTPUT(pub extern fn foo() -> noreturn;)OUTPUT");
 
     add_parseh_case("enums", AllowWarningsNo, R"SOURCE(
 enum Foo {