Skip to content

Commit 9ac3725

Browse files
committed
Auto merge of #51316 - oli-obk:const_err, r=nikomatsakis
Refactor the const eval diagnostic API * no longer report "const eval error" for things that have typeck errors * errors and lints have saner spans and messages * unified the diagnostic logic (const eval errors were slightly different depending on where they were reported, and there was also code duplication between the different reporters) * report errors if an erroneous constant is used inside a promoted (fixes most of #50814)
2 parents 685faa2 + 14d08e5 commit 9ac3725

File tree

65 files changed

+882
-462
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+882
-462
lines changed

src/librustc/ich/impls_ty.rs

+4-13
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ impl_stable_hash_for!(struct ::middle::const_val::ConstEvalErr<'tcx> {
510510

511511
impl_stable_hash_for!(struct ::middle::const_val::FrameInfo {
512512
span,
513+
lint_root,
513514
location
514515
});
515516

@@ -523,21 +524,11 @@ for ::middle::const_val::ErrKind<'gcx> {
523524
mem::discriminant(self).hash_stable(hcx, hasher);
524525

525526
match *self {
526-
NonConstPath |
527527
TypeckError |
528+
CouldNotResolve |
528529
CheckMatchError => {
529530
// nothing to do
530531
}
531-
UnimplementedConstVal(s) => {
532-
s.hash_stable(hcx, hasher);
533-
}
534-
IndexOutOfBounds { len, index } => {
535-
len.hash_stable(hcx, hasher);
536-
index.hash_stable(hcx, hasher);
537-
}
538-
LayoutError(ref layout_error) => {
539-
layout_error.hash_stable(hcx, hasher);
540-
}
541532
Miri(ref err, ref trace) => {
542533
err.hash_stable(hcx, hasher);
543534
trace.hash_stable(hcx, hasher);
@@ -608,8 +599,8 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
608599
RemainderByZero |
609600
DivisionByZero |
610601
GeneratorResumedAfterReturn |
611-
GeneratorResumedAfterPanic |
612-
ReferencedConstant => {}
602+
GeneratorResumedAfterPanic => {}
603+
ReferencedConstant(ref err) => err.hash_stable(hcx, hasher),
613604
MachineError(ref err) => err.hash_stable(hcx, hasher),
614605
FunctionPointerTyMismatch(a, b) => {
615606
a.hash_stable(hcx, hasher);

src/librustc/lint/context.rs

+3
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,9 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
655655
f(self);
656656
self.param_env = old_param_env;
657657
}
658+
pub fn current_lint_root(&self) -> ast::NodeId {
659+
self.last_ast_node_with_lint_attrs
660+
}
658661
}
659662

660663
impl<'a, 'tcx> LayoutOf for &'a LateContext<'a, 'tcx> {

src/librustc/middle/const_val.rs

+77-62
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
// except according to those terms.
1010

1111
use hir::def_id::DefId;
12-
use ty::{self, TyCtxt, layout};
12+
use ty;
1313
use ty::subst::Substs;
14+
use ty::maps::TyCtxtAt;
1415
use mir::interpret::ConstValue;
1516
use errors::DiagnosticBuilder;
1617

1718
use graphviz::IntoCow;
1819
use syntax_pos::Span;
20+
use syntax::ast;
1921

2022
use std::borrow::Cow;
2123
use rustc_data_structures::sync::Lrc;
@@ -28,30 +30,26 @@ pub enum ConstVal<'tcx> {
2830
Value(ConstValue<'tcx>),
2931
}
3032

31-
#[derive(Clone, Debug)]
33+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
3234
pub struct ConstEvalErr<'tcx> {
3335
pub span: Span,
3436
pub kind: Lrc<ErrKind<'tcx>>,
3537
}
3638

37-
#[derive(Clone, Debug)]
39+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
3840
pub enum ErrKind<'tcx> {
3941

40-
NonConstPath,
41-
UnimplementedConstVal(&'static str),
42-
IndexOutOfBounds { len: u64, index: u64 },
43-
44-
LayoutError(layout::LayoutError<'tcx>),
45-
42+
CouldNotResolve,
4643
TypeckError,
4744
CheckMatchError,
4845
Miri(::mir::interpret::EvalError<'tcx>, Vec<FrameInfo>),
4946
}
5047

51-
#[derive(Clone, Debug)]
48+
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
5249
pub struct FrameInfo {
5350
pub span: Span,
5451
pub location: String,
52+
pub lint_root: Option<ast::NodeId>,
5553
}
5654

5755
#[derive(Clone, Debug)]
@@ -83,81 +81,98 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
8381
}
8482

8583
match *self.kind {
86-
NonConstPath => simple!("non-constant path in constant expression"),
87-
UnimplementedConstVal(what) =>
88-
simple!("unimplemented constant expression: {}", what),
89-
IndexOutOfBounds { len, index } => {
90-
simple!("index out of bounds: the len is {} but the index is {}",
91-
len, index)
92-
}
93-
94-
LayoutError(ref err) => Simple(err.to_string().into_cow()),
95-
84+
CouldNotResolve => simple!("could not resolve"),
9685
TypeckError => simple!("type-checking failed"),
9786
CheckMatchError => simple!("match-checking failed"),
9887
Miri(ref err, ref trace) => Backtrace(err, trace),
9988
}
10089
}
10190

10291
pub fn struct_error(&self,
103-
tcx: TyCtxt<'a, 'gcx, 'tcx>,
104-
primary_span: Span,
105-
primary_kind: &str)
106-
-> DiagnosticBuilder<'gcx>
92+
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
93+
message: &str)
94+
-> Option<DiagnosticBuilder<'tcx>>
10795
{
108-
let mut diag = struct_error(tcx, self.span, "constant evaluation error");
109-
self.note(tcx, primary_span, primary_kind, &mut diag);
110-
diag
96+
self.struct_generic(tcx, message, None, true)
11197
}
11298

113-
pub fn note(&self,
114-
_tcx: TyCtxt<'a, 'gcx, 'tcx>,
115-
primary_span: Span,
116-
primary_kind: &str,
117-
diag: &mut DiagnosticBuilder)
118-
{
119-
match self.description() {
120-
ConstEvalErrDescription::Simple(message) => {
121-
diag.span_label(self.span, message);
122-
}
123-
ConstEvalErrDescription::Backtrace(miri, frames) => {
124-
diag.span_label(self.span, format!("{}", miri));
125-
for frame in frames {
126-
diag.span_label(frame.span, format!("inside call to `{}`", frame.location));
127-
}
128-
}
99+
pub fn report_as_error(&self,
100+
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
101+
message: &str
102+
) {
103+
let err = self.struct_generic(tcx, message, None, true);
104+
if let Some(mut err) = err {
105+
err.emit();
129106
}
107+
}
130108

131-
if !primary_span.contains(self.span) {
132-
diag.span_note(primary_span,
133-
&format!("for {} here", primary_kind));
109+
pub fn report_as_lint(&self,
110+
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
111+
message: &str,
112+
lint_root: ast::NodeId,
113+
) {
114+
let lint = self.struct_generic(
115+
tcx,
116+
message,
117+
Some(lint_root),
118+
false,
119+
);
120+
if let Some(mut lint) = lint {
121+
lint.emit();
134122
}
135123
}
136124

137-
pub fn report(&self,
138-
tcx: TyCtxt<'a, 'gcx, 'tcx>,
139-
primary_span: Span,
140-
primary_kind: &str)
141-
{
142-
match *self.kind {
143-
ErrKind::TypeckError | ErrKind::CheckMatchError => return,
144-
ErrKind::Miri(ref miri, _) => {
125+
fn struct_generic(
126+
&self,
127+
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
128+
message: &str,
129+
lint_root: Option<ast::NodeId>,
130+
as_err: bool,
131+
) -> Option<DiagnosticBuilder<'tcx>> {
132+
let (msg, frames): (_, &[_]) = match *self.kind {
133+
ErrKind::TypeckError | ErrKind::CheckMatchError => return None,
134+
ErrKind::Miri(ref miri, ref frames) => {
145135
match miri.kind {
146136
::mir::interpret::EvalErrorKind::TypeckError |
147-
::mir::interpret::EvalErrorKind::Layout(_) => return,
148-
_ => {},
137+
::mir::interpret::EvalErrorKind::Layout(_) => return None,
138+
::mir::interpret::EvalErrorKind::ReferencedConstant(ref inner) => {
139+
inner.struct_generic(tcx, "referenced constant", lint_root, as_err)?.emit();
140+
(miri.to_string(), frames)
141+
},
142+
_ => (miri.to_string(), frames),
149143
}
150144
}
151-
_ => {}
145+
_ => (self.description().into_oneline().to_string(), &[]),
146+
};
147+
trace!("reporting const eval failure at {:?}", self.span);
148+
let mut err = if as_err {
149+
struct_error(tcx, message)
150+
} else {
151+
let node_id = frames
152+
.iter()
153+
.rev()
154+
.filter_map(|frame| frame.lint_root)
155+
.next()
156+
.or(lint_root)
157+
.expect("some part of a failing const eval must be local");
158+
tcx.struct_span_lint_node(
159+
::rustc::lint::builtin::CONST_ERR,
160+
node_id,
161+
tcx.span,
162+
message,
163+
)
164+
};
165+
err.span_label(self.span, msg);
166+
for FrameInfo { span, location, .. } in frames {
167+
err.span_label(*span, format!("inside call to `{}`", location));
152168
}
153-
self.struct_error(tcx, primary_span, primary_kind).emit();
169+
Some(err)
154170
}
155171
}
156172

157173
pub fn struct_error<'a, 'gcx, 'tcx>(
158-
tcx: TyCtxt<'a, 'gcx, 'tcx>,
159-
span: Span,
174+
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
160175
msg: &str,
161-
) -> DiagnosticBuilder<'gcx> {
162-
struct_span_err!(tcx.sess, span, E0080, "{}", msg)
176+
) -> DiagnosticBuilder<'tcx> {
177+
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
163178
}

src/librustc/mir/interpret/error.rs

+39-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{fmt, env};
22

33
use mir;
4+
use middle::const_val::ConstEvalErr;
45
use ty::{FnSig, Ty, layout};
56
use ty::layout::{Size, Align};
67

@@ -10,21 +11,50 @@ use super::{
1011

1112
use backtrace::Backtrace;
1213

13-
#[derive(Debug, Clone)]
14+
#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
1415
pub struct EvalError<'tcx> {
1516
pub kind: EvalErrorKind<'tcx, u64>,
16-
pub backtrace: Option<Backtrace>,
1717
}
1818

1919
impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
2020
fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
21-
let backtrace = match env::var("MIRI_BACKTRACE") {
22-
Ok(ref val) if !val.is_empty() => Some(Backtrace::new_unresolved()),
23-
_ => None
24-
};
21+
match env::var("MIRI_BACKTRACE") {
22+
Ok(ref val) if !val.is_empty() => {
23+
let backtrace = Backtrace::new();
24+
25+
use std::fmt::Write;
26+
let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
27+
write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap();
28+
'frames: for (i, frame) in backtrace.frames().iter().enumerate() {
29+
if frame.symbols().is_empty() {
30+
write!(trace_text, "{}: no symbols\n", i).unwrap();
31+
}
32+
for symbol in frame.symbols() {
33+
write!(trace_text, "{}: ", i).unwrap();
34+
if let Some(name) = symbol.name() {
35+
write!(trace_text, "{}\n", name).unwrap();
36+
} else {
37+
write!(trace_text, "<unknown>\n").unwrap();
38+
}
39+
write!(trace_text, "\tat ").unwrap();
40+
if let Some(file_path) = symbol.filename() {
41+
write!(trace_text, "{}", file_path.display()).unwrap();
42+
} else {
43+
write!(trace_text, "<unknown_file>").unwrap();
44+
}
45+
if let Some(line) = symbol.lineno() {
46+
write!(trace_text, ":{}\n", line).unwrap();
47+
} else {
48+
write!(trace_text, "\n").unwrap();
49+
}
50+
}
51+
}
52+
error!("{}", trace_text);
53+
},
54+
_ => {},
55+
}
2556
EvalError {
2657
kind,
27-
backtrace,
2858
}
2959
}
3060
}
@@ -122,7 +152,7 @@ pub enum EvalErrorKind<'tcx, O> {
122152
TypeckError,
123153
/// Cannot compute this constant because it depends on another one
124154
/// which already produced an error
125-
ReferencedConstant,
155+
ReferencedConstant(ConstEvalErr<'tcx>),
126156
GeneratorResumedAfterReturn,
127157
GeneratorResumedAfterPanic,
128158
}
@@ -238,7 +268,7 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
238268
"there were unresolved type arguments during trait selection",
239269
TypeckError =>
240270
"encountered constants with type errors, stopping evaluation",
241-
ReferencedConstant =>
271+
ReferencedConstant(_) =>
242272
"referenced constant has errors",
243273
Overflow(mir::BinOp::Add) => "attempt to add with overflow",
244274
Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",

