Skip to content

Commit 9edec57

Browse files
authored
Rollup merge of #75339 - RalfJung:eval-required, r=oli-obk
evaluate required_consts when pushing stack frame in Miri engine [Just like codegen](https://github.com/rust-lang/rust/pull/70820/files#diff-32c57af5c8e23eb048f55d1e955e5cd5R194), Miri needs to make sure all `required_consts` evaluate successfully, to catch post-monomorphization errors. While at it I also moved the const_eval error reporting logic into rustc_mir::const_eval::error; there is no reason it should be in `rustc_middle`. I kept this in a separate commit for easier reviewing. Helps with rust-lang/miri#1382. I will add a test on the Miri side (done now: rust-lang/miri#1504). r? @oli-obk
2 parents 1e41af3 + fd3851a commit 9edec57

File tree

11 files changed

+302
-225
lines changed

11 files changed

+302
-225
lines changed

src/librustc_middle/mir/interpret/error.rs

+2-167
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
use super::{AllocId, Pointer, RawConst, Scalar};
22

33
use crate::mir::interpret::ConstValue;
4-
use crate::ty::layout::LayoutError;
5-
use crate::ty::query::TyCtxtAt;
6-
use crate::ty::{self, layout, tls, FnSig, Ty};
4+
use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty};
75

86
use rustc_data_structures::sync::Lock;
97
use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorReported};
10-
use rustc_hir as hir;
11-
use rustc_hir::definitions::DefPathData;
128
use rustc_macros::HashStable;
139
use rustc_session::CtfeBacktrace;
14-
use rustc_span::{def_id::DefId, Pos, Span};
10+
use rustc_span::def_id::DefId;
1511
use rustc_target::abi::{Align, Size};
1612
use std::{any::Any, backtrace::Backtrace, fmt, mem};
1713

@@ -34,167 +30,6 @@ CloneTypeFoldableAndLiftImpls! {
3430
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
3531
pub type ConstEvalResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
3632

37-
#[derive(Debug)]
38-
pub struct ConstEvalErr<'tcx> {
39-
pub span: Span,
40-
pub error: crate::mir::interpret::InterpError<'tcx>,
41-
pub stacktrace: Vec<FrameInfo<'tcx>>,
42-
}
43-
44-
#[derive(Debug)]
45-
pub struct FrameInfo<'tcx> {
46-
pub instance: ty::Instance<'tcx>,
47-
pub span: Span,
48-
pub lint_root: Option<hir::HirId>,
49-
}
50-
51-
impl<'tcx> fmt::Display for FrameInfo<'tcx> {
52-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53-
ty::tls::with(|tcx| {
54-
if tcx.def_key(self.instance.def_id()).disambiguated_data.data
55-
== DefPathData::ClosureExpr
56-
{
57-
write!(f, "inside closure")?;
58-
} else {
59-
write!(f, "inside `{}`", self.instance)?;
60-
}
61-
if !self.span.is_dummy() {
62-
let lo = tcx.sess.source_map().lookup_char_pos(self.span.lo());
63-
write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
64-
}
65-
Ok(())
66-
})
67-
}
68-
}
69-
70-
impl<'tcx> ConstEvalErr<'tcx> {
71-
pub fn struct_error(
72-
&self,
73-
tcx: TyCtxtAt<'tcx>,
74-
message: &str,
75-
emit: impl FnOnce(DiagnosticBuilder<'_>),
76-
) -> ErrorHandled {
77-
self.struct_generic(tcx, message, emit, None)
78-
}
79-
80-
pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
81-
self.struct_error(tcx, message, |mut e| e.emit())
82-
}
83-
84-
pub fn report_as_lint(
85-
&self,
86-
tcx: TyCtxtAt<'tcx>,
87-
message: &str,
88-
lint_root: hir::HirId,
89-
span: Option<Span>,
90-
) -> ErrorHandled {
91-
self.struct_generic(
92-
tcx,
93-
message,
94-
|mut lint: DiagnosticBuilder<'_>| {
95-
// Apply the span.
96-
if let Some(span) = span {
97-
let primary_spans = lint.span.primary_spans().to_vec();
98-
// point at the actual error as the primary span
99-
lint.replace_span_with(span);
100-
// point to the `const` statement as a secondary span
101-
// they don't have any label
102-
for sp in primary_spans {
103-
if sp != span {
104-
lint.span_label(sp, "");
105-
}
106-
}
107-
}
108-
lint.emit();
109-
},
110-
Some(lint_root),
111-
)
112-
}
113-
114-
/// Create a diagnostic for this const eval error.
115-
///
116-
/// Sets the message passed in via `message` and adds span labels with detailed error
117-
/// information before handing control back to `emit` to do any final processing.
118-
/// It's the caller's responsibility to call emit(), stash(), etc. within the `emit`
119-
/// function to dispose of the diagnostic properly.
120-
///
121-
/// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
122-
/// (Except that for some errors, we ignore all that -- see `must_error` below.)
123-
fn struct_generic(
124-
&self,
125-
tcx: TyCtxtAt<'tcx>,
126-
message: &str,
127-
emit: impl FnOnce(DiagnosticBuilder<'_>),
128-
lint_root: Option<hir::HirId>,
129-
) -> ErrorHandled {
130-
let must_error = match self.error {
131-
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
132-
return ErrorHandled::TooGeneric;
133-
}
134-
err_inval!(TypeckError(error_reported)) => {
135-
return ErrorHandled::Reported(error_reported);
136-
}
137-
// We must *always* hard error on these, even if the caller wants just a lint.
138-
err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
139-
_ => false,
140-
};
141-
trace!("reporting const eval failure at {:?}", self.span);
142-
143-
let err_msg = match &self.error {
144-
InterpError::MachineStop(msg) => {
145-
// A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
146-
// Should be turned into a string by now.
147-
msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
148-
}
149-
err => err.to_string(),
150-
};
151-
152-
let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
153-
if let Some(span_msg) = span_msg {
154-
err.span_label(self.span, span_msg);
155-
}
156-
// Add spans for the stacktrace. Don't print a single-line backtrace though.
157-
if self.stacktrace.len() > 1 {
158-
for frame_info in &self.stacktrace {
159-
err.span_label(frame_info.span, frame_info.to_string());
160-
}
161-
}
162-
// Let the caller finish the job.
163-
emit(err)
164-
};
165-
166-
if must_error {
167-
// The `message` makes little sense here, this is a more serious error than the
168-
// caller thinks anyway.
169-
// See <https://github.com/rust-lang/rust/pull/63152>.
170-
finish(struct_error(tcx, &err_msg), None);
171-
ErrorHandled::Reported(ErrorReported)
172-
} else {
173-
// Regular case.
174-
if let Some(lint_root) = lint_root {
175-
// Report as lint.
176-
let hir_id = self
177-
.stacktrace
178-
.iter()
179-
.rev()
180-
.find_map(|frame| frame.lint_root)
181-
.unwrap_or(lint_root);
182-
tcx.struct_span_lint_hir(
183-
rustc_session::lint::builtin::CONST_ERR,
184-
hir_id,
185-
tcx.span,
186-
|lint| finish(lint.build(message), Some(err_msg)),
187-
);
188-
ErrorHandled::Linted
189-
} else {
190-
// Report as hard error.
191-
finish(struct_error(tcx, message), Some(err_msg));
192-
ErrorHandled::Reported(ErrorReported)
193-
}
194-
}
195-
}
196-
}
197-
19833
pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
19934
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
20035
}

