Skip to content

Commit

Permalink
Rollup merge of rust-lang#45880 - arielb1:never-coerce, r=nikomatsakis
Browse files Browse the repository at this point in the history
make coercions to `!` in unreachable code a hard error

This was added to cover up a lazy extra semicolon in rust-lang#35849, but does
not actually make sense. This is removed as a part of the stabilization
of `never_type`.
  • Loading branch information
Ariel Ben-Yehuda committed Nov 30, 2017
2 parents d6b010f + 235de09 commit 8ae7017
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 12 deletions.
9 changes: 8 additions & 1 deletion src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ declare_lint! {
"detect mut variables which don't need to be mutable"
}

declare_lint! {
pub COERCE_NEVER,
Deny,
"detect coercion to !"
}

/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
Expand Down Expand Up @@ -263,7 +269,8 @@ impl LintPass for HardwiredLints {
LATE_BOUND_LIFETIME_ARGUMENTS,
DEPRECATED,
UNUSED_UNSAFE,
UNUSED_MUT
UNUSED_MUT,
COERCE_NEVER
)
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
id: LintId::of(SAFE_PACKED_BORROWS),
reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>",
},
FutureIncompatibleInfo {
id: LintId::of(COERCE_NEVER),
reference: "issue #46325 <https://github.com/rust-lang/rust/issues/42869>",
},

]);

Expand Down
11 changes: 10 additions & 1 deletion src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::infer::{Coercion, InferResult, InferOk};
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::lint;
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
use rustc::ty::{self, LvaluePreference, TypeAndMut,
Expand Down Expand Up @@ -754,7 +755,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// type, but only if the source expression diverges.
if target.is_never() && expr_diverges.always() {
debug!("permit coercion to `!` because expr diverges");
return Ok(target);
if self.can_eq(self.param_env, source, target).is_err() {
self.tcx.lint_node(
lint::builtin::COERCE_NEVER,
expr.id,
expr.span,
&format!("cannot coerce `{}` to !", source)
);
return Ok(target);
}
}

let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
Expand Down
3 changes: 3 additions & 0 deletions src/test/compile-fail/coerce-to-bang-cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@

fn foo(x: usize, y: !, z: usize) { }

#[deny(coerce_never)]
fn cast_a() {
let y = {return; 22} as !;
//~^ ERROR cannot coerce `i32` to !
//~| hard error
}

fn cast_b() {
Expand Down
7 changes: 7 additions & 0 deletions src/test/compile-fail/coerce-to-bang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// except according to those terms.

#![feature(never_type)]
#![deny(coerce_never)]

fn foo(x: usize, y: !, z: usize) { }

Expand All @@ -17,6 +18,8 @@ fn call_foo_a() {
// the coercion to `!`, but within same expression. Not clear that
// these are the rules we want.
foo(return, 22, 44);
//~^ ERROR cannot coerce `{integer}` to !
//~| hard error
}

fn call_foo_b() {
Expand All @@ -36,6 +39,8 @@ fn call_foo_d() {
let b = 22;
let c = 44;
foo(a, b, c); // ... and hence a reference to `a` is expected to diverge.
//~^ ERROR cannot coerce `{integer}` to !
//~| hard error
}

fn call_foo_e() {
Expand Down Expand Up @@ -75,6 +80,8 @@ fn tuple_a() {
fn tuple_b() {
// Divergence happens before coercion: OK
let x: (usize, !, usize) = (return, 44, 66);
//~^ ERROR cannot coerce `{integer}` to !
//~| hard error
}

fn tuple_c() {
Expand Down
10 changes: 7 additions & 3 deletions src/test/compile-fail/diverging-fn-tail-35849.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn _converge() -> ! {
42 //~ ERROR mismatched types
#[deny(coerce_never)]
fn assert_sizeof() -> ! {
unsafe {
::std::mem::transmute::<f64, [u8; 8]>(panic!())
//~^ ERROR cannot coerce `[u8; 8]` to !
//~| hard error
}
}

fn main() { }

2 changes: 1 addition & 1 deletion src/test/run-pass/diverging-fn-tail-35849.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[allow(coerce_never)]
fn assert_sizeof() -> ! {
unsafe {
::std::mem::transmute::<f64, [u8; 8]>(panic!())
}
}

fn main() { }

5 changes: 4 additions & 1 deletion src/test/ui/reachable/expr_unary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
#![allow(unused_assignments)]
#![allow(dead_code)]
#![deny(unreachable_code)]
#![deny(coerce_never)]
#![feature(never_type)]

fn foo() {
let x: ! = ! { return; 22 }; //~ ERROR unreachable
//~^ ERROR cannot apply unary operator `!` to type `!`
//~^ ERROR cannot coerce
//~| hard error
//~| ERROR cannot apply unary operator `!` to type `!`
}

fn main() { }
24 changes: 19 additions & 5 deletions src/test/ui/reachable/expr_unary.stderr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
error: unreachable expression
--> $DIR/expr_unary.rs:18:28
--> $DIR/expr_unary.rs:19:28
|
18 | let x: ! = ! { return; 22 }; //~ ERROR unreachable
19 | let x: ! = ! { return; 22 }; //~ ERROR unreachable
| ^^
|
note: lint level defined here
Expand All @@ -10,11 +10,25 @@ note: lint level defined here
14 | #![deny(unreachable_code)]
| ^^^^^^^^^^^^^^^^

error: cannot coerce `{integer}` to !
--> $DIR/expr_unary.rs:19:28
|
19 | let x: ! = ! { return; 22 }; //~ ERROR unreachable
| ^^
|
note: lint level defined here
--> $DIR/expr_unary.rs:15:9
|
15 | #![deny(coerce_never)]
| ^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #46325 <https://github.com/rust-lang/rust/issues/42869>

error[E0600]: cannot apply unary operator `!` to type `!`
--> $DIR/expr_unary.rs:18:16
--> $DIR/expr_unary.rs:19:16
|
18 | let x: ! = ! { return; 22 }; //~ ERROR unreachable
19 | let x: ! = ! { return; 22 }; //~ ERROR unreachable
| ^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

0 comments on commit 8ae7017

Please sign in to comment.