about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-10-28 18:49:46 +0000
committerbors <bors@rust-lang.org>2018-10-28 18:49:46 +0000
commit96064eb61dc703c289fae61bdf90593d3e7b2449 (patch)
tree6c3428593dbec23a6ccf36984d478f154c17e6cb
parentd492c6792c4fa24fb542bf457667f45b55b7c093 (diff)
parent5903fdb28184d465c01cd6247d0e8ce0c4128211 (diff)
downloadrust-96064eb61dc703c289fae61bdf90593d3e7b2449.tar.gz
rust-96064eb61dc703c289fae61bdf90593d3e7b2449.zip
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 https://github.com/rust-lang/rust/pull/53821. Only [the last three commits](https://github.com/oli-obk/rust/compare/sanity_query...RalfJung:ctfe-backtrace) are new.

Fixes https://github.com/rust-lang/rust/issues/53355
-rw-r--r--src/librustc/ich/impls_ty.rs42
-rw-r--r--src/librustc/mir/interpret/error.rs153
-rw-r--r--src/librustc_mir/const_eval.rs20
-rw-r--r--src/librustc_mir/transform/const_prop.rs25
4 files changed, 88 insertions, 152 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 0c38cb10a23..8f837327ddb 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -597,48 +597,6 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
                 required.hash_stable(hcx, hasher);
                 has.hash_stable(hcx, hasher)
             },
-            MemoryLockViolation {
-                ptr,
-                len,
-                frame,
-                access,
-                ref lock,
-            } =>  {
-                ptr.hash_stable(hcx, hasher);
-                len.hash_stable(hcx, hasher);
-                frame.hash_stable(hcx, hasher);
-                access.hash_stable(hcx, hasher);
-                lock.hash_stable(hcx, hasher)
-            },
-            MemoryAcquireConflict {
-                ptr,
-                len,
-                kind,
-                ref lock,
-            } =>  {
-                ptr.hash_stable(hcx, hasher);
-                len.hash_stable(hcx, hasher);
-                kind.hash_stable(hcx, hasher);
-                lock.hash_stable(hcx, hasher)
-            },
-            InvalidMemoryLockRelease {
-                ptr,
-                len,
-                frame,
-                ref lock,
-            } =>  {
-                ptr.hash_stable(hcx, hasher);
-                len.hash_stable(hcx, hasher);
-                frame.hash_stable(hcx, hasher);
-                lock.hash_stable(hcx, hasher)
-            },
-            DeallocatedLockedMemory {
-                ptr,
-                ref lock,
-            } => {
-                ptr.hash_stable(hcx, hasher);
-                lock.hash_stable(hcx, hasher)
-            },
             ValidationFailure(ref s) => s.hash_stable(hcx, hasher),
             TypeNotPrimitive(ty) => ty.hash_stable(hcx, hasher),
             ReallocatedWrongMemoryKind(ref a, ref b) => {
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 2445ce334c0..8e025f0d029 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -15,9 +15,7 @@ use ty::{Ty, layout};
 use ty::layout::{Size, Align, LayoutError};
 use rustc_target::spec::abi::Abi;
 
-use super::{
-    Pointer, Lock, AccessKind
-};
+use super::Pointer;
 
 use backtrace::Backtrace;
 
@@ -53,7 +51,7 @@ pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct ConstEvalErr<'tcx> {
     pub span: Span,
-    pub error: ::mir::interpret::EvalError<'tcx>,
+    pub error: ::mir::interpret::EvalErrorKind<'tcx, u64>,
     pub stacktrace: Vec<FrameInfo>,
 }
 
@@ -112,7 +110,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
         message: &str,
         lint_root: Option<ast::NodeId>,
     ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
