move const_eval error reporting logic into rustc_mir::const_eval::error
This commit is contained in:
parent
8e738539be
commit
bff69c9525
7 changed files with 201 additions and 194 deletions
|
@ -1,17 +1,13 @@
|
||||||
use super::{AllocId, Pointer, RawConst, Scalar};
|
use super::{AllocId, Pointer, RawConst, Scalar};
|
||||||
|
|
||||||
use crate::mir::interpret::ConstValue;
|
use crate::mir::interpret::ConstValue;
|
||||||
use crate::ty::layout::LayoutError;
|
use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty};
|
||||||
use crate::ty::query::TyCtxtAt;
|
|
||||||
use crate::ty::{self, layout, tls, FnSig, Ty};
|
|
||||||
|
|
||||||
use rustc_data_structures::sync::Lock;
|
use rustc_data_structures::sync::Lock;
|
||||||
use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorReported};
|
use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorReported};
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_hir::definitions::DefPathData;
|
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
use rustc_session::CtfeBacktrace;
|
use rustc_session::CtfeBacktrace;
|
||||||
use rustc_span::{def_id::DefId, Pos, Span};
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::{Align, Size};
|
||||||
use std::{any::Any, backtrace::Backtrace, fmt, mem};
|
use std::{any::Any, backtrace::Backtrace, fmt, mem};
|
||||||
|
|
||||||
|
@ -34,167 +30,6 @@ CloneTypeFoldableAndLiftImpls! {
|
||||||
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
|
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
|
||||||
pub type ConstEvalResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
|
pub type ConstEvalResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ConstEvalErr<'tcx> {
|
|
||||||
pub span: Span,
|
|
||||||
pub error: crate::mir::interpret::InterpError<'tcx>,
|
|
||||||
pub stacktrace: Vec<FrameInfo<'tcx>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct FrameInfo<'tcx> {
|
|
||||||
pub instance: ty::Instance<'tcx>,
|
|
||||||
pub span: Span,
|
|
||||||
pub lint_root: Option<hir::HirId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> fmt::Display for FrameInfo<'tcx> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
ty::tls::with(|tcx| {
|
|
||||||
if tcx.def_key(self.instance.def_id()).disambiguated_data.data
|
|
||||||
== DefPathData::ClosureExpr
|
|
||||||
{
|
|
||||||
write!(f, "inside closure")?;
|
|
||||||
} else {
|
|
||||||
write!(f, "inside `{}`", self.instance)?;
|
|
||||||
}
|
|
||||||
if !self.span.is_dummy() {
|
|
||||||
let lo = tcx.sess.source_map().lookup_char_pos(self.span.lo());
|
|
||||||
write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> ConstEvalErr<'tcx> {
|
|
||||||
pub fn struct_error(
|
|
||||||
&self,
|
|
||||||
tcx: TyCtxtAt<'tcx>,
|
|
||||||
message: &str,
|
|
||||||
emit: impl FnOnce(DiagnosticBuilder<'_>),
|
|
||||||
) -> ErrorHandled {
|
|
||||||
self.struct_generic(tcx, message, emit, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
|
|
||||||
self.struct_error(tcx, message, |mut e| e.emit())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn report_as_lint(
|
|
||||||
&self,
|
|
||||||
tcx: TyCtxtAt<'tcx>,
|
|
||||||
message: &str,
|
|
||||||
lint_root: hir::HirId,
|
|
||||||
span: Option<Span>,
|
|
||||||
) -> ErrorHandled {
|
|
||||||
self.struct_generic(
|
|
||||||
tcx,
|
|
||||||
message,
|
|
||||||
|mut lint: DiagnosticBuilder<'_>| {
|
|
||||||
// Apply the span.
|
|
||||||
if let Some(span) = span {
|
|
||||||
let primary_spans = lint.span.primary_spans().to_vec();
|
|
||||||
// point at the actual error as the primary span
|
|
||||||
lint.replace_span_with(span);
|
|
||||||
// point to the `const` statement as a secondary span
|
|
||||||
// they don't have any label
|
|
||||||
for sp in primary_spans {
|
|
||||||
if sp != span {
|
|
||||||
lint.span_label(sp, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lint.emit();
|
|
||||||
},
|
|
||||||
Some(lint_root),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a diagnostic for this const eval error.
|
|
||||||
///
|
|
||||||
/// Sets the message passed in via `message` and adds span labels with detailed error
|
|
||||||
/// information before handing control back to `emit` to do any final processing.
|
|
||||||
/// It's the caller's responsibility to call emit(), stash(), etc. within the `emit`
|
|
||||||
/// function to dispose of the diagnostic properly.
|
|
||||||
///
|
|
||||||
/// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
|
|
||||||
/// (Except that for some errors, we ignore all that -- see `must_error` below.)
|
|
||||||
fn struct_generic(
|
|
||||||
&self,
|
|
||||||
tcx: TyCtxtAt<'tcx>,
|
|
||||||
message: &str,
|
|
||||||
emit: impl FnOnce(DiagnosticBuilder<'_>),
|
|
||||||
lint_root: Option<hir::HirId>,
|
|
||||||
) -> ErrorHandled {
|
|
||||||
let must_error = match self.error {
|
|
||||||
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
|
|
||||||
return ErrorHandled::TooGeneric;
|
|
||||||
}
|
|
||||||
err_inval!(TypeckError(error_reported)) => {
|
|
||||||
return ErrorHandled::Reported(error_reported);
|
|
||||||
}
|
|
||||||
// We must *always* hard error on these, even if the caller wants just a lint.
|
|
||||||
err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
trace!("reporting const eval failure at {:?}", self.span);
|
|
||||||
|
|
||||||
let err_msg = match &self.error {
|
|
||||||
InterpError::MachineStop(msg) => {
|
|
||||||
// A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
|
|
||||||
// Should be turned into a string by now.
|
|
||||||
msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
|
|
||||||
}
|
|
||||||
err => err.to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
|
|
||||||
if let Some(span_msg) = span_msg {
|
|
||||||
err.span_label(self.span, span_msg);
|
|
||||||
}
|
|
||||||
// Add spans for the stacktrace. Don't print a single-line backtrace though.
|
|
||||||
if self.stacktrace.len() > 1 {
|
|
||||||
for frame_info in &self.stacktrace {
|
|
||||||
err.span_label(frame_info.span, frame_info.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Let the caller finish the job.
|
|
||||||
emit(err)
|
|
||||||
};
|
|
||||||
|
|
||||||
if must_error {
|
|
||||||
// The `message` makes little sense here, this is a more serious error than the
|
|
||||||
// caller thinks anyway.
|
|
||||||
// See <https://github.com/rust-lang/rust/pull/63152>.
|
|
||||||
finish(struct_error(tcx, &err_msg), None);
|
|
||||||
ErrorHandled::Reported(ErrorReported)
|
|
||||||
} else {
|
|
||||||
// Regular case.
|
|
||||||
if let Some(lint_root) = lint_root {
|
|
||||||
// Report as lint.
|
|
||||||
let hir_id = self
|
|
||||||
.stacktrace
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.find_map(|frame| frame.lint_root)
|
|
||||||
.unwrap_or(lint_root);
|
|
||||||
tcx.struct_span_lint_hir(
|
|
||||||
rustc_session::lint::builtin::CONST_ERR,
|
|
||||||
hir_id,
|
|
||||||
tcx.span,
|
|
||||||
|lint| finish(lint.build(message), Some(err_msg)),
|
|
||||||
);
|
|
||||||
ErrorHandled::Linted
|
|
||||||
} else {
|
|
||||||
// Report as hard error.
|
|
||||||
finish(struct_error(tcx, message), Some(err_msg));
|
|
||||||
ErrorHandled::Reported(ErrorReported)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
|
pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
|
||||||
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
|
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,9 +117,9 @@ use crate::ty::subst::GenericArgKind;
|
||||||
use crate::ty::{self, Instance, Ty, TyCtxt};
|
use crate::ty::{self, Instance, Ty, TyCtxt};
|
||||||
|
|
||||||
pub use self::error::{
|
pub use self::error::{
|
||||||
struct_error, CheckInAllocMsg, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled,
|
struct_error, CheckInAllocMsg, ConstEvalRawResult, ConstEvalResult, ErrorHandled, InterpError,
|
||||||
FrameInfo, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
|
InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, ResourceExhaustionInfo,
|
||||||
ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
|
UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit};
|
pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit};
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use rustc_errors::{DiagnosticBuilder, ErrorReported};
|
||||||
|
use rustc_hir as hir;
|
||||||
use rustc_middle::mir::AssertKind;
|
use rustc_middle::mir::AssertKind;
|
||||||
use rustc_middle::ty::ConstInt;
|
use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt};
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
|
|
||||||
use super::InterpCx;
|
use super::InterpCx;
|
||||||
use crate::interpret::{ConstEvalErr, InterpErrorInfo, Machine};
|
use crate::interpret::{
|
||||||
|
struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine,
|
||||||
|
};
|
||||||
|
|
||||||
/// The CTFE machine has some custom error kinds.
|
/// The CTFE machine has some custom error kinds.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -48,15 +52,155 @@ impl fmt::Display for ConstEvalErrKind {
|
||||||
|
|
||||||
impl Error for ConstEvalErrKind {}
|
impl Error for ConstEvalErrKind {}
|
||||||
|
|
||||||
/// Turn an interpreter error into something to report to the user.
|
/// When const-evaluation errors, this type is constructed with the resulting information,
|
||||||
/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
|
/// and then used to emit the error as a lint or hard error.
|
||||||
/// Should be called only if the error is actually going to to be reported!
|
#[derive(Debug)]
|
||||||
pub fn error_to_const_error<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>(
|
pub struct ConstEvalErr<'tcx> {
|
||||||
ecx: &InterpCx<'mir, 'tcx, M>,
|
pub span: Span,
|
||||||
error: InterpErrorInfo<'tcx>,
|
pub error: InterpError<'tcx>,
|
||||||
span: Option<Span>,
|
pub stacktrace: Vec<FrameInfo<'tcx>>,
|
||||||
) -> ConstEvalErr<'tcx> {
|
}
|
||||||
error.print_backtrace();
|
|
||||||
let stacktrace = ecx.generate_stacktrace();
|
impl<'tcx> ConstEvalErr<'tcx> {
|
||||||
ConstEvalErr { error: error.kind, stacktrace, span: span.unwrap_or_else(|| ecx.cur_span()) }
|
/// Turn an interpreter error into something to report to the user.
|
||||||
|
/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
|
||||||
|
/// Should be called only if the error is actually going to to be reported!
|
||||||
|
pub fn new<'mir, M: Machine<'mir, 'tcx>>(
|
||||||
|
ecx: &InterpCx<'mir, 'tcx, M>,
|
||||||
|
error: InterpErrorInfo<'tcx>,
|
||||||
|
span: Option<Span>,
|
||||||
|
) -> ConstEvalErr<'tcx>
|
||||||
|
where
|
||||||
|
'tcx: 'mir,
|
||||||
|
{
|
||||||
|
error.print_backtrace();
|
||||||
|
let stacktrace = ecx.generate_stacktrace();
|
||||||
|
ConstEvalErr { error: error.kind, stacktrace, span: span.unwrap_or_else(|| ecx.cur_span()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn struct_error(
|
||||||
|
&self,
|
||||||
|
tcx: TyCtxtAt<'tcx>,
|
||||||
|
message: &str,
|
||||||
|
emit: impl FnOnce(DiagnosticBuilder<'_>),
|
||||||
|
) -> ErrorHandled {
|
||||||
|
self.struct_generic(tcx, message, emit, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
|
||||||
|
self.struct_error(tcx, message, |mut e| e.emit())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report_as_lint(
|
||||||
|
&self,
|
||||||
|
tcx: TyCtxtAt<'tcx>,
|
||||||
|
message: &str,
|
||||||
|
lint_root: hir::HirId,
|
||||||
|
span: Option<Span>,
|
||||||
|
) -> ErrorHandled {
|
||||||
|
self.struct_generic(
|
||||||
|
tcx,
|
||||||
|
message,
|
||||||
|
|mut lint: DiagnosticBuilder<'_>| {
|
||||||
|
// Apply the span.
|
||||||
|
if let Some(span) = span {
|
||||||
|
let primary_spans = lint.span.primary_spans().to_vec();
|
||||||
|
// point at the actual error as the primary span
|
||||||
|
lint.replace_span_with(span);
|
||||||
|
// point to the `const` statement as a secondary span
|
||||||
|
// they don't have any label
|
||||||
|
for sp in primary_spans {
|
||||||
|
if sp != span {
|
||||||
|
lint.span_label(sp, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lint.emit();
|
||||||
|
},
|
||||||
|
Some(lint_root),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a diagnostic for this const eval error.
|
||||||
|
///
|
||||||
|
/// Sets the message passed in via `message` and adds span labels with detailed error
|
||||||
|
/// information before handing control back to `emit` to do any final processing.
|
||||||
|
/// It's the caller's responsibility to call emit(), stash(), etc. within the `emit`
|
||||||
|
/// function to dispose of the diagnostic properly.
|
||||||
|
///
|
||||||
|
/// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
|
||||||
|
/// (Except that for some errors, we ignore all that -- see `must_error` below.)
|
||||||
|
fn struct_generic(
|
||||||
|
&self,
|
||||||
|
tcx: TyCtxtAt<'tcx>,
|
||||||
|
message: &str,
|
||||||
|
emit: impl FnOnce(DiagnosticBuilder<'_>),
|
||||||
|
lint_root: Option<hir::HirId>,
|
||||||
|
) -> ErrorHandled {
|
||||||
|
let must_error = match self.error {
|
||||||
|
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
|
||||||
|
return ErrorHandled::TooGeneric;
|
||||||
|
}
|
||||||
|
err_inval!(TypeckError(error_reported)) => {
|
||||||
|
return ErrorHandled::Reported(error_reported);
|
||||||
|
}
|
||||||
|
// We must *always* hard error on these, even if the caller wants just a lint.
|
||||||
|
err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
trace!("reporting const eval failure at {:?}", self.span);
|
||||||
|
|
||||||
|
let err_msg = match &self.error {
|
||||||
|
InterpError::MachineStop(msg) => {
|
||||||
|
// A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
|
||||||
|
// Should be turned into a string by now.
|
||||||
|
msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
|
||||||
|
}
|
||||||
|
err => err.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
|
||||||
|
if let Some(span_msg) = span_msg {
|
||||||
|
err.span_label(self.span, span_msg);
|
||||||
|
}
|
||||||
|
// Add spans for the stacktrace. Don't print a single-line backtrace though.
|
||||||
|
if self.stacktrace.len() > 1 {
|
||||||
|
for frame_info in &self.stacktrace {
|
||||||
|
err.span_label(frame_info.span, frame_info.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Let the caller finish the job.
|
||||||
|
emit(err)
|
||||||
|
};
|
||||||
|
|
||||||
|
if must_error {
|
||||||
|
// The `message` makes little sense here, this is a more serious error than the
|
||||||
|
// caller thinks anyway.
|
||||||
|
// See <https://github.com/rust-lang/rust/pull/63152>.
|
||||||
|
finish(struct_error(tcx, &err_msg), None);
|
||||||
|
ErrorHandled::Reported(ErrorReported)
|
||||||
|
} else {
|
||||||
|
// Regular case.
|
||||||
|
if let Some(lint_root) = lint_root {
|
||||||
|
// Report as lint.
|
||||||
|
let hir_id = self
|
||||||
|
.stacktrace
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.find_map(|frame| frame.lint_root)
|
||||||
|
.unwrap_or(lint_root);
|
||||||
|
tcx.struct_span_lint_hir(
|
||||||
|
rustc_session::lint::builtin::CONST_ERR,
|
||||||
|
hir_id,
|
||||||
|
tcx.span,
|
||||||
|
|lint| finish(lint.build(message), Some(err_msg)),
|
||||||
|
);
|
||||||
|
ErrorHandled::Linted
|
||||||
|
} else {
|
||||||
|
// Report as hard error.
|
||||||
|
finish(struct_error(tcx, message), Some(err_msg));
|
||||||
|
ErrorHandled::Reported(ErrorReported)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use super::{error_to_const_error, CompileTimeEvalContext, CompileTimeInterpreter, MemoryExtra};
|
use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra};
|
||||||
use crate::interpret::eval_nullary_intrinsic;
|
use crate::interpret::eval_nullary_intrinsic;
|
||||||
use crate::interpret::{
|
use crate::interpret::{
|
||||||
intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, Immediate, InternKind,
|
intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, Immediate, InternKind,
|
||||||
InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar,
|
InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar,
|
||||||
ScalarMaybeUninit, StackPopCleanup,
|
ScalarMaybeUninit, StackPopCleanup,
|
||||||
};
|
};
|
||||||
|
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::interpret::{ConstEvalErr, ErrorHandled};
|
use rustc_middle::mir::interpret::ErrorHandled;
|
||||||
use rustc_middle::traits::Reveal;
|
use rustc_middle::traits::Reveal;
|
||||||
use rustc_middle::ty::{self, subst::Subst, TyCtxt};
|
use rustc_middle::ty::{self, subst::Subst, TyCtxt};
|
||||||
use rustc_span::source_map::Span;
|
use rustc_span::source_map::Span;
|
||||||
|
@ -213,7 +214,7 @@ fn validate_and_turn_into_const<'tcx>(
|
||||||
})();
|
})();
|
||||||
|
|
||||||
val.map_err(|error| {
|
val.map_err(|error| {
|
||||||
let err = error_to_const_error(&ecx, error, None);
|
let err = ConstEvalErr::new(&ecx, error, None);
|
||||||
err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| {
|
err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| {
|
||||||
diag.note(note_on_undefined_behavior_error());
|
diag.note(note_on_undefined_behavior_error());
|
||||||
diag.emit();
|
diag.emit();
|
||||||
|
@ -312,7 +313,7 @@ pub fn const_eval_raw_provider<'tcx>(
|
||||||
res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body))
|
res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body))
|
||||||
.map(|place| RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty })
|
.map(|place| RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty })
|
||||||
.map_err(|error| {
|
.map_err(|error| {
|
||||||
let err = error_to_const_error(&ecx, error, None);
|
let err = ConstEvalErr::new(&ecx, error, None);
|
||||||
// errors in statics are always emitted as fatal errors
|
// errors in statics are always emitted as fatal errors
|
||||||
if is_static {
|
if is_static {
|
||||||
// Ensure that if the above error was either `TooGeneric` or `Reported`
|
// Ensure that if the above error was either `TooGeneric` or `Reported`
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::{self as hir, def::DefKind, def_id::DefId, definitions::DefPathData};
|
||||||
use rustc_hir::def_id::DefId;
|
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
use rustc_middle::ich::StableHashingContext;
|
use rustc_middle::ich::StableHashingContext;
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::interpret::{
|
use rustc_middle::mir::interpret::{
|
||||||
sign_extend, truncate, FrameInfo, GlobalId, InterpResult, Pointer, Scalar,
|
sign_extend, truncate, GlobalId, InterpResult, Pointer, Scalar,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::layout::{self, TyAndLayout};
|
use rustc_middle::ty::layout::{self, TyAndLayout};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
|
self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
|
||||||
};
|
};
|
||||||
use rustc_span::{source_map::DUMMY_SP, Span};
|
use rustc_span::{source_map::DUMMY_SP, Pos, Span};
|
||||||
use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
|
use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -88,6 +88,14 @@ pub struct Frame<'mir, 'tcx, Tag = (), Extra = ()> {
|
||||||
pub loc: Option<mir::Location>,
|
pub loc: Option<mir::Location>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// What we store about a frame in an interpreter backtrace.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FrameInfo<'tcx> {
|
||||||
|
pub instance: ty::Instance<'tcx>,
|
||||||
|
pub span: Span,
|
||||||
|
pub lint_root: Option<hir::HirId>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
|
#[derive(Clone, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
|
||||||
pub enum StackPopCleanup {
|
pub enum StackPopCleanup {
|
||||||
/// Jump to the next block in the caller, or cause UB if None (that's a function
|
/// Jump to the next block in the caller, or cause UB if None (that's a function
|
||||||
|
@ -185,6 +193,25 @@ impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> fmt::Display for FrameInfo<'tcx> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
ty::tls::with(|tcx| {
|
||||||
|
if tcx.def_key(self.instance.def_id()).disambiguated_data.data
|
||||||
|
== DefPathData::ClosureExpr
|
||||||
|
{
|
||||||
|
write!(f, "inside closure")?;
|
||||||
|
} else {
|
||||||
|
write!(f, "inside `{}`", self.instance)?;
|
||||||
|
}
|
||||||
|
if !self.span.is_dummy() {
|
||||||
|
let lo = tcx.sess.source_map().lookup_char_pos(self.span.lo());
|
||||||
|
write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> {
|
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for InterpCx<'mir, 'tcx, M> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn data_layout(&self) -> &TargetDataLayout {
|
fn data_layout(&self) -> &TargetDataLayout {
|
||||||
|
|
|
@ -18,7 +18,7 @@ mod visitor;
|
||||||
|
|
||||||
pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
|
pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
|
||||||
|
|
||||||
pub use self::eval_context::{Frame, InterpCx, LocalState, LocalValue, StackPopCleanup};
|
pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup};
|
||||||
pub use self::intern::{intern_const_alloc_recursive, InternKind};
|
pub use self::intern::{intern_const_alloc_recursive, InternKind};
|
||||||
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
|
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
|
||||||
pub use self::memory::{get_static, AllocCheck, FnVal, Memory, MemoryKind};
|
pub use self::memory::{get_static, AllocCheck, FnVal, Memory, MemoryKind};
|
||||||
|
|
|
@ -26,7 +26,7 @@ use rustc_span::{def_id::DefId, Span};
|
||||||
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout};
|
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout};
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
|
|
||||||
use crate::const_eval::error_to_const_error;
|
use crate::const_eval::ConstEvalErr;
|
||||||
use crate::interpret::{
|
use crate::interpret::{
|
||||||
self, compile_time_machine, truncate, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx,
|
self, compile_time_machine, truncate, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx,
|
||||||
LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy,
|
LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy,
|
||||||
|
@ -451,7 +451,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
Ok(op) => Some(op),
|
Ok(op) => Some(op),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
let tcx = self.ecx.tcx.at(c.span);
|
let tcx = self.ecx.tcx.at(c.span);
|
||||||
let err = error_to_const_error(&self.ecx, error, Some(c.span));
|
let err = ConstEvalErr::new(&self.ecx, error, Some(c.span));
|
||||||
if let Some(lint_root) = self.lint_root(source_info) {
|
if let Some(lint_root) = self.lint_root(source_info) {
|
||||||
let lint_only = match c.literal.val {
|
let lint_only = match c.literal.val {
|
||||||
// Promoteds must lint and not error as the user didn't ask for them
|
// Promoteds must lint and not error as the user didn't ask for them
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue