Skip to content

Commit d538b80

Browse files
committed
Auto merge of #68969 - RalfJung:dont-panic, r=oli-obk
remove Panic variant from InterpError The interpreter engine itself does not raise `Panic` errors any more, so remove them from the error enum. Instead, const-prop and const-eval have to do their own handling of panics. I used the opportunity to refactor the const-eval error handling a bit to use the `MachineStop` variant. Also, in const-prop I could do some cleanup as now, no more lints are being reported in `use_ecx`. However, I am quite puzzled by why exactly the linting there works the way it does -- the code can certainly be cleaned up more, but I don't know enough of the intent to do that. I left some questions for the most confusing parts, but for now behavior should be unchanged by this PR (so, all that weirdness I am asking about is pre-existing and merely maintained here). Cc @wesleywiser Fixes #66902 r? @oli-obk
2 parents be493fe + 33ba83c commit d538b80

File tree

17 files changed

+271
-274
lines changed

17 files changed

+271
-274
lines changed

src/librustc/mir/interpret/error.rs

+51-95
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ use crate::ty::query::TyCtxtAt;
77
use crate::ty::{self, layout, Ty};
88

99
use backtrace::Backtrace;
10-
use hir::GeneratorKind;
1110
use rustc_errors::{struct_span_err, DiagnosticBuilder};
1211
use rustc_hir as hir;
1312
use rustc_macros::HashStable;
14-
use rustc_span::symbol::Symbol;
1513
use rustc_span::{Pos, Span};
1614
use rustc_target::spec::abi::Abi;
1715
use std::{any::Any, env, fmt};
@@ -128,9 +126,15 @@ impl<'tcx> ConstEvalErr<'tcx> {
128126
}
129127
}
130128

131-
/// Sets the message passed in via `message` and adds span labels before handing control back
132-
/// to `emit` to do any final processing. It's the caller's responsibility to call emit(),
133-
/// stash(), etc. within the `emit` function to dispose of the diagnostic properly.
129+
/// Create a diagnostic for this const eval error.
130+
///
131+
/// Sets the message passed in via `message` and adds span labels with detailed error
132+
/// information before handing control back to `emit` to do any final processing.
133+
/// It's the caller's responsibility to call emit(), stash(), etc. within the `emit`
134+
/// function to dispose of the diagnostic properly.
135+
///
136+
/// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
137+
/// (Except that for some errors, we ignore all that -- see `must_error` below.)
134138
fn struct_generic(
135139
&self,
136140
tcx: TyCtxtAt<'tcx>,
@@ -139,20 +143,30 @@ impl<'tcx> ConstEvalErr<'tcx> {
139143
lint_root: Option<hir::HirId>,
140144
) -> Result<(), ErrorHandled> {
141145
let must_error = match self.error {
142-
InterpError::MachineStop(_) => bug!("CTFE does not stop"),
143146
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
144147
return Err(ErrorHandled::TooGeneric);
145148
}
146149
err_inval!(TypeckError) => return Err(ErrorHandled::Reported),
150+
// We must *always* hard error on these, even if the caller wants just a lint.
147151
err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
148152
_ => false,
149153
};
150154
trace!("reporting const eval failure at {:?}", self.span);
151155

152-
let add_span_labels = |err: &mut DiagnosticBuilder<'_>| {
153-
if !must_error {
154-
err.span_label(self.span, self.error.to_string());
156+
let err_msg = match &self.error {
157+
InterpError::MachineStop(msg) => {
158+
// A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
159+
// Should be turned into a string by now.
160+
msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
155161
}
162+
err => err.to_string(),
163+
};
164+
165+
let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
166+
if let Some(span_msg) = span_msg {
167+
err.span_label(self.span, span_msg);
168+
}
169+
// Add spans for the stacktrace.
156170
// Skip the last, which is just the environment of the constant. The stacktrace
157171
// is sometimes empty because we create "fake" eval contexts in CTFE to do work
158172
// on constant values.
@@ -161,35 +175,37 @@ impl<'tcx> ConstEvalErr<'tcx> {
161175
err.span_label(frame_info.call_site, frame_info.to_string());
162176
}
163177
}
178+
// Let the caller finish the job.
179+
emit(err)
164180
};
165181