-        match self.error.kind {
+        match self.error {
             EvalErrorKind::Layout(LayoutError::Unknown(_)) |
             EvalErrorKind::TooGeneric => return Err(ErrorHandled::TooGeneric),
             EvalErrorKind::Layout(LayoutError::SizeOverflow(_)) |
@@ -151,50 +149,74 @@ pub fn struct_error<'a, 'gcx, 'tcx>(
     struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
 }
 
-#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
+#[derive(Debug, Clone)]
 pub struct EvalError<'tcx> {
     pub kind: EvalErrorKind<'tcx, u64>,
+    pub backtrace: Option<Box<Backtrace>>,
+}
+
+impl<'tcx> EvalError<'tcx> {
+    pub fn print_backtrace(&mut self) {
+        if let Some(ref mut backtrace) = self.backtrace {
+            eprintln!("{}", print_backtrace(&mut *backtrace));
+        }
+    }
+}
+
+fn print_backtrace(backtrace: &mut Backtrace) -> String {
+    use std::fmt::Write;
+
+    backtrace.resolve();
+
+    let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
+    write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap();
+    'frames: for (i, frame) in backtrace.frames().iter().enumerate() {
+        if frame.symbols().is_empty() {
+            write!(trace_text, "{}: no symbols\n", i).unwrap();
+        }
+        for symbol in frame.symbols() {
+            write!(trace_text, "{}: ", i).unwrap();
+            if let Some(name) = symbol.name() {
+                write!(trace_text, "{}\n", name).unwrap();
+            } else {
+                write!(trace_text, "<unknown>\n").unwrap();
+            }
+            write!(trace_text, "\tat ").unwrap();
+            if let Some(file_path) = symbol.filename() {
+                write!(trace_text, "{}", file_path.display()).unwrap();
+            } else {
+                write!(trace_text, "<unknown_file>").unwrap();
+            }
+            if let Some(line) = symbol.lineno() {
+                write!(trace_text, ":{}\n", line).unwrap();
+            } else {
+                write!(trace_text, "\n").unwrap();
+            }
+        }
+    }
+    trace_text
 }
 
 impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
     fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
-        match env::var("MIRI_BACKTRACE") {
-            Ok(ref val) if !val.is_empty() => {
-                let backtrace = Backtrace::new();
+        let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
+            // matching RUST_BACKTRACE, we treat "0" the same as "not present".
+            Ok(ref val) if val != "0" => {
+                let mut backtrace = Backtrace::new_unresolved();
 
-                use std::fmt::Write;
-                let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
-                write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap();
-                'frames: for (i, frame) in backtrace.frames().iter().enumerate() {
-                    if frame.symbols().is_empty() {
-                        write!(trace_text, "{}: no symbols\n", i).unwrap();
-                    }
-                    for symbol in frame.symbols() {
-                        write!(trace_text, "{}: ", i).unwrap();
-                        if let Some(name) = symbol.name() {
-                            write!(trace_text, "{}\n", name).unwrap();
-                        } else {
-                            write!(trace_text, "<unknown>\n").unwrap();
-                        }
-                        write!(trace_text, "\tat ").unwrap();
-                        if let Some(file_path) = symbol.filename() {
-                            write!(trace_text, "{}", file_path.display()).unwrap();
-                        } else {
-                            write!(trace_text, "<unknown_file>").unwrap();
-                        }
-                        if let Some(line) = symbol.lineno() {
-                            write!(trace_text, ":{}\n", line).unwrap();
-                        } else {
-                            write!(trace_text, "\n").unwrap();
-                        }
-                    }
+                if val == "immediate" {
+                    // Print it now
+                    eprintln!("{}", print_backtrace(&mut backtrace));
+                    None
+                } else {
+                    Some(Box::new(backtrace))
                 }
-                error!("{}", trace_text);
             },
-            _ => {},
-        }
+            _ => None,
+        };
         EvalError {
             kind,
+            backtrace,
         }
     }
 }
@@ -250,29 +272,6 @@ pub enum EvalErrorKind<'tcx, O> {
         required: Align,
         has: Align,
     },
