Skip to content

Commit

Permalink
Refactor the const eval diagnostic API
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Jun 5, 2018
1 parent 4a9c58c commit 5c0d135
Show file tree
Hide file tree
Showing 51 changed files with 352 additions and 349 deletions.
1 change: 1 addition & 0 deletions src/librustc/ich/impls_ty.rs
Expand Up @@ -510,6 +510,7 @@ impl_stable_hash_for!(struct ::middle::const_val::ConstEvalErr<'tcx> {

impl_stable_hash_for!(struct ::middle::const_val::FrameInfo {
span,
lint_root,
location
});

Expand Down
3 changes: 3 additions & 0 deletions src/librustc/lint/context.rs
Expand Up @@ -655,6 +655,9 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
f(self);
self.param_env = old_param_env;
}
pub fn current_lint_root(&self) -> ast::NodeId {
self.last_ast_node_with_lint_attrs
}
}

impl<'a, 'tcx> LayoutOf for &'a LateContext<'a, 'tcx> {
Expand Down
111 changes: 68 additions & 43 deletions src/librustc/middle/const_val.rs
Expand Up @@ -9,13 +9,15 @@
// except according to those terms.

use hir::def_id::DefId;
use ty::{self, TyCtxt, layout};
use ty::{self, layout};
use ty::subst::Substs;
use ty::maps::TyCtxtAt;
use mir::interpret::ConstValue;
use errors::DiagnosticBuilder;

use graphviz::IntoCow;
use syntax_pos::Span;
use syntax::ast;

use std::borrow::Cow;
use rustc_data_structures::sync::Lrc;
Expand Down Expand Up @@ -52,6 +54,7 @@ pub enum ErrKind<'tcx> {
pub struct FrameInfo {
pub span: Span,
pub location: String,
pub lint_root: Option<ast::NodeId>,
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -100,64 +103,86 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
}

pub fn struct_error(&self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
primary_span: Span,
primary_kind: &str)
-> DiagnosticBuilder<'gcx>
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str)
-> Option<DiagnosticBuilder<'tcx>>
{
let mut diag = struct_error(tcx, self.span, "constant evaluation error");
self.note(tcx, primary_span, primary_kind, &mut diag);
diag
self.struct_generic(tcx, message, None, true)
}

pub fn note(&self,
_tcx: TyCtxt<'a, 'gcx, 'tcx>,
primary_span: Span,
primary_kind: &str,
diag: &mut DiagnosticBuilder)
{
match self.description() {
ConstEvalErrDescription::Simple(message) => {
diag.span_label(self.span, message);
}
ConstEvalErrDescription::Backtrace(miri, frames) => {
diag.span_label(self.span, format!("{}", miri));
for frame in frames {
diag.span_label(frame.span, format!("inside call to `{}`", frame.location));
}
}
pub fn report_as_error(&self,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str
) {
let err = self.struct_generic(tcx, message, None, true);
if let Some(mut err) = err {
err.emit();
}
}

if !primary_span.contains(self.span) {
diag.span_note(primary_span,
&format!("for {} here", primary_kind));
pub fn report_as_lint(&self,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str,
lint_root: ast::NodeId,
) {
let lint = self.struct_generic(
tcx,
message,
Some(lint_root),
false,
);
if let Some(mut lint) = lint {
lint.emit();
}
}

pub fn report(&self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
primary_span: Span,
primary_kind: &str)
{
match *self.kind {
ErrKind::TypeckError | ErrKind::CheckMatchError => return,
ErrKind::Miri(ref miri, _) => {
fn struct_generic(
&self,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str,
lint_root: Option<ast::NodeId>,
as_err: bool,
) -> Option<DiagnosticBuilder<'tcx>> {
let (msg, frames): (_, &[_]) = match *self.kind {
ErrKind::TypeckError | ErrKind::CheckMatchError => return None,
ErrKind::Miri(ref miri, ref frames) => {
match miri.kind {
::mir::interpret::EvalErrorKind::TypeckError |
::mir::interpret::EvalErrorKind::Layout(_) => return,
_ => {},
::mir::interpret::EvalErrorKind::Layout(_) => return None,
_ => (miri.to_string(), frames),
}
}
_ => {}
_ => (self.description().into_oneline().to_string(), &[]),
};
trace!("reporting const eval failure at {:?}", self.span);
let mut err = if as_err {
struct_error(tcx, message)
} else {
let node_id = frames
.iter()
.rev()
.filter_map(|frame| frame.lint_root)
.next()
.or(lint_root)
.expect("some part of a failing const eval must be local");
tcx.struct_span_lint_node(
::rustc::lint::builtin::CONST_ERR,
node_id,
tcx.span,
message,
)
};
err.span_label(self.span, msg);
for FrameInfo { span, location, .. } in frames {
err.span_label(*span, format!("inside call to `{}`", location));
}
self.struct_error(tcx, primary_span, primary_kind).emit();
Some(err)
}
}

pub fn struct_error<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
span: Span,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
msg: &str,
) -> DiagnosticBuilder<'gcx> {
struct_span_err!(tcx.sess, span, E0080, "{}", msg)
) -> DiagnosticBuilder<'tcx> {
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
}
36 changes: 36 additions & 0 deletions src/librustc/mir/interpret/error.rs
Expand Up @@ -16,6 +16,42 @@ pub struct EvalError<'tcx> {
pub backtrace: Option<Backtrace>,
}