src/librustc_middle/mir/interpret/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,9 @@ use crate::ty::subst::GenericArgKind;
117117
use crate::ty::{self, Instance, Ty, TyCtxt};
118118

119119
pub use self::error::{
120-
struct_error, CheckInAllocMsg, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled,
121-
FrameInfo, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType,
122-
ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
120+
struct_error, CheckInAllocMsg, ConstEvalRawResult, ConstEvalResult, ErrorHandled, InterpError,
121+
InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, ResourceExhaustionInfo,
122+
UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
123123
};
124124

125125
pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit};

src/librustc_mir/const_eval/error.rs

+157-13
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
use std::error::Error;
22
use std::fmt;
33

4+
use rustc_errors::{DiagnosticBuilder, ErrorReported};
5+
use rustc_hir as hir;
46
use rustc_middle::mir::AssertKind;
5-
use rustc_middle::ty::ConstInt;
7+
use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt};
68
use rustc_span::{Span, Symbol};
79

810
use super::InterpCx;
9-
use crate::interpret::{ConstEvalErr, InterpErrorInfo, Machine};
11+
use crate::interpret::{
12+
struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine,
13+
};
1014

1115
/// The CTFE machine has some custom error kinds.
1216
#[derive(Clone, Debug)]
@@ -48,15 +52,155 @@ impl fmt::Display for ConstEvalErrKind {
4852

4953
impl Error for ConstEvalErrKind {}
5054

51-
/// Turn an interpreter error into something to report to the user.
52-
/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
53-
/// Should be called only if the error is actually going to to be reported!
54-
pub fn error_to_const_error<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>(
55-
ecx: &InterpCx<'mir, 'tcx, M>,
56-
error: InterpErrorInfo<'tcx>,
57-
span: Option<Span>,
58-
) -> ConstEvalErr<'tcx> {
59-
error.print_backtrace();
60-
let stacktrace = ecx.generate_stacktrace();
61-
ConstEvalErr { error: error.kind, stacktrace, span: span.unwrap_or_else(|| ecx.cur_span()) }
55+
/// When const-evaluation errors, this type is constructed with the resulting information,
56+
/// and then used to emit the error as a lint or hard error.
57+
#[derive(Debug)]
58+
pub struct ConstEvalErr<'tcx> {
59+
pub span: Span,
60+
pub error: InterpError<'tcx>,
61+
pub stacktrace: Vec<FrameInfo<'tcx>>,
62+
}
63+
64+
impl<'tcx> ConstEvalErr<'tcx> {
65+
/// Turn an interpreter error into something to report to the user.
66+
/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
67+
/// Should be called only if the error is actually going to to be reported!
68+
pub fn new<'mir, M: Machine<'mir, 'tcx>>(
69+
ecx: &InterpCx<'mir, 'tcx, M>,
70+
error: InterpErrorInfo<'tcx>,
71+
span: Option<Span>,
72+
) -> ConstEvalErr<'tcx>
73+
where
74+
'tcx: 'mir,
75+
{
76+
error.print_backtrace();
77+
let stacktrace = ecx.generate_stacktrace();
78+
ConstEvalErr { error: error.kind, stacktrace, span: span.unwrap_or_else(|| ecx.cur_span()) }
79+
}
80+
81+
pub fn struct_error(
82+
&self,
83+
tcx: TyCtxtAt<'tcx>,
84+
message: &str,
85+
emit: impl FnOnce(DiagnosticBuilder<'_>),
86+
) -> ErrorHandled {
87+
self.struct_generic(tcx, message, emit, None)
88+
}
89+
90+
pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
91+
self.struct_error(tcx, message, |mut e| e.emit())
92+
}
93+
94+
pub fn report_as_lint(
95+
&self,
96+
tcx: TyCtxtAt<'tcx>,
97+
message: &str,
98+
lint_root: hir::HirId,
99+
span: Option<Span>,
100+
) -> ErrorHandled {
101+
self.struct_generic(
102+
tcx,
103+
message,
104+
|mut lint: DiagnosticBuilder<'_>| {
105+
// Apply the span.
106+
if let Some(span) = span {
107+
let primary_spans = lint.span.primary_spans().to_vec();
108+
// point at the actual error as the primary span
109+
lint.replace_span_with(span);
110+
// point to the `const` statement as a secondary span
111+
// they don't have any label
112+
for sp in primary_spans {
113+
if sp != span {
114+
lint.span_label(sp, "");
115+
}
116+
}
117+
}
118+
lint.emit();
119+
},
120+
Some(lint_root),
121+
)
122+
}
123+
124+
/// Create a diagnostic for this const eval error.
125+
///
126+
/// Sets the message passed in via `message` and adds span labels with detailed error
127+
/// information before handing control back to `emit` to do any final processing.
128+
/// It's the caller's responsibility to call emit(), stash(), etc. within the `emit`
129+
/// function to dispose of the diagnostic properly.
130+
///
131+
/// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
132+
/// (Except that for some errors, we ignore all that -- see `must_error` below.)
133+
fn struct_generic(
134+
&self,
135+
tcx: TyCtxtAt<'tcx>,
136+
message: &str,
137+
emit: impl FnOnce(DiagnosticBuilder<'_>),
138+
lint_root: Option<hir::HirId>,
139+
) -> ErrorHandled {
140+
let must_error = match self.error {
141+
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
142+
return ErrorHandled::TooGeneric;
143+
}
144+
err_inval!(TypeckError(error_reported)) => {
145+
return ErrorHandled::Reported(error_reported);
146+
}
147+
// We must *always* hard error on these, even if the caller wants just a lint.
148+
err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
149+
_ => false,
150+
};
151+
trace!("reporting const eval failure at {:?}", self.span);
152+
153+
let err_msg = match &self.error {
154+
InterpError::MachineStop(msg) => {
155+
// A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
156+
// Should be turned into a string by now.
157+
msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
158+
}
159+
err => err.to_string(),
160+
};
161+
162+
let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
163+
if let Some(span_msg) = span_msg {
164+
err.span_label(self.span, span_msg);
165+
}
166+
// Add spans for the stacktrace. Don't print a single-line backtrace though.
167+
if self.stacktrace.len() > 1 {
168+
for frame_info in &self.stacktrace {
169+
err.span_label(frame_info.span, frame_info.to_string());
170+
}
171+
}
172+
// Let the caller finish the job.
173+
emit(err)
174+
};
175+
176+
if must_error {
177+
// The `message` makes little sense here, this is a more serious error than the
178+
// caller thinks anyway.
179+
// See <https://github.com/rust-lang/rust/pull/63152>.
180+
finish(struct_error(tcx, &err_msg), None);
181+
ErrorHandled::Reported(ErrorReported)
182+
} else {
183+
// Regular case.
184+
if let Some(lint_root) = lint_root {
185+
// Report as lint.
186+
let hir_id = self
187+
.stacktrace
188+
.iter()
189+
.rev()
190+
.find_map(|frame| frame.lint_root)
191+
.unwrap_or(lint_root);
192+
tcx.struct_span_lint_hir(
193+
rustc_session::lint::builtin::CONST_ERR,
194+
hir_id,
195+
tcx.span,
196+
|lint| finish(lint.build(message), Some(err_msg)),
197+
);
198+
ErrorHandled::Linted
199+
} else {
200+
// Report as hard error.
201+
finish(struct_error(tcx, message), Some(err_msg));
202+
ErrorHandled::Reported(ErrorReported)
203+
}
204+
}
205+
}
62206
}

0 commit comments

Comments
 (0)