166-
if let (Some(lint_root), false) = (lint_root, must_error) {
167-
let hir_id = self
168-
.stacktrace
169-
.iter()
170-
.rev()
171-
.filter_map(|frame| frame.lint_root)
172-
.next()
173-
.unwrap_or(lint_root);
174-
tcx.struct_span_lint_hir(
175-
rustc_session::lint::builtin::CONST_ERR,
176-
hir_id,
177-
tcx.span,
178-
|lint| {
179-
let mut err = lint.build(message);
180-
add_span_labels(&mut err);
181-
emit(err);
182-
},
183-
);
182+
if must_error {
183+
// The `message` makes little sense here, this is a more serious error than the
184+
// caller thinks anyway.
185+
// See <https://github.com/rust-lang/rust/pull/63152>.
186+
finish(struct_error(tcx, &err_msg), None);
184187
} else {
185-
let mut err = if must_error {
186-
struct_error(tcx, &self.error.to_string())
188+
// Regular case.
189+
if let Some(lint_root) = lint_root {
190+
// Report as lint.
191+
let hir_id = self
192+
.stacktrace
193+
.iter()
194+
.rev()
195+
.filter_map(|frame| frame.lint_root)
196+
.next()
197+
.unwrap_or(lint_root);
198+
tcx.struct_span_lint_hir(
199+
rustc_session::lint::builtin::CONST_ERR,
200+
hir_id,
201+
tcx.span,
202+
|lint| finish(lint.build(message), Some(err_msg)),
203+
);
187204
} else {
188-
struct_error(tcx, message)
189-
};
190-
add_span_labels(&mut err);
191-
emit(err);
192-
};
205+
// Report as hard error.
206+
finish(struct_error(tcx, message), Some(err_msg));
207+
}
208+
}
193209
Ok(())
194210
}
195211
}
@@ -259,63 +275,6 @@ impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
259275
}
260276
}
261277

262-
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
263-
pub enum PanicInfo<O> {
264-
Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
265-
BoundsCheck { len: O, index: O },
266-
Overflow(mir::BinOp),
267-
OverflowNeg,
268-
DivisionByZero,
269-
RemainderByZero,
270-
ResumedAfterReturn(GeneratorKind),
271-
ResumedAfterPanic(GeneratorKind),
272-
}
273-
274-
/// Type for MIR `Assert` terminator error messages.
275-
pub type AssertMessage<'tcx> = PanicInfo<mir::Operand<'tcx>>;
276-
277-
impl<O> PanicInfo<O> {
278-
/// Getting a description does not require `O` to be printable, and does not
279-
/// require allocation.
280-
/// The caller is expected to handle `Panic` and `BoundsCheck` separately.
281-
pub fn description(&self) -> &'static str {
282-
use PanicInfo::*;
283-
match self {
284-
Overflow(mir::BinOp::Add) => "attempt to add with overflow",
285-
Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
286-
Overflow(mir::BinOp::Mul) => "attempt to multiply with overflow",
287-
Overflow(mir::BinOp::Div) => "attempt to divide with overflow",
288-
Overflow(mir::BinOp::Rem) => "attempt to calculate the remainder with overflow",
289-
OverflowNeg => "attempt to negate with overflow",
290-
Overflow(mir::BinOp::Shr) => "attempt to shift right with overflow",
291-
Overflow(mir::BinOp::Shl) => "attempt to shift left with overflow",
292-
Overflow(op) => bug!("{:?} cannot overflow", op),
293-
DivisionByZero => "attempt to divide by zero",
294-
RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
295-
ResumedAfterReturn(GeneratorKind::Gen) => "generator resumed after completion",
296-
ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion",
297-
ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking",
298-
ResumedAfterPanic(GeneratorKind::Async(_)) => "`async fn` resumed after panicking",
299-
Panic { .. } | BoundsCheck { .. } => bug!("Unexpected PanicInfo"),
300-
}
301-
}
302-
}
303-
304-
impl<O: fmt::Debug> fmt::Debug for PanicInfo<O> {
305-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306-
use PanicInfo::*;
307-
match self {
308-
Panic { ref msg, line, col, ref file } => {
309-
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col)
310-
}
311-
BoundsCheck { ref len, ref index } => {
312-
write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index)
313-
}
314-
_ => write!(f, "{}", self.description()),
315-
}
316-
}
317-
}
318-
319278
/// Error information for when the program we executed turned out not to actually be a valid
320279
/// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
321280
/// where we work on generic code or execution does not have all information available.
@@ -616,8 +575,6 @@ impl fmt::Debug for ResourceExhaustionInfo {
616575
}
617576