-    MemoryLockViolation {
-        ptr: Pointer,
-        len: u64,
-        frame: usize,
-        access: AccessKind,
-        lock: Lock,
-    },
-    MemoryAcquireConflict {
-        ptr: Pointer,
-        len: u64,
-        kind: AccessKind,
-        lock: Lock,
-    },
-    InvalidMemoryLockRelease {
-        ptr: Pointer,
-        len: u64,
-        frame: usize,
-        lock: Lock,
-    },
-    DeallocatedLockedMemory {
-        ptr: Pointer,
-        lock: Lock,
-    },
     ValidationFailure(String),
     CalledClosureAsFunction,
     VtableForArgumentlessMethod,
@@ -336,16 +335,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
                 "pointer offset outside bounds of allocation",
             InvalidNullPointerUsage =>
                 "invalid use of NULL pointer",
-            MemoryLockViolation { .. } =>
-                "memory access conflicts with lock",
-            MemoryAcquireConflict { .. } =>
-                "new memory lock conflicts with existing lock",
             ValidationFailure(..) =>
                 "type validation failed",
-            InvalidMemoryLockRelease { .. } =>
-                "invalid attempt to release write lock",
-            DeallocatedLockedMemory { .. } =>
-                "tried to deallocate memory in conflict with a lock",
             ReadPointerAsBytes =>
                 "a raw memory access tried to access part of a pointer value as raw bytes",
             ReadBytesAsPointer =>
@@ -452,7 +443,13 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
 
 impl<'tcx> fmt::Display for EvalError<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self.kind)
+        write!(f, "{}", self.kind)
+    }
+}
+
+impl<'tcx> fmt::Display for EvalErrorKind<'tcx, u64> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self)
     }
 }
 
@@ -465,22 +462,6 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
                        if access { "memory access" } else { "pointer computed" },
                        ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
             },
-            MemoryLockViolation { ptr, len, frame, access, ref lock } => {
-                write!(f, "{:?} access by frame {} at {:?}, size {}, is in conflict with lock {:?}",
-                       access, frame, ptr, len, lock)
-            }
-            MemoryAcquireConflict { ptr, len, kind, ref lock } => {
-                write!(f, "new {:?} lock at {:?}, size {}, is in conflict with lock {:?}",
-                       kind, ptr, len, lock)
-            }
-            InvalidMemoryLockRelease { ptr, len, frame, ref lock } => {
-                write!(f, "frame {} tried to release memory write lock at {:?}, size {}, but \
-                       cannot release lock {:?}", frame, ptr, len, lock)
-            }
-            DeallocatedLockedMemory { ptr, ref lock } => {
-                write!(f, "tried to deallocate memory at {:?} in conflict with lock {:?}",
-                       ptr, lock)
-            }
             ValidationFailure(ref err) => {
                 write!(f, "type validation failed: {}", err)
             }
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index d9200170428..73cb2038094 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -513,8 +513,7 @@ pub fn const_field<'a, 'tcx>(
         op_to_const(&ecx, field, true)
     })();
     result.map_err(|error| {
-        let stacktrace = ecx.generate_stacktrace(None);
-        let err = ::rustc::mir::interpret::ConstEvalErr { error, stacktrace, span: ecx.tcx.span };
+        let err = error_to_const_error(&ecx, error);
         err.report_as_error(ecx.tcx, "could not access field of constant");
         ErrorHandled::Reported
     })
@@ -532,6 +531,15 @@ pub fn const_variant_index<'a, 'tcx>(
     Ok(ecx.read_discriminant(op)?.1)
 }
 
