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 c1434716c1dc67f8c96b488121a9b91163516aa3 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 9 Dec 2019 13:05:41 +0100 Subject: [PATCH 2/2] Show const_err lint in addition to the hard error --- src/test/ui/consts/assoc_const_generic_impl.rs | 4 ++-- src/test/ui/consts/assoc_const_generic_impl.stderr | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/test/ui/consts/assoc_const_generic_impl.rs b/src/test/ui/consts/assoc_const_generic_impl.rs index cce0cdbf8c559..62702a8ec5cb1 100644 --- a/src/test/ui/consts/assoc_const_generic_impl.rs +++ b/src/test/ui/consts/assoc_const_generic_impl.rs @@ -1,4 +1,4 @@ -#![allow(const_err)] +#![warn(const_err)] trait ZeroSized: Sized { const I_AM_ZERO_SIZED: (); @@ -6,7 +6,7 @@ trait ZeroSized: Sized { } impl ZeroSized for T { - const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; + const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; //~ WARN any use of this value fn requires_zero_size(self) { let () = Self::I_AM_ZERO_SIZED; //~ ERROR erroneous constant encountered println!("requires_zero_size called"); diff --git a/src/test/ui/consts/assoc_const_generic_impl.stderr b/src/test/ui/consts/assoc_const_generic_impl.stderr index 3765a3703c7fc..a114d5c6ccd14 100644 --- a/src/test/ui/consts/assoc_const_generic_impl.stderr +++ b/src/test/ui/consts/assoc_const_generic_impl.stderr @@ -1,3 +1,17 @@ +warning: any use of this value will cause an error + --> $DIR/assoc_const_generic_impl.rs:9:34 + | +LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; + | -----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | index out of bounds: the len is 1 but the index is 4 + | +note: lint level defined here + --> $DIR/assoc_const_generic_impl.rs:1:9 + | +LL | #![warn(const_err)] + | ^^^^^^^^^ + error: erroneous constant encountered --> $DIR/assoc_const_generic_impl.rs:11:18 |