618577
pub enum InterpError<'tcx> {
619-
/// The program panicked.
620-
Panic(PanicInfo<u64>),
621578
/// The program caused undefined behavior.
622579
UndefinedBehavior(UndefinedBehaviorInfo),
623580
/// The program did something the interpreter does not support (some of these *might* be UB
@@ -650,8 +607,7 @@ impl fmt::Debug for InterpError<'_> {
650607
InvalidProgram(ref msg) => write!(f, "{:?}", msg),
651608
UndefinedBehavior(ref msg) => write!(f, "{:?}", msg),
652609
ResourceExhaustion(ref msg) => write!(f, "{:?}", msg),
653-
Panic(ref msg) => write!(f, "{:?}", msg),
654-
MachineStop(_) => write!(f, "machine caused execution to stop"),
610+
MachineStop(_) => bug!("unhandled MachineStop"),
655611
}
656612
}
657613
}

src/librustc/mir/interpret/mod.rs

+3-17
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,6 @@ macro_rules! err_ub_format {
3737
($($tt:tt)*) => { err_ub!(Ub(format!($($tt)*))) };
3838
}
3939

40-
#[macro_export]
41-
macro_rules! err_panic {
42-
($($tt:tt)*) => {
43-
$crate::mir::interpret::InterpError::Panic(
44-
$crate::mir::interpret::PanicInfo::$($tt)*
45-
)
46-
};
47-
}
48-
4940
#[macro_export]
5041
macro_rules! err_exhaust {
5142
($($tt:tt)*) => {
@@ -80,11 +71,6 @@ macro_rules! throw_ub_format {
8071
($($tt:tt)*) => { throw_ub!(Ub(format!($($tt)*))) };
8172
}
8273

83-
#[macro_export]
84-
macro_rules! throw_panic {
85-
($($tt:tt)*) => { return Err(err_panic!($($tt)*).into()) };
86-
}
87-
8874
#[macro_export]
8975
macro_rules! throw_exhaust {
9076
($($tt:tt)*) => { return Err(err_exhaust!($($tt)*).into()) };
@@ -104,9 +90,9 @@ mod queries;
10490
mod value;
10591

10692
pub use self::error::{
107-
struct_error, AssertMessage, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled,
108-
FrameInfo, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, PanicInfo,
109-
ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo,
93+
struct_error, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled, FrameInfo,
94+
InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, ResourceExhaustionInfo,
95+
UndefinedBehaviorInfo, UnsupportedOpInfo,
11096
};
11197

11298
pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUndef};

src/librustc/mir/mod.rs

+59-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/mir/index.html
44
5-
use crate::mir::interpret::{GlobalAlloc, PanicInfo, Scalar};
5+
use crate::mir::interpret::{GlobalAlloc, Scalar};
66
use crate::mir::visit::MirVisitable;
77
use crate::ty::adjustment::PointerCast;
88
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
@@ -36,7 +36,6 @@ pub use syntax::ast::Mutability;
3636
use syntax::ast::Name;
3737

3838
pub use self::cache::{BodyAndCache, ReadOnlyBodyAndCache};
39-
pub use self::interpret::AssertMessage;
4039
pub use self::query::*;
4140
pub use crate::read_only;
4241

@@ -1154,6 +1153,21 @@ pub enum TerminatorKind<'tcx> {
11541153
},
11551154
}
11561155

1156+
/// Information about an assertion failure.
1157+
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
1158+
pub enum AssertKind<O> {
1159+
BoundsCheck { len: O, index: O },
1160+
Overflow(BinOp),
1161+
OverflowNeg,
1162+
DivisionByZero,
1163+
RemainderByZero,
1164+
ResumedAfterReturn(GeneratorKind),
1165+
ResumedAfterPanic(GeneratorKind),
1166+
}
1167+
1168+
/// Type for MIR `Assert` terminator error messages.
1169+
pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
1170+
11571171
pub type Successors<'a> =
11581172
iter::Chain<option::IntoIter<&'a BasicBlock>, slice::Iter<'a, BasicBlock>>;
11591173
pub type SuccessorsMut<'a> =
@@ -1383,6 +1397,45 @@ impl<'tcx> BasicBlockData<'tcx> {
13831397
}
13841398
}
13851399