src/librustc/traits/error_reporting.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -827,10 +827,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
827827
}
828828

829829
ConstEvalFailure(ref err) => {
830-
if let ::middle::const_val::ErrKind::TypeckError = *err.kind {
831-
return;
830+
match err.struct_error(
831+
self.tcx.at(span),
832+
"could not evaluate constant expression",
833+
) {
834+
Some(err) => err,
835+
None => return,
832836
}
833-
err.struct_error(self.tcx, span, "constant expression")
834837
}
835838

836839
Overflow => {

src/librustc/traits/fulfill.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -534,8 +534,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
534534
} else {
535535
Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
536536
span: obligation.cause.span,
537-
kind: ErrKind::UnimplementedConstVal("could not resolve")
538-
.into(),
537+
kind: ErrKind::CouldNotResolve.into(),
539538
})))
540539
}
541540
},

src/librustc/ty/mod.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -2075,15 +2075,17 @@ impl<'a, 'gcx, 'tcx> AdtDef {
20752075
} else {
20762076
info!("invalid enum discriminant: {:#?}", val);
20772077
::middle::const_val::struct_error(
2078-
tcx,
2079-
tcx.def_span(expr_did),
2078+
tcx.at(tcx.def_span(expr_did)),
20802079
"constant evaluation of enum discriminant resulted in non-integer",
20812080
).emit();
20822081
None
20832082
}
20842083
}
20852084
Err(err) => {
2086-
err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
2085+
err.report_as_error(
2086+
tcx.at(tcx.def_span(expr_did)),
2087+
"could not evaluate enum discriminant",
2088+
);
20872089
if !expr_did.is_local() {
20882090
span_bug!(tcx.def_span(expr_did),
20892091
"variant discriminant evaluation succeeded \

0 commit comments

Comments
 (0)