diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index b2b615d29a5b..ef30b1e45223 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -143,7 +143,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(expr) = expr { unpack!(block = this.into(destination, block, expr)); } else { - this.cfg.push_assign_unit(block, source_info, destination); + // If a block has no trailing expression, then it is given an implicit return type. + // This return type is usually `()`, unless the block is diverging, in which case the + // return type is `!`. For the unit type, we need to actually return the unit, but in + // the case of `!`, no return value is required, as the block will never return. + let tcx = this.hir.tcx(); + let ty = destination.ty(&this.local_decls, tcx).to_ty(tcx); + if ty.is_nil() { + // We only want to assign an implicit `()` as the return value of the block if the + // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.) + this.cfg.push_assign_unit(block, source_info, destination); + } } // Finally, we pop all the let scopes before exiting out from the scope of block // itself. diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 3e0ccc7d0726..68b23d1ae17e 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -272,7 +272,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::InlineAsm { .. } | - ExprKind::Return {.. } => { + ExprKind::Return { .. } => { unpack!(block = this.stmt_expr(block, expr)); this.cfg.push_assign_unit(block, source_info, destination); block.unit() diff --git a/src/test/run-pass/never-type-rvalues.rs b/src/test/run-pass/never-type-rvalues.rs new file mode 100644 index 000000000000..bda288f40869 --- /dev/null +++ b/src/test/run-pass/never-type-rvalues.rs @@ -0,0 +1,46 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(never_type)] +#![allow(dead_code)] +#![allow(path_statements)] +#![allow(unreachable_patterns)] + +fn never_direct(x: !) { + x; +} + +fn never_ref_pat(ref x: !) { + *x; +} + +fn never_ref(x: &!) { + let &y = x; + y; +} + +fn never_pointer(x: *const !) { + unsafe { + *x; + } +} + +fn never_slice(x: &[!]) { + x[0]; +} + +fn never_match(x: Result<(), !>) { + match x { + Ok(_) => {}, + Err(_) => {}, + } +} + +pub fn main() { }