about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-11-24 06:58:25 +0000
committerbors <bors@rust-lang.org>2015-11-24 06:58:25 +0000
commit561d0884e5563569e6e5c6b9a72b7b7d0bd44302 (patch)
tree5515e586a56ff7fa5fc694c62bf16156bbac2e9d
parent92f96b2445db675e343b8e795faecacdee0d29cc (diff)
parent7fbcb51589a9d10a2b3ec227611b31b7384b5370 (diff)
downloadrust-561d0884e5563569e6e5c6b9a72b7b7d0bd44302.tar.gz
rust-561d0884e5563569e6e5c6b9a72b7b7d0bd44302.zip
Auto merge of #30000 - Manishearth:unreachable-call, r=nrc
Fixes #1889
-rw-r--r--src/librustc_typeck/check/mod.rs28
-rw-r--r--src/libsyntax/ext/base.rs4
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs4
-rw-r--r--src/test/compile-fail/unreachable-in-call.rs32
4 files changed, 64 insertions, 4 deletions
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a635c1b047d..bac85e4b700 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2490,6 +2490,8 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // of arguments when we typecheck the functions. This isn't really the
     // right way to do this.
     let xs = [false, true];
+    let mut any_diverges = false; // has any of the arguments diverged?
+    let mut warned = false; // have we already warned about unreachable code?
     for check_blocks in &xs {
         let check_blocks = *check_blocks;
         debug!("check_blocks={}", check_blocks);
@@ -2512,6 +2514,16 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             supplied_arg_count
         };
         for (i, arg) in args.iter().take(t).enumerate() {
+            if any_diverges && !warned {
+                fcx.ccx
+                    .tcx
+                    .sess
+                    .add_lint(lint::builtin::UNREACHABLE_CODE,
+                              arg.id,
+                              arg.span,
+                              "unreachable expression".to_string());
+                warned = true;
+            }
             let is_block = match arg.node {
                 hir::ExprClosure(..) => true,
                 _ => false
@@ -2542,7 +2554,23 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     coerce_ty.map(|ty| demand::suptype(fcx, arg.span, formal_ty, ty));
                 });
             }
+
+            if let Some(&arg_ty) = fcx.inh.tables.borrow().node_types.get(&arg.id) {
+                any_diverges = any_diverges || fcx.infcx().type_var_diverges(arg_ty);
+            }
+        }
+        if any_diverges && !warned {
+            let parent = fcx.ccx.tcx.map.get_parent_node(args[0].id);
+            fcx.ccx
+                .tcx
+                .sess
+                .add_lint(lint::builtin::UNREACHABLE_CODE,
+                          parent,
+                          sp,
+                          "unreachable call".to_string());
+            warned = true;
         }
+
     }
 
     // We also need to make sure we at least write the ty of the other
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index c8db3853cc2..55f0fa5675a 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -678,9 +678,9 @@ impl<'a> ExtCtxt<'a> {
     pub fn bt_push(&mut self, ei: ExpnInfo) {
         self.recursion_count += 1;
         if self.recursion_count > self.ecfg.recursion_limit {
-            panic!(self.span_fatal(ei.call_site,
+            self.span_fatal(ei.call_site,
                             &format!("recursion limit reached while expanding the macro `{}`",
-                                    ei.callee.name())));
+                                    ei.callee.name()));
         }
 
         let mut call_site = ei.call_site;
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 43647ea4a2e..23d6b794a72 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -209,12 +209,12 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                 best_fail_msg = (*msg).clone();
             },
             Error(err_sp, ref msg) => {
-                panic!(cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]))
+                cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..])
             }
         }
     }
 
-    panic!(cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg[..]));
+     cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg[..]);
 }
 
 // Note that macro-by-example's input is also matched against a token tree:
diff --git a/src/test/compile-fail/unreachable-in-call.rs b/src/test/compile-fail/unreachable-in-call.rs
new file mode 100644
index 00000000000..5a3257d54db
--- /dev/null
+++ b/src/test/compile-fail/unreachable-in-call.rs
@@ -0,0 +1,32 @@
+// 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.
+
+#![allow(dead_code)]
+#![deny(unreachable_code)]
+
+fn diverge() -> ! { panic!() }
+
+fn get_u8() -> u8 {
+    1
+}
+fn call(_: u8, _: u8) {
+
+}
+fn diverge_first() {
+    call(diverge(),
+         get_u8()); //~ ERROR unreachable expression
+}
+fn diverge_second() {
+    call( //~ ERROR unreachable call
+        get_u8(),
+        diverge());
+}
+
+fn main() {}