From 401aeaf6d3a6ec712ee46151faf574adaa5ff3c6 Mon Sep 17 00:00:00 2001
From: Keegan McAllister <kmcallister@mozilla.com>
Date: Wed, 3 Sep 2014 12:00:08 -0700
Subject: [PATCH 1/2] Add intrinsics::unreachable

---
 src/libcore/intrinsics.rs               | 7 +++++++
 src/librustc/middle/trans/intrinsic.rs  | 4 ++++
 src/librustc/middle/typeck/check/mod.rs | 1 +
 3 files changed, 12 insertions(+)

diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index a3d63bbe06cd1..7d86b65168f3c 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -250,6 +250,13 @@ extern "rust-intrinsic" {
     /// Abort the execution of the process.
     pub fn abort() -> !;
 
+    /// Tell LLVM that this point in the code is not reachable,
+    /// enabling further optimizations.
+    ///
+    /// NB: This is very different from the `unreachable!()` macro!
+    #[cfg(not(stage0))]
+    pub fn unreachable() -> !;
+
     /// Execute a breakpoint trap, for inspection by a debugger.
     pub fn breakpoint();
 
diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs
index 628971775ae8c..f9d55143c8400 100644
--- a/src/librustc/middle/trans/intrinsic.rs
+++ b/src/librustc/middle/trans/intrinsic.rs
@@ -228,6 +228,10 @@ pub fn trans_intrinsic_call<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, node: ast::N
             Unreachable(bcx);
             v
         }
+        (_, "unreachable") => {
+            Unreachable(bcx);
+            C_nil(ccx)
+        }
         (_, "breakpoint") => {
             let llfn = ccx.get_intrinsic(&("llvm.debugtrap"));
             Call(bcx, llfn, [], None)
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index d4c38d48a8c56..197fd2367277a 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -5589,6 +5589,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
     } else {
         match name.get() {
             "abort" => (0, Vec::new(), ty::mk_bot()),
+            "unreachable" => (0, Vec::new(), ty::mk_bot()),
             "breakpoint" => (0, Vec::new(), ty::mk_nil()),
             "size_of" |
             "pref_align_of" | "min_align_of" => (1u, Vec::new(), ty::mk_uint()),

From 675aa7692dd1b75e63b11cd991be5efddbdb2acd Mon Sep 17 00:00:00 2001
From: Keegan McAllister <kmcallister@mozilla.com>
Date: Thu, 4 Sep 2014 16:09:18 -0700
Subject: [PATCH 2/2] Add tests for intrinsics::unreachable

---
 .../run-make/intrinsic-unreachable/Makefile   | 15 ++++++++++++
 .../intrinsic-unreachable/exit-ret.rs         | 20 ++++++++++++++++
 .../intrinsic-unreachable/exit-unreachable.rs | 22 +++++++++++++++++
 src/test/run-pass/intrinsic-unreachable.rs    | 24 +++++++++++++++++++
 4 files changed, 81 insertions(+)
 create mode 100644 src/test/run-make/intrinsic-unreachable/Makefile
 create mode 100644 src/test/run-make/intrinsic-unreachable/exit-ret.rs
 create mode 100644 src/test/run-make/intrinsic-unreachable/exit-unreachable.rs
 create mode 100644 src/test/run-pass/intrinsic-unreachable.rs

diff --git a/src/test/run-make/intrinsic-unreachable/Makefile b/src/test/run-make/intrinsic-unreachable/Makefile
new file mode 100644
index 0000000000000..305e8a7ddc968
--- /dev/null
+++ b/src/test/run-make/intrinsic-unreachable/Makefile
@@ -0,0 +1,15 @@
+-include ../tools.mk
+
+ifndef IS_WINDOWS
+# The assembly for exit-unreachable.rs should be shorter because it's missing
+# (at minimum) a return instruction.
+
+all:
+	$(RUSTC) -O --emit asm exit-ret.rs
+	$(RUSTC) -O --emit asm exit-unreachable.rs
+	test `wc -l < $(TMPDIR)/exit-unreachable.s` -lt `wc -l < $(TMPDIR)/exit-ret.s`
+else
+# Because of Windows exception handling, the code is not necessarily any shorter.
+# https://github.com/llvm-mirror/llvm/commit/64b2297786f7fd6f5fa24cdd4db0298fbf211466
+all:
+endif
diff --git a/src/test/run-make/intrinsic-unreachable/exit-ret.rs b/src/test/run-make/intrinsic-unreachable/exit-ret.rs
new file mode 100644
index 0000000000000..02c03445ef4e6
--- /dev/null
+++ b/src/test/run-make/intrinsic-unreachable/exit-ret.rs
@@ -0,0 +1,20 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(asm)]
+#![crate_type="lib"]
+
+pub fn exit(n: uint) {
+    unsafe {
+        // Pretend this asm is an exit() syscall.
+        asm!("" :: "r"(n) :: "volatile");
+        // Can't actually reach this point, but rustc doesn't know that.
+    }
+}
diff --git a/src/test/run-make/intrinsic-unreachable/exit-unreachable.rs b/src/test/run-make/intrinsic-unreachable/exit-unreachable.rs
new file mode 100644
index 0000000000000..835e068c15cfd
--- /dev/null
+++ b/src/test/run-make/intrinsic-unreachable/exit-unreachable.rs
@@ -0,0 +1,22 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(asm)]
+#![crate_type="lib"]
+
+use std::intrinsics;
+
+pub fn exit(n: uint) -> ! {
+    unsafe {
+        // Pretend this asm is an exit() syscall.
+        asm!("" :: "r"(n) :: "volatile");
+        intrinsics::unreachable()
+    }
+}
diff --git a/src/test/run-pass/intrinsic-unreachable.rs b/src/test/run-pass/intrinsic-unreachable.rs
new file mode 100644
index 0000000000000..5e8b758cdf68f
--- /dev/null
+++ b/src/test/run-pass/intrinsic-unreachable.rs
@@ -0,0 +1,24 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::intrinsics;
+
+// See also src/test/run-make/intrinsic-unreachable.
+
+unsafe fn f(x: uint) -> uint {
+    match x {
+        17 => 23,
+        _ => intrinsics::unreachable(),
+    }
+}
+
+fn main() {
+    assert_eq!(unsafe { f(17) }, 23);
+}