Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report const eval error inside the query #53821

Merged
merged 21 commits into from
Oct 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ define_dep_nodes!( <'tcx>
[] UsedTraitImports(DefId),
[] HasTypeckTables(DefId),
[] ConstEval { param_env: ParamEnvAnd<'tcx, GlobalId<'tcx>> },
[] ConstEvalRaw { param_env: ParamEnvAnd<'tcx, GlobalId<'tcx>> },
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
[] CheckMatch(DefId),
[] SymbolName(DefId),
[] InstanceSymbolName { instance: Instance<'tcx> },
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/hir/map/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub struct FnLikeNode<'a> { node: Node<'a> }

/// MaybeFnLike wraps a method that indicates if an object
/// corresponds to some FnLikeNode.
pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
trait MaybeFnLike { fn is_fn_like(&self) -> bool; }

impl MaybeFnLike for ast::Item {
fn is_fn_like(&self) -> bool {
Expand Down
12 changes: 4 additions & 8 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,10 +483,9 @@ impl_stable_hash_for!(struct ty::Const<'tcx> {
val
});

impl_stable_hash_for!(struct ::mir::interpret::ConstEvalErr<'tcx> {
span,
stacktrace,
error
impl_stable_hash_for!(enum mir::interpret::ErrorHandled {
Reported,
TooGeneric
});

impl_stable_hash_for!(struct ::mir::interpret::FrameInfo {
Expand All @@ -503,8 +502,6 @@ impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
predicates
});

impl_stable_hash_for!(struct ::mir::interpret::EvalError<'tcx> { kind });

impl<'a, 'gcx, O: HashStable<StableHashingContext<'a>>> HashStable<StableHashingContext<'a>>
for ::mir::interpret::EvalErrorKind<'gcx, O> {
fn hash_stable<W: StableHasherResult>(&self,
Expand Down Expand Up @@ -543,14 +540,14 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
UnimplementedTraitSelection |
TypeckError |
TooGeneric |
CheckMatchError |
DerefFunctionPointer |
ExecuteMemory |
OverflowNeg |
RemainderByZero |
DivisionByZero |
GeneratorResumedAfterReturn |
GeneratorResumedAfterPanic |
ReferencedConstant |
InfiniteLoop => {}
ReadUndefBytes(offset) => offset.hash_stable(hcx, hasher),
InvalidDiscriminant(val) => val.hash_stable(hcx, hasher),
Expand All @@ -560,7 +557,6 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
line.hash_stable(hcx, hasher);
col.hash_stable(hcx, hasher);
},
ReferencedConstant(ref err) => err.hash_stable(hcx, hasher),
MachineError(ref err) => err.hash_stable(hcx, hasher),
FunctionAbiMismatch(a, b) => {
a.hash_stable(hcx, hasher);
Expand Down
68 changes: 44 additions & 24 deletions src/librustc/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ use std::{fmt, env};

use mir;
use ty::{Ty, layout};
use ty::layout::{Size, Align};
use rustc_data_structures::sync::Lrc;
use ty::layout::{Size, Align, LayoutError};
use rustc_target::spec::abi::Abi;

use super::{
Expand All @@ -30,7 +29,26 @@ use syntax_pos::Span;
use syntax::ast;
use syntax::symbol::Symbol;

pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>>;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ErrorHandled {
/// Already reported a lint or an error for this evaluation
Reported,
/// Don't emit an error, the evaluation failed because the MIR was generic
/// and the substs didn't fully monomorphize it.
TooGeneric,
}

impl ErrorHandled {
pub fn assert_reported(self) {
match self {
ErrorHandled::Reported => {},
ErrorHandled::TooGeneric => bug!("MIR interpretation failed without reporting an error \
even though it was fully monomorphized"),
}
}
}

pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>;

#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ConstEvalErr<'tcx> {
Expand All @@ -50,33 +68,41 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
pub fn struct_error(&self,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str)
-> Option<DiagnosticBuilder<'tcx>>
-> Result<DiagnosticBuilder<'tcx>, ErrorHandled>
{
self.struct_generic(tcx, message, None)
}

pub fn report_as_error(&self,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str
) {
) -> ErrorHandled {
let err = self.struct_error(tcx, message);
if let Some(mut err) = err {
err.emit();
match err {
Ok(mut err) => {
err.emit();
ErrorHandled::Reported
},
Err(err) => err,
}
}

pub fn report_as_lint(&self,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str,
lint_root: ast::NodeId,
) {
) -> ErrorHandled {
let lint = self.struct_generic(
tcx,
message,
Some(lint_root),
);
if let Some(mut lint) = lint {
lint.emit();
match lint {
Ok(mut lint) => {
lint.emit();
ErrorHandled::Reported
},
Err(err) => err,
}
}

Expand All @@ -85,15 +111,12 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str,
lint_root: Option<ast::NodeId>,
) -> Option<DiagnosticBuilder<'tcx>> {
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
match self.error.kind {
::mir::interpret::EvalErrorKind::TypeckError |
::mir::interpret::EvalErrorKind::TooGeneric |
::mir::interpret::EvalErrorKind::CheckMatchError |
::mir::interpret::EvalErrorKind::Layout(_) => return None,
::mir::interpret::EvalErrorKind::ReferencedConstant(ref inner) => {
inner.struct_generic(tcx, "referenced constant has errors", lint_root)?.emit();
},
EvalErrorKind::Layout(LayoutError::Unknown(_)) |
EvalErrorKind::TooGeneric => return Err(ErrorHandled::TooGeneric),
EvalErrorKind::Layout(LayoutError::SizeOverflow(_)) |
EvalErrorKind::TypeckError => return Err(ErrorHandled::Reported),
_ => {},
}
trace!("reporting const eval failure at {:?}", self.span);
Expand All @@ -117,7 +140,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
for FrameInfo { span, location, .. } in &self.stacktrace {
err.span_label(*span, format!("inside call to `{}`", location));
}
Some(err)
Ok(err)
}
}

Expand Down Expand Up @@ -279,10 +302,9 @@ pub enum EvalErrorKind<'tcx, O> {
TypeckError,
/// Resolution can fail if we are in a too generic context
TooGeneric,
CheckMatchError,
/// Cannot compute this constant because it depends on another one
/// which already produced an error
ReferencedConstant(Lrc<ConstEvalErr<'tcx>>),
ReferencedConstant,
GeneratorResumedAfterReturn,
GeneratorResumedAfterPanic,
InfiniteLoop,
Expand Down Expand Up @@ -407,9 +429,7 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
"encountered constants with type errors, stopping evaluation",
TooGeneric =>
"encountered overly generic constant",
CheckMatchError =>
"match checking failed",
ReferencedConstant(_) =>
ReferencedConstant =>
"referenced constant has errors",
Overflow(mir::BinOp::Add) => "attempt to add with overflow",
Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
Expand Down
12 changes: 6 additions & 6 deletions src/librustc/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ mod value;

pub use self::error::{
EvalError, EvalResult, EvalErrorKind, AssertMessage, ConstEvalErr, struct_error,
FrameInfo, ConstEvalResult,
FrameInfo, ConstEvalResult, ErrorHandled,
};

pub use self::value::{Scalar, ConstValue};
Expand Down Expand Up @@ -176,33 +176,33 @@ impl<'tcx, Tag> Pointer<Tag> {
Pointer { alloc_id, offset, tag }
}

pub fn wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
pub fn wrapping_signed_offset(self, i: i64, cx: impl HasDataLayout) -> Self {
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
Pointer::new_with_tag(
self.alloc_id,
Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)),
self.tag,
)
}

pub fn overflowing_signed_offset<C: HasDataLayout>(self, i: i128, cx: C) -> (Self, bool) {
pub fn overflowing_signed_offset(self, i: i128, cx: impl HasDataLayout) -> (Self, bool) {
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
}

pub fn signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
pub fn signed_offset(self, i: i64, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
Ok(Pointer::new_with_tag(
self.alloc_id,
Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
self.tag,
))
}

pub fn overflowing_offset<C: HasDataLayout>(self, i: Size, cx: C) -> (Self, bool) {
pub fn overflowing_offset(self, i: Size, cx: impl HasDataLayout) -> (Self, bool) {
let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
}

pub fn offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
pub fn offset(self, i: Size, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
Ok(Pointer::new_with_tag(
self.alloc_id,
Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
Expand Down
16 changes: 4 additions & 12 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -880,18 +880,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.tcx.report_object_safety_error(span, did, violations)
}

ConstEvalFailure(ref err) => {
match err.struct_error(
self.tcx.at(span),
"could not evaluate constant expression",
) {
Some(err) => err,
None => {
self.tcx.sess.delay_span_bug(span,
&format!("constant in type had an ignored error: {:?}", err));
return;
}
}
// already reported in the query
ConstEvalFailure(_) => {
self.tcx.sess.delay_span_bug(span, "constant in type had an ignored error");
return;
}

Overflow => {
Expand Down
14 changes: 4 additions & 10 deletions src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@
// except according to those terms.

use infer::InferCtxt;
use mir::interpret::GlobalId;
use mir::interpret::{GlobalId, ErrorHandled};
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate};
use ty::error::ExpectedFound;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, ObligationForest};
use rustc_data_structures::obligation_forest::{ObligationProcessor, ProcessResult};
use std::marker::PhantomData;
use hir::def_id::DefId;
use mir::interpret::ConstEvalErr;
use mir::interpret::EvalErrorKind;

use super::CodeAmbiguity;
use super::CodeProjectionError;
Expand Down Expand Up @@ -495,13 +493,9 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
CodeSelectionError(ConstEvalFailure(err)))
}
} else {
ProcessResult::Error(
CodeSelectionError(ConstEvalFailure(ConstEvalErr {
span: obligation.cause.span,
error: EvalErrorKind::TooGeneric.into(),
stacktrace: vec![],
}.into()))
)
ProcessResult::Error(CodeSelectionError(
ConstEvalFailure(ErrorHandled::TooGeneric)
))
}
},
None => {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use hir::def_id::DefId;
use infer::SuppressRegionErrors;
use infer::outlives::env::OutlivesEnvironment;
use middle::region;
use mir::interpret::ConstEvalErr;
use mir::interpret::ErrorHandled;
use ty::subst::Substs;
use ty::{self, AdtKind, List, Ty, TyCtxt, GenericParamDefKind, ToPredicate};
use ty::error::{ExpectedFound, TypeError};
Expand Down Expand Up @@ -438,7 +438,7 @@ pub enum SelectionError<'tcx> {
ty::PolyTraitRef<'tcx>,
ty::error::TypeError<'tcx>),
TraitNotObjectSafe(DefId),
ConstEvalFailure(Lrc<ConstEvalErr<'tcx>>),
ConstEvalFailure(ErrorHandled),
Overflow,
}

Expand Down
4 changes: 1 addition & 3 deletions src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
)
}
super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)),
super::ConstEvalFailure(ref err) => tcx.lift(&**err).map(|err| super::ConstEvalFailure(
err.into(),
)),
super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)),
super::Overflow => Some(super::Overflow),
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte
use middle::privacy::AccessLevels;
use middle::resolve_lifetime::ObjectLifetimeDefault;
use mir::Mir;
use mir::interpret::GlobalId;
use mir::interpret::{GlobalId, ErrorHandled};
use mir::GeneratorLayout;
use session::CrateDisambiguator;
use traits::{self, Reveal};
Expand Down Expand Up @@ -2191,18 +2191,18 @@ impl<'a, 'gcx, 'tcx> AdtDef {
None
}
}
Err(err) => {
err.report_as_error(
tcx.at(tcx.def_span(expr_did)),
"could not evaluate enum discriminant",
);
Err(ErrorHandled::Reported) => {
if !expr_did.is_local() {
span_bug!(tcx.def_span(expr_did),
"variant discriminant evaluation succeeded \
in its crate but failed locally");
}
None
}
Err(ErrorHandled::TooGeneric) => span_bug!(
tcx.def_span(expr_did),
"enum discriminant depends on generic arguments",
),
}
}

Expand Down
Loading