1400+
impl<O> AssertKind<O> {
1401+
/// Getting a description does not require `O` to be printable, and does not
1402+
/// require allocation.
1403+
/// The caller is expected to handle `BoundsCheck` separately.
1404+
pub fn description(&self) -> &'static str {
1405+
use AssertKind::*;
1406+
match self {
1407+
Overflow(BinOp::Add) => "attempt to add with overflow",
1408+
Overflow(BinOp::Sub) => "attempt to subtract with overflow",
1409+
Overflow(BinOp::Mul) => "attempt to multiply with overflow",
1410+
Overflow(BinOp::Div) => "attempt to divide with overflow",
1411+
Overflow(BinOp::Rem) => "attempt to calculate the remainder with overflow",
1412+
OverflowNeg => "attempt to negate with overflow",
1413+
Overflow(BinOp::Shr) => "attempt to shift right with overflow",
1414+
Overflow(BinOp::Shl) => "attempt to shift left with overflow",
1415+
Overflow(op) => bug!("{:?} cannot overflow", op),
1416+
DivisionByZero => "attempt to divide by zero",
1417+
RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
1418+
ResumedAfterReturn(GeneratorKind::Gen) => "generator resumed after completion",
1419+
ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion",
1420+
ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking",
1421+
ResumedAfterPanic(GeneratorKind::Async(_)) => "`async fn` resumed after panicking",
1422+
BoundsCheck { .. } => bug!("Unexpected AssertKind"),
1423+
}
1424+
}
1425+
}
1426+
1427+
impl<O: fmt::Debug> fmt::Debug for AssertKind<O> {
1428+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1429+
use AssertKind::*;
1430+
match self {
1431+
BoundsCheck { ref len, ref index } => {
1432+
write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index)
1433+
}
1434+
_ => write!(f, "{}", self.description()),
1435+
}
1436+
}
1437+
}
1438+
13861439
impl<'tcx> Debug for TerminatorKind<'tcx> {
13871440
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
13881441
self.fmt_head(fmt)?;
@@ -2666,13 +2719,12 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
26662719
}
26672720
}
26682721
Assert { ref cond, expected, ref msg, target, cleanup } => {
2669-
use PanicInfo::*;
2722+
use AssertKind::*;
26702723
let msg = match msg {
26712724
BoundsCheck { ref len, ref index } => {
26722725
BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
26732726
}
2674-
Panic { .. }
2675-
| Overflow(_)
2727+
Overflow(_)
26762728
| OverflowNeg
26772729
| DivisionByZero
26782730
| RemainderByZero
@@ -2716,13 +2768,12 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
27162768
}
27172769
Assert { ref cond, ref msg, .. } => {
27182770
if cond.visit_with(visitor) {
2719-
use PanicInfo::*;
2771+
use AssertKind::*;
27202772
match msg {
27212773
BoundsCheck { ref len, ref index } => {
27222774
len.visit_with(visitor) || index.visit_with(visitor)
27232775
}
2724-
Panic { .. }
2725-
| Overflow(_)
2776+
Overflow(_)
27262777
| OverflowNeg
27272778
| DivisionByZero
27282779
| RemainderByZero

src/librustc/mir/visit.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -533,13 +533,13 @@ macro_rules! make_mir_visitor {
533533
fn super_assert_message(&mut self,
534534
msg: & $($mutability)? AssertMessage<'tcx>,
535535
location: Location) {
536-
use crate::mir::interpret::PanicInfo::*;
536+
use crate::mir::AssertKind::*;
537537
match msg {
538538
BoundsCheck { len, index } => {
539539
self.visit_operand(len, location);
540540
self.visit_operand(index, location);
541541
}
542-
Panic { .. } | Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
542+
Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
543543
ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
544544
// Nothing to visit
545545
}

0 commit comments

Comments
 (0)