Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 02a4238

Browse files
committedOct 28, 2018
rename env var to control ctfe backtraces, and make it usually show the backtrace delayed
The env var is now RUST_CTFE_BACKTRACE. Similar to RUST_BACKTRACE, it usually only prints a backtrace when the error actually surfaces, not when it happens. This makes a difference when we catch errors. As per @oli-obk's request, one can set RUST_CTFE_BACKTRACE=immediate to get the backtrace shown immediately.
1 parent 1982f18 commit 02a4238

File tree

3 files changed

+87
-56
lines changed

3 files changed

+87
-56
lines changed
 

‎src/librustc/mir/interpret/error.rs

Lines changed: 66 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
5353
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
5454
pub struct ConstEvalErr<'tcx> {
5555
pub span: Span,
56-
pub error: ::mir::interpret::EvalError<'tcx>,
56+
pub error: ::mir::interpret::EvalErrorKind<'tcx, u64>,
5757
pub stacktrace: Vec<FrameInfo>,
5858
}
5959

@@ -112,7 +112,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
112112
message: &str,
113113
lint_root: Option<ast::NodeId>,
114114
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
115-
match self.error.kind {
115+
match self.error {
116116
EvalErrorKind::Layout(LayoutError::Unknown(_)) |
117117
EvalErrorKind::TooGeneric => return Err(ErrorHandled::TooGeneric),
118118
EvalErrorKind::Layout(LayoutError::SizeOverflow(_)) |
@@ -151,50 +151,74 @@ pub fn struct_error<'a, 'gcx, 'tcx>(
151151
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
152152
}
153153

154-
#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
154+
#[derive(Debug, Clone)]
155155
pub struct EvalError<'tcx> {
156156
pub kind: EvalErrorKind<'tcx, u64>,
157+
pub backtrace: Option<Box<Backtrace>>,
158+
}
159+
160+
impl<'tcx> EvalError<'tcx> {
161+
pub fn print_backtrace(&mut self) {
162+
if let Some(ref mut backtrace) = self.backtrace {
163+
error!("{}", print_backtrace(&mut *backtrace));
164+
}
165+
}
166+
}
167+
168+
fn print_backtrace(backtrace: &mut Backtrace) -> String {
169+
use std::fmt::Write;
170+
171+
backtrace.resolve();
172+
173+
let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
174+
write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap();
175+
'frames: for (i, frame) in backtrace.frames().iter().enumerate() {
176+
if frame.symbols().is_empty() {
177+
write!(trace_text, "{}: no symbols\n", i).unwrap();
178+
}
179+
for symbol in frame.symbols() {
180+
write!(trace_text, "{}: ", i).unwrap();
181+
if let Some(name) = symbol.name() {
182+
write!(trace_text, "{}\n", name).unwrap();
183+
} else {
184+
write!(trace_text, "<unknown>\n").unwrap();
185+
}
186+
write!(trace_text, "\tat ").unwrap();
187+
if let Some(file_path) = symbol.filename() {
188+
write!(trace_text, "{}", file_path.display()).unwrap();
189+
} else {
190+
write!(trace_text, "<unknown_file>").unwrap();
191+
}
192+
if let Some(line) = symbol.lineno() {
193+
write!(trace_text, ":{}\n", line).unwrap();
194+
} else {
195+
write!(trace_text, "\n").unwrap();
196+
}
197+
}
198+
}
199+
trace_text
157200
}
158201

159202
impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
160203
fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
161-
match env::var("MIRI_BACKTRACE") {
162-
Ok(ref val) if !val.is_empty() => {
163-
let backtrace = Backtrace::new();
204+
let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
205+
// matching RUST_BACKTRACE, we treat "0" the same as "not present".
206+
Ok(ref val) if val != "0" => {
207+
let mut backtrace = Backtrace::new_unresolved();
164208

165-
use std::fmt::Write;
166-
let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
167-
write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap();
168-
'frames: for (i, frame) in backtrace.frames().iter().enumerate() {
169-
if frame.symbols().is_empty() {
170-
write!(trace_text, "{}: no symbols\n", i).unwrap();
171-
}
172-
for symbol in frame.symbols() {
173-
write!(trace_text, "{}: ", i).unwrap();
174-
if let Some(name) = symbol.name() {
175-
write!(trace_text, "{}\n", name).unwrap();
176-
} else {
177-
write!(trace_text, "<unknown>\n").unwrap();
178-
}
179-
write!(trace_text, "\tat ").unwrap();
180-
if let Some(file_path) = symbol.filename() {
181-
write!(trace_text, "{}", file_path.display()).unwrap();
182-
} else {
183-
write!(trace_text, "<unknown_file>").unwrap();
184-
}
185-
if let Some(line) = symbol.lineno() {
186-
write!(trace_text, ":{}\n", line).unwrap();
187-
} else {
188-
write!(trace_text, "\n").unwrap();
189-
}
190-
}
209+
if val == "immediate" {
210+
// Print it now
211+
error!("{}", print_backtrace(&mut backtrace));
212+
None
213+
} else {
214+
Some(Box::new(backtrace))
191215
}
192-
error!("{}", trace_text);
193216
},
194-
_ => {},
195-
}
217+
_ => None,
218+
};
196219
EvalError {
197220
kind,
221+
backtrace,
198222
}
199223
}
200224
}
@@ -452,7 +476,13 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
452476

453477
impl<'tcx> fmt::Display for EvalError<'tcx> {
454478
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455-
write!(f, "{:?}", self.kind)
479+
write!(f, "{}", self.kind)
480+
}
481+
}
482+
483+
impl<'tcx> fmt::Display for EvalErrorKind<'tcx, u64> {
484+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485+
write!(f, "{:?}", self)
456486
}
457487
}
458488

