From 235de094ce0d35a550089ce830e2fe65a3c31ffe Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 9 Nov 2017 00:46:15 +0200 Subject: [PATCH] make coercions to `!` in unreachable code a hard error This was added to cover up a lazy extra semicolon in #35849, but does not actually make sense. This is removed as a part of the stabilization of `never_type`. --- src/librustc/lint/builtin.rs | 9 ++++++- src/librustc_lint/lib.rs | 4 ++++ src/librustc_typeck/check/coercion.rs | 11 ++++++++- src/test/compile-fail/coerce-to-bang-cast.rs | 3 +++ src/test/compile-fail/coerce-to-bang.rs | 7 ++++++ .../compile-fail/diverging-fn-tail-35849.rs | 10 +++++--- src/test/run-pass/diverging-fn-tail-35849.rs | 2 +- src/test/ui/reachable/expr_unary.rs | 5 +++- src/test/ui/reachable/expr_unary.stderr | 24 +++++++++++++++---- 9 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index ef4a1c8c39949..1008da1e937a5 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -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)] @@ -263,7 +269,8 @@ impl LintPass for HardwiredLints { LATE_BOUND_LIFETIME_ARGUMENTS, DEPRECATED, UNUSED_UNSAFE, - UNUSED_MUT + UNUSED_MUT, + COERCE_NEVER ) } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index b4d439f0ba809..c352198e8463f 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -247,6 +247,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(SAFE_PACKED_BORROWS), reference: "issue #46043 ", }, + FutureIncompatibleInfo { + id: LintId::of(COERCE_NEVER), + reference: "issue #46325 ", + }, ]); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 94422f93e5922..3e725d7ef415c 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -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, @@ -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); diff --git a/src/test/compile-fail/coerce-to-bang-cast.rs b/src/test/compile-fail/coerce-to-bang-cast.rs index 0479f5cce6537..0d5bf6cd68cb8 100644 --- a/src/test/compile-fail/coerce-to-bang-cast.rs +++ b/src/test/compile-fail/coerce-to-bang-cast.rs @@ -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() { diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index 870665bb49ee6..2cf568777d475 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(never_type)] +#![deny(coerce_never)] fn foo(x: usize, y: !, z: usize) { } @@ -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() { @@ -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() { @@ -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() { diff --git a/src/test/compile-fail/diverging-fn-tail-35849.rs b/src/test/compile-fail/diverging-fn-tail-35849.rs index 3a27c08413328..a91c000bbf712 100644 --- a/src/test/compile-fail/diverging-fn-tail-35849.rs +++ b/src/test/compile-fail/diverging-fn-tail-35849.rs @@ -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::(panic!()) + //~^ ERROR cannot coerce `[u8; 8]` to ! + //~| hard error + } } fn main() { } - diff --git a/src/test/run-pass/diverging-fn-tail-35849.rs b/src/test/run-pass/diverging-fn-tail-35849.rs index 6c05a02e7183c..dfd99bcc9fb47 100644 --- a/src/test/run-pass/diverging-fn-tail-35849.rs +++ b/src/test/run-pass/diverging-fn-tail-35849.rs @@ -8,6 +8,7 @@ // 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::(panic!()) @@ -15,4 +16,3 @@ fn assert_sizeof() -> ! { } fn main() { } - diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs index 6cff3ff964439..ad12cb876fe9b 100644 --- a/src/test/ui/reachable/expr_unary.rs +++ b/src/test/ui/reachable/expr_unary.rs @@ -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() { } diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr index f14824728a70c..710cf79cbe9a7 100644 --- a/src/test/ui/reachable/expr_unary.stderr +++ b/src/test/ui/reachable/expr_unary.stderr @@ -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 @@ -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 + 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