From df26968bb57a0ac9dc71f1cc7b9191229db82182 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 8 Dec 2019 01:55:14 +0100 Subject: [PATCH 1/2] Ensure that we get a hard error on generic ZST constants if their body causes an error during evaluation --- src/librustc_codegen_ssa/mir/constant.rs | 9 ++++++++- src/librustc_mir/transform/simplify.rs | 13 +++++++++---- .../ui/consts/assoc_const_generic_impl.rs | 19 +++++++++++++++++++ .../ui/consts/assoc_const_generic_impl.stderr | 8 ++++++++ 4 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/consts/assoc_const_generic_impl.rs create mode 100644 src/test/ui/consts/assoc_const_generic_impl.stderr diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 27891be6b82c5..fb8f504d04b10 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -16,6 +16,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant: &mir::Constant<'tcx>, ) -> Result, ErrorHandled> { match constant.literal.val { + // Special case unevaluated statics, because statics have an identity and thus should + // use `get_static` to get at their id. + // FIXME(oli-obk): can we unify this somehow, maybe by making const eval of statics + // always produce `&STATIC`. This may also simplify how const eval works with statics. ty::ConstKind::Unevaluated(def_id, substs) if self.cx.tcx().is_static(def_id) => { assert!(substs.is_empty(), "we don't support generic statics yet"); @@ -46,7 +50,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { instance, promoted: None, }; - self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid)) + self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid)).map_err(|err| { + self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered"); + err + }) }, _ => Ok(self.monomorphize(&constant.literal)), } diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 900752d3ce06c..6ce77a3057a0a 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -29,7 +29,7 @@ use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; -use rustc::ty::TyCtxt; +use rustc::ty::{self, TyCtxt}; use rustc::mir::*; use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext, MutatingUseContext}; use std::borrow::Cow; @@ -367,9 +367,14 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> { if let StatementKind::Assign( box (p, Rvalue::Use(Operand::Constant(c))) ) = &stmt.kind { - if !p.is_indirect() { - trace!("skipping store of const value {:?} to {:?}", c, p); - return; + match c.literal.val { + // Keep assignments from unevaluated constants around, since the evaluation + // may report errors, even if the use of the constant is dead code. + ty::ConstKind::Unevaluated(..) => {} + _ => if !p.is_indirect() { + trace!("skipping store of const value {:?} to {:?}", c, p); + return; + }, } } } diff --git a/src/test/ui/consts/assoc_const_generic_impl.rs b/src/test/ui/consts/assoc_const_generic_impl.rs new file mode 100644 index 0000000000000..cce0cdbf8c559 --- /dev/null +++ b/src/test/ui/consts/assoc_const_generic_impl.rs @@ -0,0 +1,19 @@ +#![allow(const_err)] + +trait ZeroSized: Sized { + const I_AM_ZERO_SIZED: (); + fn requires_zero_size(self); +} + +impl ZeroSized for T { + const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; + fn requires_zero_size(self) { + let () = Self::I_AM_ZERO_SIZED; //~ ERROR erroneous constant encountered + println!("requires_zero_size called"); + } +} + +fn main() { + ().requires_zero_size(); + 42_u32.requires_zero_size(); +} diff --git a/src/test/ui/consts/assoc_const_generic_impl.stderr b/src/test/ui/consts/assoc_const_generic_impl.stderr new file mode 100644 index 0000000000000..3765a3703c7fc --- /dev/null +++ b/src/test/ui/consts/assoc_const_generic_impl.stderr @@ -0,0 +1,8 @@ +error: erroneous constant encountered + --> $DIR/assoc_const_generic_impl.rs:11:18 + | +LL | let () = Self::I_AM_ZERO_SIZED; + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From d2ed209699b169808293223f6a3b83e755fdf708 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 8 Dec 2019 21:50:23 +0000 Subject: [PATCH 2/2] Ensure that unevaluated constants of type `!` are present in the MIR --- src/librustc_mir/build/expr/into.rs | 9 +++++- src/test/mir-opt/retain-never-const.rs | 28 +++++++++++++++++++ .../index-out-of-bounds-never-type.rs | 18 ++++++++++++ .../index-out-of-bounds-never-type.stderr | 22 +++++++++++++++ .../const-eval/panic-assoc-never-type.rs | 15 ++++++++++ .../const-eval/panic-assoc-never-type.stderr | 24 ++++++++++++++++ .../ui/consts/const-eval/panic-never-type.rs | 11 ++++++++ .../consts/const-eval/panic-never-type.stderr | 24 ++++++++++++++++ 8 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 src/test/mir-opt/retain-never-const.rs create mode 100644 src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs create mode 100644 src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr create mode 100644 src/test/ui/consts/const-eval/panic-assoc-never-type.rs create mode 100644 src/test/ui/consts/const-eval/panic-assoc-never-type.stderr create mode 100644 src/test/ui/consts/const-eval/panic-never-type.rs create mode 100644 src/test/ui/consts/const-eval/panic-never-type.stderr diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index f5dc09ccebc1e..07a44b190b20a 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -65,7 +65,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => false, }; - unpack!(block = this.as_local_rvalue(block, source)); + // (#66975) Source could be a const of type `!`, so has to + // exist in the generated MIR. + unpack!(block = this.as_temp( + block, + this.local_scope(), + source, + Mutability::Mut, + )); // This is an optimization. If the expression was a call then we already have an // unreachable block. Don't bother to terminate it and create a new one. diff --git a/src/test/mir-opt/retain-never-const.rs b/src/test/mir-opt/retain-never-const.rs new file mode 100644 index 0000000000000..5d59b2f48429d --- /dev/null +++ b/src/test/mir-opt/retain-never-const.rs @@ -0,0 +1,28 @@ +// Regression test for #66975 - ensure that we don't keep unevaluated +// `!`-typed constants until codegen. + +// Force generation of optimized mir for functions that do not reach codegen. +// compile-flags: --emit mir,link + +#![feature(const_panic)] + +struct PrintName(T); + +impl PrintName { + const VOID: ! = panic!(); +} + +fn no_codegen() { + let _ = PrintName::::VOID; +} + +fn main() {} + +// END RUST SOURCE +// START rustc.no_codegen.PreCodegen.after.mir +// bb0: { +// StorageLive(_1); +// _1 = const PrintName::::VOID; +// unreachable; +// } +// END rustc.no_codegen.PreCodegen.after.mir diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs new file mode 100644 index 0000000000000..516ca4f3f77e0 --- /dev/null +++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs @@ -0,0 +1,18 @@ +// Regression test for #66975 +#![warn(const_err)] + +struct PrintName(T); + +impl PrintName { + const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; + //~^ WARN any use of this value will cause an error +} + +fn f() { + let _ = PrintName::::VOID; + //~^ ERROR erroneous constant encountered +} + +pub fn main() { + f::<()>(); +} diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr new file mode 100644 index 0000000000000..e2bd8d0cc85ea --- /dev/null +++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr @@ -0,0 +1,22 @@ +warning: any use of this value will cause an error + --> $DIR/index-out-of-bounds-never-type.rs:7:61 + | +LL | const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; + | --------------------------------------------------------^^^^^--- + | | + | index out of bounds: the len is 0 but the index is 0 + | +note: lint level defined here + --> $DIR/index-out-of-bounds-never-type.rs:2:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + +error: erroneous constant encountered + --> $DIR/index-out-of-bounds-never-type.rs:12:13 + | +LL | let _ = PrintName::::VOID; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs new file mode 100644 index 0000000000000..b39d9af5546f8 --- /dev/null +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs @@ -0,0 +1,15 @@ +// Regression test for #66975 +#![warn(const_err)] +#![feature(const_panic)] + +struct PrintName; + +impl PrintName { + const VOID: ! = panic!(); + //~^ WARN any use of this value will cause an error +} + +fn main() { + let _ = PrintName::VOID; + //~^ ERROR erroneous constant used +} diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr new file mode 100644 index 0000000000000..c07c8c65a2f20 --- /dev/null +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr @@ -0,0 +1,24 @@ +warning: any use of this value will cause an error + --> $DIR/panic-assoc-never-type.rs:8:21 + | +LL | const VOID: ! = panic!(); + | ----------------^^^^^^^^- + | | + | the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:8:21 + | +note: lint level defined here + --> $DIR/panic-assoc-never-type.rs:2:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0080]: erroneous constant used + --> $DIR/panic-assoc-never-type.rs:13:13 + | +LL | let _ = PrintName::VOID; + | ^^^^^^^^^^^^^^^ referenced constant has errors + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/panic-never-type.rs b/src/test/ui/consts/const-eval/panic-never-type.rs new file mode 100644 index 0000000000000..42eabbf58470f --- /dev/null +++ b/src/test/ui/consts/const-eval/panic-never-type.rs @@ -0,0 +1,11 @@ +// Regression test for #66975 +#![warn(const_err)] +#![feature(const_panic)] + +const VOID: ! = panic!(); +//~^ WARN any use of this value will cause an error + +fn main() { + let _ = VOID; + //~^ ERROR erroneous constant used +} diff --git a/src/test/ui/consts/const-eval/panic-never-type.stderr b/src/test/ui/consts/const-eval/panic-never-type.stderr new file mode 100644 index 0000000000000..4fb11a61525f4 --- /dev/null +++ b/src/test/ui/consts/const-eval/panic-never-type.stderr @@ -0,0 +1,24 @@ +warning: any use of this value will cause an error + --> $DIR/panic-never-type.rs:5:17 + | +LL | const VOID: ! = panic!(); + | ----------------^^^^^^^^- + | | + | the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:5:17 + | +note: lint level defined here + --> $DIR/panic-never-type.rs:2:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error[E0080]: erroneous constant used + --> $DIR/panic-never-type.rs:9:13 + | +LL | let _ = VOID; + | ^^^^ referenced constant has errors + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`.