impl<'tcx> EvalError<'tcx> {
pub fn print_backtrace(&mut self) {
if let Some(ref mut backtrace) = self.backtrace {
use std::fmt::Write;
let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
backtrace.resolve();
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();
}
}
}
error!("{}", trace_text);
}
}
}

impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
let backtrace = match env::var("MIRI_BACKTRACE") {
Expand Down
9 changes: 6 additions & 3 deletions src/librustc/traits/error_reporting.rs
Expand Up @@ -827,10 +827,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}

ConstEvalFailure(ref err) => {
if let ::middle::const_val::ErrKind::TypeckError = *err.kind {
return;
match err.struct_error(
self.tcx.at(span),
"could not evaluate constant expression",
) {
Some(err) => err,
None => return,
}
err.struct_error(self.tcx, span, "constant expression")
}

Overflow => {
Expand Down
8 changes: 5 additions & 3 deletions src/librustc/ty/mod.rs
Expand Up @@ -2075,15 +2075,17 @@ impl<'a, 'gcx, 'tcx> AdtDef {
} else {
info!("invalid enum discriminant: {:#?}", val);
::middle::const_val::struct_error(
tcx,
tcx.def_span(expr_did),
tcx.at(tcx.def_span(expr_did)),
"constant evaluation of enum discriminant resulted in non-integer",
).emit();
None
}
}
Err(err) => {
err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
err.report_as_error(
tcx.at(tcx.def_span(expr_did)),
"could not evaluate enum discriminant",
);
if !expr_did.is_local() {
span_bug!(tcx.def_span(expr_did),
"variant discriminant evaluation succeeded \
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_codegen_llvm/mir/constant.rs
Expand Up @@ -217,7 +217,10 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
Ok((llval, constant.ty))
})
.unwrap_or_else(|e| {
e.report(bx.tcx(), constant.span, "shuffle_indices");
e.report_as_error(
bx.tcx().at(constant.span),
"could not evaluate shuffle_indices at compile time",
);
// We've errored, so we don't have to produce working code.
let ty = self.monomorphize(&constant.ty);
let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_codegen_llvm/mir/operand.rs
Expand Up @@ -416,7 +416,10 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
// FIXME: generate a panic here
},
mir::Literal::Value { .. } => {
err.report(bx.tcx(), constant.span, "const operand");
err.report_as_error(
bx.tcx().at(constant.span),
"could not evaluate constant operand",
);
},
}
// We've errored, so we don't have to produce working code.
Expand Down
19 changes: 3 additions & 16 deletions src/librustc_lint/builtin.rs
Expand Up @@ -1501,24 +1501,11 @@ fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) {
};
if let Err(err) = cx.tcx.const_eval(param_env.and(cid)) {
let span = cx.tcx.def_span(def_id);
let mut diag = cx.struct_span_lint(
CONST_ERR,
span,
err.report_as_lint(
cx.tcx.at(span),
&format!("this {} cannot be used", what),
cx.current_lint_root(),
);
use rustc::middle::const_val::ConstEvalErrDescription;
match err.description() {
ConstEvalErrDescription::Simple(message) => {
diag.span_label(span, message);
}
ConstEvalErrDescription::Backtrace(miri, frames) => {
diag.span_label(span, format!("{}", miri));
for frame in frames {
diag.span_label(frame.span, format!("inside call to `{}`", frame.location));
}
}
}
diag.emit()
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/hair/cx/expr.rs
Expand Up @@ -523,7 +523,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let count = match cx.tcx.at(span).const_eval(cx.param_env.and(global_id)) {
Ok(cv) => cv.unwrap_usize(cx.tcx),
Err(e) => {
e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
e.report_as_error(cx.tcx.at(span), "could not evaluate array length");
0
},
};
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/hair/pattern/check_match.rs
Expand Up @@ -141,13 +141,13 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
PatternError::FloatBug => {
// FIXME(#31407) this is only necessary because float parsing is buggy
::rustc::middle::const_val::struct_error(
self.tcx, pat_span,
self.tcx.at(pat_span),
"could not evaluate float literal (see issue #31407)",
).emit();
}
PatternError::NonConstPath(span) => {
::rustc::middle::const_val::struct_error(
self.tcx, span,
self.tcx.at(span),
"runtime values cannot be referenced in patterns",
).emit();
}
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_mir/hair/pattern/mod.rs
Expand Up @@ -695,7 +695,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
return self.const_to_pat(instance, value, id, span)
},
Err(err) => {
err.report(self.tcx, span, "pattern");
err.report_as_error(
self.tcx.at(span),
"could not evaluate constant pattern",
);
PatternKind::Wild
},
}
Expand Down

0 comments on commit 5c0d135

Please sign in to comment.