Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure that panicking in constants eventually errors #67164

Merged
merged 2 commits into from
Dec 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/librustc_codegen_ssa/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
constant: &mir::Constant<'tcx>,
) -> Result<OperandRef<'tcx, Bx::Value>, 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");
Expand Down Expand Up @@ -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)),
}
Expand Down
9 changes: 8 additions & 1 deletion src/librustc_mir/build/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
13 changes: 9 additions & 4 deletions src/librustc_mir/transform/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
},
}
}
}
Expand Down
28 changes: 28 additions & 0 deletions src/test/mir-opt/retain-never-const.rs
Original file line number Diff line number Diff line change
@@ -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>(T);

impl<T> PrintName<T> {
const VOID: ! = panic!();
}

fn no_codegen<T>() {
let _ = PrintName::<T>::VOID;
}

fn main() {}

// END RUST SOURCE
// START rustc.no_codegen.PreCodegen.after.mir
// bb0: {
// StorageLive(_1);
// _1 = const PrintName::<T>::VOID;
// unreachable;
// }
// END rustc.no_codegen.PreCodegen.after.mir
19 changes: 19 additions & 0 deletions src/test/ui/consts/assoc_const_generic_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#![allow(const_err)]

trait ZeroSized: Sized {
const I_AM_ZERO_SIZED: ();
fn requires_zero_size(self);
}

impl<T: Sized> ZeroSized for T {
const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::<Self>()];
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();
}
8 changes: 8 additions & 0 deletions src/test/ui/consts/assoc_const_generic_impl.stderr
Original file line number Diff line number Diff line change
@@ -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

18 changes: 18 additions & 0 deletions src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Regression test for #66975
#![warn(const_err)]

struct PrintName<T>(T);

impl<T> PrintName<T> {
const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
//~^ WARN any use of this value will cause an error
}

fn f<T>() {
let _ = PrintName::<T>::VOID;
//~^ ERROR erroneous constant encountered
}

pub fn main() {
f::<()>();
}
Original file line number Diff line number Diff line change
@@ -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::<T>(); [][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::<T>::VOID;
| ^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

15 changes: 15 additions & 0 deletions src/test/ui/consts/const-eval/panic-assoc-never-type.rs
Original file line number Diff line number Diff line change
@@ -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
}
24 changes: 24 additions & 0 deletions src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
Original file line number Diff line number Diff line change
@@ -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`.
11 changes: 11 additions & 0 deletions src/test/ui/consts/const-eval/panic-never-type.rs
Original file line number Diff line number Diff line change
@@ -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
}
24 changes: 24 additions & 0 deletions src/test/ui/consts/const-eval/panic-never-type.stderr
Original file line number Diff line number Diff line change
@@ -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`.