Skip to content

Commit 96064eb

Browse files
committed
Auto merge of #54487 - RalfJung:ctfe-backtrace, r=oli-obk
Delayed CTFE backtraces This renames the env var that controls CTFE backtraces from `MIRI_BACKTRACE` to `RUST_CTFE_BACKTRACE` so that we can use `MIRI_BACKTRACE` in the miri tool to only show backtraces of the main miri execution. It also makes `RUST_CTFE_BACKTRACE` only show backtraces that actually get rendered as errors, instead of showing them eagerly when the `Err` happens. The current behavior is near useless in miri because it shows about one gazillion backtraces for errors that we later catch and do not care about. However, @oli-obk likes the current behavior for rustc CTFE work so it is still available via `RUST_CTFE_BACKTRACE=immediate`. NOTE: This is based on top of #53821. Only [the last three commits](oli-obk/rust@sanity_query...RalfJung:ctfe-backtrace) are new. Fixes #53355
2 parents d492c67 + 5903fdb commit 96064eb

File tree

4 files changed

+88
-152
lines changed

4 files changed

+88
-152
lines changed

src/librustc/ich/impls_ty.rs

-42
Original file line numberDiff line numberDiff line change
@@ -597,48 +597,6 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
597597
required.hash_stable(hcx, hasher);
598598
has.hash_stable(hcx, hasher)
599599
},
600-
MemoryLockViolation {
601-
ptr,
602-
len,
603-
frame,
604-
access,
605-
ref lock,
606-
} => {
607-
ptr.hash_stable(hcx, hasher);
608-
len.hash_stable(hcx, hasher);
609-
frame.hash_stable(hcx, hasher);
610-
access.hash_stable(hcx, hasher);
611-
lock.hash_stable(hcx, hasher)
612-
},
613-
MemoryAcquireConflict {
614-
ptr,
615-
len,
616-
kind,
617-
ref lock,
618-
} => {
619-
ptr.hash_stable(hcx, hasher);
620-
len.hash_stable(hcx, hasher);
621-
kind.hash_stable(hcx, hasher);
622-
lock.hash_stable(hcx, hasher)
623-
},
624-
InvalidMemoryLockRelease {
625-
ptr,
626-
len,
627-
frame,
628-
ref lock,
629-
} => {
630-
ptr.hash_stable(hcx, hasher);
631-
len.hash_stable(hcx, hasher);
632-
frame.hash_stable(hcx, hasher);
633-
lock.hash_stable(hcx, hasher)
634-
},
635-
DeallocatedLockedMemory {
636-
ptr,
637-
ref lock,
638-
} => {
639-
ptr.hash_stable(hcx, hasher);
640-
lock.hash_stable(hcx, hasher)
641-
},
642600
ValidationFailure(ref s) => s.hash_stable(hcx, hasher),
643601
TypeNotPrimitive(ty) => ty.hash_stable(hcx, hasher),
644602
ReallocatedWrongMemoryKind(ref a, ref b) => {

src/librustc/mir/interpret/error.rs

+67-86
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ use ty::{Ty, layout};
1515
use ty::layout::{Size, Align, LayoutError};
1616
use rustc_target::spec::abi::Abi;
1717

18-
use super::{
19-
Pointer, Lock, AccessKind
20-
};
18+
use super::Pointer;
2119

2220
use backtrace::Backtrace;
2321

@@ -53,7 +51,7 @@ pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
5351
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
5452
pub struct ConstEvalErr<'tcx> {
5553
pub span: Span,
56-
pub error: ::mir::interpret::EvalError<'tcx>,
54+
pub error: ::mir::interpret::EvalErrorKind<'tcx, u64>,
5755
pub stacktrace: Vec<FrameInfo>,
5856
}
5957