‎src/librustc_mir/const_eval.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -513,8 +513,7 @@ pub fn const_field<'a, 'tcx>(
513513
op_to_const(&ecx, field, true)
514514
})();
515515
result.map_err(|error| {
516-
let stacktrace = ecx.generate_stacktrace(None);
517-
let err = ::rustc::mir::interpret::ConstEvalErr { error, stacktrace, span: ecx.tcx.span };
516+
let err = error_to_const_error(&ecx, error);
518517
err.report_as_error(ecx.tcx, "could not access field of constant");
519518
ErrorHandled::Reported
520519
})
@@ -532,6 +531,15 @@ pub fn const_variant_index<'a, 'tcx>(
532531
Ok(ecx.read_discriminant(op)?.1)
533532
}
534533

534+
pub fn error_to_const_error<'a, 'mir, 'tcx>(
535+
ecx: &EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
536+
mut error: EvalError<'tcx>
537+
) -> ConstEvalErr<'tcx> {
538+
error.print_backtrace();
539+
let stacktrace = ecx.generate_stacktrace(None);
540+
ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span }
541+
}
542+
535543
fn validate_const<'a, 'tcx>(
536544
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
537545
constant: &'tcx ty::Const<'tcx>,
@@ -554,8 +562,7 @@ fn validate_const<'a, 'tcx>(
554562
})();
555563

556564
val.map_err(|error| {
557-
let stacktrace = ecx.generate_stacktrace(None);
558-
let err = ::rustc::mir::interpret::ConstEvalErr { error, stacktrace, span: ecx.tcx.span };
565+
let err = error_to_const_error(&ecx, error);
559566
match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
560567
Ok(mut diag) => {
561568
diag.note("The rules on what exactly is undefined behavior aren't clear, \
@@ -647,8 +654,7 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
647654
}
648655
op_to_const(&ecx, op, normalize)
649656
}).map_err(|error| {
650-
let stacktrace = ecx.generate_stacktrace(None);
651-
let err = ConstEvalErr { error, stacktrace, span: ecx.tcx.span };
657+
let err = error_to_const_error(&ecx, error);
652658
// errors in statics are always emitted as fatal errors
653659
if tcx.is_static(def_id).is_some() {
654660
let err = err.report_as_error(ecx.tcx, "could not evaluate static initializer");
@@ -678,7 +684,7 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
678684
// any other kind of error will be reported to the user as a deny-by-default lint
679685
_ => if let Some(p) = cid.promoted {
680686
let span = tcx.optimized_mir(def_id).promoted[p].span;
681-
if let EvalErrorKind::ReferencedConstant = err.error.kind {
687+
if let EvalErrorKind::ReferencedConstant = err.error {
682688
err.report_as_error(
683689
tcx.at(span),
684690
"evaluation of constant expression failed",

‎src/librustc_mir/transform/const_prop.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,8 @@ use rustc::mir::{Constant, Location, Place, Mir, Operand, Rvalue, Local};
1717
use rustc::mir::{NullOp, UnOp, StatementKind, Statement, BasicBlock, LocalKind};
1818
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
1919
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
20-
use rustc::mir::interpret::{
21-
ConstEvalErr, EvalErrorKind, Scalar, GlobalId, EvalResult,
22-
};
20+
use rustc::mir::interpret::{EvalErrorKind, Scalar, GlobalId, EvalResult};
2321
use rustc::ty::{TyCtxt, self, Instance};
24-
use interpret::{self, EvalContext, Value, OpTy, MemoryKind, ScalarMaybeUndef};
25-
use const_eval::{CompileTimeInterpreter, eval_promoted, mk_borrowck_eval_cx};
26-
use transform::{MirPass, MirSource};
2722
use syntax::source_map::{Span, DUMMY_SP};
2823
use rustc::ty::subst::Substs;
2924
use rustc_data_structures::indexed_vec::IndexVec;
@@ -33,6 +28,10 @@ use rustc::ty::layout::{
3328
HasTyCtxt, TargetDataLayout, HasDataLayout,
3429
};
3530

31+
use interpret::{self, EvalContext, ScalarMaybeUndef, Value, OpTy, MemoryKind};
32+
use const_eval::{CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_borrowck_eval_cx};
33+
use transform::{MirPass, MirSource};
34+
3635
pub struct ConstProp;
3736

3837
impl MirPass for ConstProp {
@@ -154,10 +153,9 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
154153
let r = match f(self) {
155154
Ok(val) => Some(val),
156155
Err(error) => {
157-
let stacktrace = self.ecx.generate_stacktrace(None);
158-
let diagnostic = ConstEvalErr { span: source_info.span, error, stacktrace };
156+
let diagnostic = error_to_const_error(&self.ecx, error);
159157
use rustc::mir::interpret::EvalErrorKind::*;
160-
match diagnostic.error.kind {
158+
match diagnostic.error {
161159
// don't report these, they make no sense in a const prop context
162160
| MachineError(_)
163161
// at runtime these transformations might make sense
@@ -273,10 +271,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
273271
Some((op, c.span))
274272
},
275273
Err(error) => {
276-
let stacktrace = self.ecx.generate_stacktrace(None);
277-
let err = ::rustc::mir::interpret::ConstEvalErr {
278-
error, stacktrace, span: source_info.span,
279-
};
274+
let err = error_to_const_error(&self.ecx, error);
280275
err.report_as_error(self.ecx.tcx, "erroneous constant used");
281276
None
282277
},

0 commit comments

Comments
 (0)
Please sign in to comment.