+pub fn error_to_const_error<'a, 'mir, 'tcx>(
+    ecx: &EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
+    mut error: EvalError<'tcx>
+) -> ConstEvalErr<'tcx> {
+    error.print_backtrace();
+    let stacktrace = ecx.generate_stacktrace(None);
+    ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span }
+}
+
 fn validate_const<'a, 'tcx>(
     tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
     constant: &'tcx ty::Const<'tcx>,
@@ -554,8 +562,7 @@ fn validate_const<'a, 'tcx>(
     })();
 
     val.map_err(|error| {
-        let stacktrace = ecx.generate_stacktrace(None);
-        let err = ::rustc::mir::interpret::ConstEvalErr { error, stacktrace, span: ecx.tcx.span };
+        let err = error_to_const_error(&ecx, error);
         match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
             Ok(mut diag) => {
                 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>(
         }
         op_to_const(&ecx, op, normalize)
     }).map_err(|error| {
-        let stacktrace = ecx.generate_stacktrace(None);
-        let err = ConstEvalErr { error, stacktrace, span: ecx.tcx.span };
+        let err = error_to_const_error(&ecx, error);
         // errors in statics are always emitted as fatal errors
         if tcx.is_static(def_id).is_some() {
             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>(
                 // any other kind of error will be reported to the user as a deny-by-default lint
                 _ => if let Some(p) = cid.promoted {
                     let span = tcx.optimized_mir(def_id).promoted[p].span;
-                    if let EvalErrorKind::ReferencedConstant = err.error.kind {
+                    if let EvalErrorKind::ReferencedConstant = err.error {
                         err.report_as_error(
                             tcx.at(span),
                             "evaluation of constant expression failed",
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 052c6032dec..8ee009db023 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -17,13 +17,8 @@ use rustc::mir::{Constant, Location, Place, Mir, Operand, Rvalue, Local};
 use rustc::mir::{NullOp, UnOp, StatementKind, Statement, BasicBlock, LocalKind};
 use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
 use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
-use rustc::mir::interpret::{
-    ConstEvalErr, EvalErrorKind, Scalar, GlobalId, EvalResult,
-};
+use rustc::mir::interpret::{EvalErrorKind, Scalar, GlobalId, EvalResult};
 use rustc::ty::{TyCtxt, self, Instance};
-use interpret::{self, EvalContext, Value, OpTy, MemoryKind, ScalarMaybeUndef};
-use const_eval::{CompileTimeInterpreter, eval_promoted, mk_borrowck_eval_cx};
-use transform::{MirPass, MirSource};
 use syntax::source_map::{Span, DUMMY_SP};
 use rustc::ty::subst::Substs;
 use rustc_data_structures::indexed_vec::IndexVec;
@@ -33,6 +28,10 @@ use rustc::ty::layout::{
     HasTyCtxt, TargetDataLayout, HasDataLayout,
 };
 
+use interpret::{self, EvalContext, ScalarMaybeUndef, Value, OpTy, MemoryKind};
+use const_eval::{CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_borrowck_eval_cx};
+use transform::{MirPass, MirSource};
+
 pub struct ConstProp;
 
 impl MirPass for ConstProp {
@@ -154,10 +153,9 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
         let r = match f(self) {
             Ok(val) => Some(val),
             Err(error) => {
-                let stacktrace = self.ecx.generate_stacktrace(None);
-                let diagnostic = ConstEvalErr { span: source_info.span, error, stacktrace };
+                let diagnostic = error_to_const_error(&self.ecx, error);
                 use rustc::mir::interpret::EvalErrorKind::*;
-                match diagnostic.error.kind {
+                match diagnostic.error {
                     // don't report these, they make no sense in a const prop context
                     | MachineError(_)
                     // at runtime these transformations might make sense
@@ -185,11 +183,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
                     | InvalidDiscriminant(..)
                     | PointerOutOfBounds { .. }
                     | InvalidNullPointerUsage
-                    | MemoryLockViolation { .. }
-                    | MemoryAcquireConflict { .. }
                     | ValidationFailure(..)
-                    | InvalidMemoryLockRelease { .. }
-                    | DeallocatedLockedMemory { .. }
                     | InvalidPointerMath
                     | ReadUndefBytes(_)
                     | DeadLocal
@@ -273,10 +267,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
                 Some((op, c.span))
             },
             Err(error) => {
-                let stacktrace = self.ecx.generate_stacktrace(None);
-                let err = ::rustc::mir::interpret::ConstEvalErr {
-                    error, stacktrace, span: source_info.span,
-                };
+                let err = error_to_const_error(&self.ecx, error);
                 err.report_as_error(self.ecx.tcx, "erroneous constant used");
                 None
             },