@@ -112,7 +110,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
112110
message: &str,
113111
lint_root: Option<ast::NodeId>,
114112
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
115-
match self.error.kind {
113+
match self.error {
116114
EvalErrorKind::Layout(LayoutError::Unknown(_)) |
117115
EvalErrorKind::TooGeneric => return Err(ErrorHandled::TooGeneric),
118116
EvalErrorKind::Layout(LayoutError::SizeOverflow(_)) |
@@ -151,50 +149,74 @@ pub fn struct_error<'a, 'gcx, 'tcx>(
151149
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
152150
}
153151

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

159200
impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
160201
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();
202+
let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
203+
// matching RUST_BACKTRACE, we treat "0" the same as "not present".
204+
Ok(ref val) if val != "0" => {
205+
let mut backtrace = Backtrace::new_unresolved();
164206

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-
}
207+
if val == "immediate" {
208+
// Print it now
209+
eprintln!("{}", print_backtrace(&mut backtrace));
210+
None
211+
} else {
212+
Some(Box::new(backtrace))
191213
}
192-
error!("{}", trace_text);
193214
},
194-
_ => {},
195-
}
215+
_ => None,
216+
};
196217
EvalError {
197218
kind,
219+
backtrace,
198220
}
199221
}
200222
}
@@ -250,29 +272,6 @@ pub enum EvalErrorKind<'tcx, O> {
250272
required: Align,
251273
has: Align,
252274
},
253-
MemoryLockViolation {
254-
ptr: Pointer,
255-
len: u64,
256-
frame: usize,
257-
access: AccessKind,
258-
lock: Lock,
259-
},
260-
MemoryAcquireConflict {
261-
ptr: Pointer,
262-
len: u64,
263-
kind: AccessKind,
264-
lock: Lock,
265-
},
266-
InvalidMemoryLockRelease {
267-
ptr: Pointer,
268-
len: u64,
269-
frame: usize,
270-
lock: Lock,
271-
},
272-
DeallocatedLockedMemory {
273-
ptr: Pointer,
274-
lock: Lock,
275-
},
276275
ValidationFailure(String),
277276
CalledClosureAsFunction,
278277
VtableForArgumentlessMethod,
@@ -336,16 +335,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
336335
"pointer offset outside bounds of allocation",
337336
InvalidNullPointerUsage =>
338337
"invalid use of NULL pointer",
339-
MemoryLockViolation { .. } =>
340-
"memory access conflicts with lock",
341-
MemoryAcquireConflict { .. } =>
342-
"new memory lock conflicts with existing lock",
343338
ValidationFailure(..) =>
344339
"type validation failed",
345-
InvalidMemoryLockRelease { .. } =>
346-
"invalid attempt to release write lock",
347-
DeallocatedLockedMemory { .. } =>
348-
"tried to deallocate memory in conflict with a lock",
349340
ReadPointerAsBytes =>
350341
"a raw memory access tried to access part of a pointer value as raw bytes",
351342
ReadBytesAsPointer =>
@@ -452,7 +443,13 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
452443

453444
impl<'tcx> fmt::Display for EvalError<'tcx> {
454445
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455-
write!(f, "{:?}", self.kind)
446+
write!(f, "{}", self.kind)
447+
}
448+
}
449+
450+
impl<'tcx> fmt::Display for EvalErrorKind<'tcx, u64> {
451+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
452+
write!(f, "{:?}", self)
456453
}
457454
}
458455

@@ -465,22 +462,6 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
465462
if access { "memory access" } else { "pointer computed" },
466463
ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
467464
},
468-
MemoryLockViolation { ptr, len, frame, access, ref lock } => {
469-
write!(f, "{:?} access by frame {} at {:?}, size {}, is in conflict with lock {:?}",
470-
access, frame, ptr, len, lock)
471-
}
472-
MemoryAcquireConflict { ptr, len, kind, ref lock } => {
473-
write!(f, "new {:?} lock at {:?}, size {}, is in conflict with lock {:?}",
474-
kind, ptr, len, lock)
475-
}
476-
InvalidMemoryLockRelease { ptr, len, frame, ref lock } => {
477-
write!(f, "frame {} tried to release memory write lock at {:?}, size {}, but \
478-
cannot release lock {:?}", frame, ptr, len, lock)
479-
}
480-
DeallocatedLockedMemory { ptr, ref lock } => {
481-
write!(f, "tried to deallocate memory at {:?} in conflict with lock {:?}",
482-
ptr, lock)
483-
}
484465
ValidationFailure(ref err) => {
485466
write!(f, "type validation failed: {}", err)
486467
}

src/librustc_mir/const_eval.rs

+13-7
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, \
@@ -654,8 +661,7 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
654661
}
655662
op_to_const(&ecx, op, normalize)
656663
}).map_err(|error| {
657-
let stacktrace = ecx.generate_stacktrace(None);
658-
let err = ConstEvalErr { error, stacktrace, span: ecx.tcx.span };
664+
let err = error_to_const_error(&ecx, error);
659665
// errors in statics are always emitted as fatal errors
660666
if tcx.is_static(def_id).is_some() {
661667
let err = err.report_as_error(ecx.tcx, "could not evaluate static initializer");
@@ -685,7 +691,7 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
685691
// any other kind of error will be reported to the user as a deny-by-default lint
686692
_ => if let Some(p) = cid.promoted {
687693
let span = tcx.optimized_mir(def_id).promoted[p].span;
688-
if let EvalErrorKind::ReferencedConstant = err.error.kind {
694+
if let EvalErrorKind::ReferencedConstant = err.error {
689695
err.report_as_error(
690696
tcx.at(span),
691697
"evaluation of constant expression failed",

src/librustc_mir/transform/const_prop.rs

+8-17
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
@@ -185,11 +183,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
185183
| InvalidDiscriminant(..)
186184
| PointerOutOfBounds { .. }
187185
| InvalidNullPointerUsage
188-
| MemoryLockViolation { .. }
189-
| MemoryAcquireConflict { .. }
190186
| ValidationFailure(..)
191-
| InvalidMemoryLockRelease { .. }
192-
| DeallocatedLockedMemory { .. }
193187
| InvalidPointerMath
194188
| ReadUndefBytes(_)
195189
| DeadLocal
@@ -273,10 +267,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
273267
Some((op, c.span))
274268
},
275269
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-
};
270+
let err = error_to_const_error(&self.ecx, error);
280271
err.report_as_error(self.ecx.tcx, "erroneous constant used");
281272
None
282273
},

0 commit comments

Comments
 (0)