}
}
-impl_stable_hash_for!(enum mir::interpret::ScalarMaybeUndef {
- Scalar(v),
- Undef
-});
-
impl_stable_hash_for!(struct mir::interpret::Pointer {
alloc_id,
offset
})
}
- /// Clears the selection, evaluation, and projection cachesThis is useful when
+ /// Clears the selection, evaluation, and projection caches. This is useful when
/// repeatedly attemping to select an Obligation while changing only
/// its ParamEnv, since FulfillmentContext doesn't use 'probe'
pub fn clear_caches(&self) {
FrameInfo, ConstEvalResult,
};
-pub use self::value::{Scalar, ConstValue, ScalarMaybeUndef};
+pub use self::value::{Scalar, ConstValue};
use std::fmt;
use mir;
/// to allow HIR creation to happen for everything before needing to be able to run constant
/// evaluation
Unevaluated(DefId, &'tcx Substs<'tcx>),
+
/// Used only for types with layout::abi::Scalar ABI and ZSTs
///
/// Not using the enum `Value` to encode that this must not be `Undef`
Scalar(Scalar),
- /// Used only for types with layout::abi::ScalarPair
+
+ /// Used only for *fat pointers* with layout::abi::ScalarPair
///
- /// The second field may be undef in case of `Option<usize>::None`
- ScalarPair(Scalar, ScalarMaybeUndef),
- /// Used only for the remaining cases. An allocation + offset into the allocation.
+ /// Needed for pattern matching code related to slices and strings.
+ ScalarPair(Scalar, Scalar),
+
+ /// An allocation + offset into the allocation.
/// Invariant: The AllocId matches the allocation.
ByRef(AllocId, &'tcx Allocation, Size),
}
ConstValue::ScalarPair(val, Scalar::Bits {
bits: len as u128,
size: cx.data_layout().pointer_size.bytes() as u8,
- }.into())
+ })
}
#[inline]
pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
- ConstValue::ScalarPair(val, Scalar::Ptr(vtable).into())
+ ConstValue::ScalarPair(val, Scalar::Ptr(vtable))
}
}
/// relocation and its associated offset together as a `Pointer` here.
Ptr(Pointer<Id>),
}
-
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub enum ScalarMaybeUndef<Id=AllocId> {
- Scalar(Scalar<Id>),
- Undef,
-}
-
-impl From<Scalar> for ScalarMaybeUndef {
- #[inline(always)]
- fn from(s: Scalar) -> Self {
- ScalarMaybeUndef::Scalar(s)
- }
-}
-
-impl<'tcx> ScalarMaybeUndef {
- #[inline]
- pub fn not_undef(self) -> EvalResult<'static, Scalar> {
- match self {
- ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
- ScalarMaybeUndef::Undef => err!(ReadUndefBytes(Size::from_bytes(0))),
- }
- }
-
- #[inline(always)]
- pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
- self.not_undef()?.to_ptr()
- }
-
- #[inline(always)]
- pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
- self.not_undef()?.to_bits(target_size)
- }
-
- #[inline(always)]
- pub fn to_bool(self) -> EvalResult<'tcx, bool> {
- self.not_undef()?.to_bool()
- }
-
- #[inline(always)]
- pub fn to_char(self) -> EvalResult<'tcx, char> {
- self.not_undef()?.to_char()
- }
-
- #[inline(always)]
- pub fn to_f32(self) -> EvalResult<'tcx, f32> {
- self.not_undef()?.to_f32()
- }
-
- #[inline(always)]
- pub fn to_f64(self) -> EvalResult<'tcx, f64> {
- self.not_undef()?.to_f64()
- }
-
- #[inline(always)]
- pub fn to_u8(self) -> EvalResult<'tcx, u8> {
- self.not_undef()?.to_u8()
- }
-
- #[inline(always)]
- pub fn to_u32(self) -> EvalResult<'tcx, u32> {
- self.not_undef()?.to_u32()
- }
-
- #[inline(always)]
- pub fn to_u64(self) -> EvalResult<'tcx, u64> {
- self.not_undef()?.to_u64()
- }
-
- #[inline(always)]
- pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
- self.not_undef()?.to_usize(cx)
- }
-
- #[inline(always)]
- pub fn to_i8(self) -> EvalResult<'tcx, i8> {
- self.not_undef()?.to_i8()
- }
-
- #[inline(always)]
- pub fn to_i32(self) -> EvalResult<'tcx, i32> {
- self.not_undef()?.to_i32()
- }
-
- #[inline(always)]
- pub fn to_i64(self) -> EvalResult<'tcx, i64> {
- self.not_undef()?.to_i64()
- }
-
- #[inline(always)]
- pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, i64> {
- self.not_undef()?.to_isize(cx)
- }
-}
use hir::def_id::DefId;
use hir::{self, HirId, InlineAsm};
use middle::region;
-use mir::interpret::{ConstValue, EvalErrorKind, Scalar, ScalarMaybeUndef};
+use mir::interpret::{ConstValue, EvalErrorKind, Scalar};
use mir::visit::MirVisitable;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
// print string literals
if let ConstValue::ScalarPair(ptr, len) = value {
if let Scalar::Ptr(ptr) = ptr {
- if let ScalarMaybeUndef::Scalar(Scalar::Bits { bits: len, .. }) = len {
+ if let Scalar::Bits { bits: len, .. } = len {
if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty {
return ty::tls::with(|tcx| {
let alloc = tcx.alloc_map.lock().get(ptr.alloc_id);
use ty::error::{ExpectedFound, TypeError};
use ty::fold::{TypeFolder, TypeFoldable, TypeVisitor};
use infer::{InferCtxt};
+use util::common::ErrorReported;
use rustc_data_structures::sync::Lrc;
use std::fmt::Debug;
}
}
-// FIXME: this is gonna need to be removed ...
-/// Normalizes the parameter environment, reporting errors if they occur.
-pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- region_context: DefId,
- unnormalized_env: ty::ParamEnv<'tcx>,
- cause: ObligationCause<'tcx>)
- -> ty::ParamEnv<'tcx>
+fn do_normalize_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ region_context: DefId,
+ cause: ObligationCause<'tcx>,
+ elaborated_env: ty::ParamEnv<'tcx>,
+ predicates: Vec<ty::Predicate<'tcx>>)
+ -> Result<Vec<ty::Predicate<'tcx>>, ErrorReported>
{
- // I'm not wild about reporting errors here; I'd prefer to
- // have the errors get reported at a defined place (e.g.,
- // during typeck). Instead I have all parameter
- // environments, in effect, going through this function
- // and hence potentially reporting errors. This ensures of
- // course that we never forget to normalize (the
- // alternative seemed like it would involve a lot of
- // manual invocations of this fn -- and then we'd have to
- // deal with the errors at each of those sites).
- //
- // In any case, in practice, typeck constructs all the
- // parameter environments once for every fn as it goes,
- // and errors will get reported then; so after typeck we
- // can be sure that no errors should occur.
-
+ debug!("do_normalize_predicates({:?})", predicates);
let span = cause.span;
-
- debug!("normalize_param_env_or_error(unnormalized_env={:?})",
- unnormalized_env);
-
- let predicates: Vec<_> =
- util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec())
- .collect();
-
- debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
- predicates);
-
- let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
- unnormalized_env.reveal);
-
tcx.infer_ctxt().enter(|infcx| {
// FIXME. We should really... do something with these region
// obligations. But this call just continues the older
// them here too, and we will remove this function when
// we move over to lazy normalization *anyway*.
let fulfill_cx = FulfillmentContext::new_ignoring_regions();
-
let predicates = match fully_normalize(
&infcx,
fulfill_cx,
cause,
elaborated_env,
- // You would really want to pass infcx.param_env.caller_bounds here,
- // but that is an interned slice, and fully_normalize takes &T and returns T, so
- // without further refactoring, a slice can't be used. Luckily, we still have the
- // predicate vector from which we created the ParamEnv in infcx, so we
- // can pass that instead. It's roundabout and a bit brittle, but this code path
- // ought to be refactored anyway, and until then it saves us from having to copy.
&predicates,
) {
Ok(predicates) => predicates,
Err(errors) => {
infcx.report_fulfillment_errors(&errors, None, false);
- // An unnormalized env is better than nothing.
- return elaborated_env;
+ return Err(ErrorReported)
}
};
- debug!("normalize_param_env_or_error: normalized predicates={:?}",
- predicates);
+ debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
let region_scope_tree = region::ScopeTree::default();
// unconstrained variable, and it seems better not to ICE,
// all things considered.
tcx.sess.span_err(span, &fixup_err.to_string());
- // An unnormalized env is better than nothing.
- return elaborated_env;
+ return Err(ErrorReported)
}
};
- let predicates = match tcx.lift_to_global(&predicates) {
- Some(predicates) => predicates,
- None => return elaborated_env,
+ match tcx.lift_to_global(&predicates) {
+ Some(predicates) => Ok(predicates),
+ None => {
+ // FIXME: shouldn't we, you know, actually report an error here? or an ICE?
+ Err(ErrorReported)
+ }
+ }
+ })
+}
+
+// FIXME: this is gonna need to be removed ...
+/// Normalizes the parameter environment, reporting errors if they occur.
+pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ region_context: DefId,
+ unnormalized_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>)
+ -> ty::ParamEnv<'tcx>
+{
+ // I'm not wild about reporting errors here; I'd prefer to
+ // have the errors get reported at a defined place (e.g.,
+ // during typeck). Instead I have all parameter
+ // environments, in effect, going through this function
+ // and hence potentially reporting errors. This ensures of
+ // course that we never forget to normalize (the
+ // alternative seemed like it would involve a lot of
+ // manual invocations of this fn -- and then we'd have to
+ // deal with the errors at each of those sites).
+ //
+ // In any case, in practice, typeck constructs all the
+ // parameter environments once for every fn as it goes,
+ // and errors will get reported then; so after typeck we
+ // can be sure that no errors should occur.
+
+ debug!("normalize_param_env_or_error(region_context={:?}, unnormalized_env={:?}, cause={:?})",
+ region_context, unnormalized_env, cause);
+
+ let mut predicates: Vec<_> =
+ util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec())
+ .collect();
+
+ debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
+ predicates);
+
+ let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
+ unnormalized_env.reveal);
+
+ // HACK: we are trying to normalize the param-env inside *itself*. The problem is that
+ // normalization expects its param-env to be already normalized, which means we have
+ // a circularity.
+ //
+ // The way we handle this is by normalizing the param-env inside an unnormalized version
+ // of the param-env, which means that if the param-env contains unnormalized projections,
+ // we'll have some normalization failures. This is unfortunate.
+ //
+ // Lazy normalization would basically handle this by treating just the
+ // normalizing-a-trait-ref-requires-itself cycles as evaluation failures.
+ //
+ // Inferred outlives bounds can create a lot of `TypeOutlives` predicates for associated
+ // types, so to make the situation less bad, we normalize all the predicates *but*
+ // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and
+ // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment.
+ //
+ // This works fairly well because trait matching does not actually care about param-env
+ // TypeOutlives predicates - these are normally used by regionck.
+ let outlives_predicates: Vec<_> = predicates.drain_filter(|predicate| {
+ match predicate {
+ ty::Predicate::TypeOutlives(..) => true,
+ _ => false
+ }
+ }).collect();
+
+ debug!("normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})",
+ predicates, outlives_predicates);
+ let non_outlives_predicates =
+ match do_normalize_predicates(tcx, region_context, cause.clone(),
+ elaborated_env, predicates) {
+ Ok(predicates) => predicates,
+ // An unnormalized env is better than nothing.
+ Err(ErrorReported) => {
+ debug!("normalize_param_env_or_error: errored resolving non-outlives predicates");
+ return elaborated_env
+ }
};
- debug!("normalize_param_env_or_error: resolved predicates={:?}",
- predicates);
+ debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates);
+
+ // Not sure whether it is better to include the unnormalized TypeOutlives predicates
+ // here. I believe they should not matter, because we are ignoring TypeOutlives param-env
+ // predicates here anyway. Keeping them here anyway because it seems safer.
+ let outlives_env: Vec<_> =
+ non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
+ let outlives_env = ty::ParamEnv::new(tcx.intern_predicates(&outlives_env),
+ unnormalized_env.reveal);
+ let outlives_predicates =
+ match do_normalize_predicates(tcx, region_context, cause,
+ outlives_env, outlives_predicates) {
+ Ok(predicates) => predicates,
+ // An unnormalized env is better than nothing.
+ Err(ErrorReported) => {
+ debug!("normalize_param_env_or_error: errored resolving outlives predicates");
+ return elaborated_env
+ }
+ };
+ debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates);
- ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal)
- })
+ let mut predicates = non_outlives_predicates;
+ predicates.extend(outlives_predicates);
+ debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
+ ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal)
}
pub fn fully_normalize<'a, 'gcx, 'tcx, T>(
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::mir::interpret::ConstEvalErr;
+use rustc::mir::interpret::{ConstValue, ConstEvalErr};
use rustc::mir;
-use rustc::mir::interpret::{ConstValue, ScalarMaybeUndef};
use rustc::ty;
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
use rustc_data_structures::sync::Lrc;
layout.scalar_pair_element_llvm_type(bx.cx, 0, true),
);
let b_layout = layout.scalar_pair_element_llvm_type(bx.cx, 1, true);
- let b_llval = match b {
- ScalarMaybeUndef::Scalar(b) => scalar_to_llvm(
- bx.cx,
- b,
- b_scalar,
- b_layout,
- ),
- ScalarMaybeUndef::Undef => C_undef(b_layout),
- };
+ let b_llval = scalar_to_llvm(
+ bx.cx,
+ b,
+ b_scalar,
+ b_layout,
+ );
OperandValue::Pair(a_llval, b_llval)
},
ConstValue::ByRef(_, alloc, offset) => {
use rustc::mir::interpret::ConstEvalErr;
use rustc::mir;
use rustc::ty::{self, TyCtxt, Instance, query::TyCtxtAt};
-use rustc::ty::layout::{LayoutOf, TyLayout};
+use rustc::ty::layout::{self, LayoutOf, TyLayout};
use rustc::ty::subst::Subst;
use rustc_data_structures::indexed_vec::IndexVec;
pub fn op_to_const<'tcx>(
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
op: OpTy<'tcx>,
- normalize: bool,
+ may_normalize: bool,
) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
+ // We do not normalize just any data. Only scalar layout and fat pointers.
+ let normalize = may_normalize
+ && match op.layout.abi {
+ layout::Abi::Scalar(..) => true,
+ layout::Abi::ScalarPair(..) => {
+ // Must be a fat pointer
+ op.layout.ty.builtin_deref(true).is_some()
+ },
+ _ => false,
+ };
let normalized_op = if normalize {
ecx.try_read_value(op)?
} else {
Ok(Value::Scalar(x)) =>
ConstValue::Scalar(x.not_undef()?),
Ok(Value::ScalarPair(a, b)) =>
- ConstValue::ScalarPair(a.not_undef()?, b),
+ ConstValue::ScalarPair(a.not_undef()?, b.not_undef()?),
};
Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, op.layout.ty))
}
len_b,
),
) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
- let len_a = len_a.not_undef().ok();
- let len_b = len_b.not_undef().ok();
- if len_a.is_none() || len_b.is_none() {
- tcx.sess.struct_err("str slice len is undef").delay_as_bug();
- }
- let len_a = len_a?;
- let len_b = len_b?;
if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) {
if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) {
if len_a == len_b {
use rustc::mir::interpret::{
GlobalId, Scalar, FrameInfo, AllocId,
EvalResult, EvalErrorKind,
- ScalarMaybeUndef,
truncate, sign_extend,
};
use syntax::source_map::{self, Span};
use super::{
- Value, Operand, MemPlace, MPlaceTy, Place,
+ Value, Operand, MemPlace, MPlaceTy, Place, ScalarMaybeUndef,
Memory, Machine
};
use rustc::ty::{self, Instance, query::TyCtxtAt};
use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
-use rustc::mir::interpret::{Pointer, AllocId, Allocation, ConstValue, ScalarMaybeUndef, GlobalId,
+use rustc::mir::interpret::{Pointer, AllocId, Allocation, ConstValue, GlobalId,
EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
truncate};
pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
use syntax::ast::Mutability;
-use super::Machine;
+use super::{Machine, ScalarMaybeUndef};
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub enum MemoryKind<T> {
pub use self::machine::Machine;
-pub use self::operand::{Value, ValTy, Operand, OpTy};
+pub use self::operand::{ScalarMaybeUndef, Value, ValTy, Operand, OpTy};
use rustc::mir::interpret::{
GlobalId, AllocId,
- ConstValue, Pointer, Scalar, ScalarMaybeUndef,
+ ConstValue, Pointer, Scalar,
EvalResult, EvalErrorKind
};
use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
+pub enum ScalarMaybeUndef<Id=AllocId> {
+ Scalar(Scalar<Id>),
+ Undef,
+}
+
+impl From<Scalar> for ScalarMaybeUndef {
+ #[inline(always)]
+ fn from(s: Scalar) -> Self {
+ ScalarMaybeUndef::Scalar(s)
+ }
+}
+
+impl<'tcx> ScalarMaybeUndef {
+ #[inline]
+ pub fn not_undef(self) -> EvalResult<'static, Scalar> {
+ match self {
+ ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
+ ScalarMaybeUndef::Undef => err!(ReadUndefBytes(Size::from_bytes(0))),
+ }
+ }
+
+ #[inline(always)]
+ pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+ self.not_undef()?.to_ptr()
+ }
+
+ #[inline(always)]
+ pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
+ self.not_undef()?.to_bits(target_size)
+ }
+
+ #[inline(always)]
+ pub fn to_bool(self) -> EvalResult<'tcx, bool> {
+ self.not_undef()?.to_bool()
+ }
+
+ #[inline(always)]
+ pub fn to_char(self) -> EvalResult<'tcx, char> {
+ self.not_undef()?.to_char()
+ }
+
+ #[inline(always)]
+ pub fn to_f32(self) -> EvalResult<'tcx, f32> {
+ self.not_undef()?.to_f32()
+ }
+
+ #[inline(always)]
+ pub fn to_f64(self) -> EvalResult<'tcx, f64> {
+ self.not_undef()?.to_f64()
+ }
+
+ #[inline(always)]
+ pub fn to_u8(self) -> EvalResult<'tcx, u8> {
+ self.not_undef()?.to_u8()
+ }
+
+ #[inline(always)]
+ pub fn to_u32(self) -> EvalResult<'tcx, u32> {
+ self.not_undef()?.to_u32()
+ }
+
+ #[inline(always)]
+ pub fn to_u64(self) -> EvalResult<'tcx, u64> {
+ self.not_undef()?.to_u64()
+ }
+
+ #[inline(always)]
+ pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
+ self.not_undef()?.to_usize(cx)
+ }
+
+ #[inline(always)]
+ pub fn to_i8(self) -> EvalResult<'tcx, i8> {
+ self.not_undef()?.to_i8()
+ }
+
+ #[inline(always)]
+ pub fn to_i32(self) -> EvalResult<'tcx, i32> {
+ self.not_undef()?.to_i32()
+ }
+
+ #[inline(always)]
+ pub fn to_i64(self) -> EvalResult<'tcx, i64> {
+ self.not_undef()?.to_i64()
+ }
+
+ #[inline(always)]
+ pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, i64> {
+ self.not_undef()?.to_isize(cx)
+ }
+}
+
+
/// A `Value` represents a single immediate self-contained Rust value.
///
/// For optimization of a few very common cases, there is also a representation for a pair of
Ok(Operand::Indirect(MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)))
},
ConstValue::ScalarPair(a, b) =>
- Ok(Operand::Immediate(Value::ScalarPair(a.into(), b))),
+ Ok(Operand::Immediate(Value::ScalarPair(a.into(), b.into()))),
ConstValue::Scalar(x) =>
Ok(Operand::Immediate(Value::Scalar(x.into()))),
}
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
use rustc::mir::interpret::{
- GlobalId, AllocId, Scalar, EvalResult, Pointer, ScalarMaybeUndef, PointerArithmetic
+ GlobalId, AllocId, Scalar, EvalResult, Pointer, PointerArithmetic
};
-use super::{EvalContext, Machine, Value, ValTy, Operand, OpTy, MemoryKind};
+use super::{EvalContext, Machine, Value, ValTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct MemPlace<Id=AllocId> {
use rustc::ich::{StableHashingContext, StableHashingContextProvider};
use rustc::mir;
use rustc::mir::interpret::{
- AllocId, Pointer, Scalar, ScalarMaybeUndef,
+ AllocId, Pointer, Scalar,
Relocations, Allocation, UndefMask,
EvalResult, EvalErrorKind,
};
use syntax::source_map::Span;
use super::eval_context::{LocalValue, StackPopCleanup};
-use super::{Frame, Memory, Operand, MemPlace, Place, Value};
+use super::{Frame, Memory, Operand, MemPlace, Place, Value, ScalarMaybeUndef};
use const_eval::CompileTimeInterpreter;
#[derive(Default)]
}
}
+impl_stable_hash_for!(enum ::interpret::ScalarMaybeUndef {
+ Scalar(v),
+ Undef
+});
+
impl_snapshot_for!(enum ScalarMaybeUndef {
Scalar(s),
Undef,
use rustc::ty::{self, Ty};
use rustc_data_structures::fx::FxHashSet;
use rustc::mir::interpret::{
- Scalar, AllocType, EvalResult, ScalarMaybeUndef, EvalErrorKind, PointerArithmetic
+ Scalar, AllocType, EvalResult, EvalErrorKind, PointerArithmetic
};
use super::{
- OpTy, Machine, EvalContext
+ OpTy, Machine, EvalContext, ScalarMaybeUndef
};
macro_rules! validation_failure{
use rustc::hir::Node;
use rustc::hir::def_id::DefId;
-use rustc::mir::interpret::{AllocId, ConstValue, ScalarMaybeUndef};
+use rustc::mir::interpret::{AllocId, ConstValue};
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
use rustc::ty::subst::Substs;
use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind};
};
match val {
ConstValue::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
- ConstValue::ScalarPair(Scalar::Ptr(a), ScalarMaybeUndef::Scalar(Scalar::Ptr(b))) => {
+ ConstValue::ScalarPair(Scalar::Ptr(a), Scalar::Ptr(b)) => {
collect_miri(tcx, a.alloc_id, output);
collect_miri(tcx, b.alloc_id, output);
}
- ConstValue::ScalarPair(_, ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr))) |
+ ConstValue::ScalarPair(_, Scalar::Ptr(ptr)) |
ConstValue::ScalarPair(Scalar::Ptr(ptr), _) |
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
collect_miri(tcx, ptr.alloc_id, output),
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
use rustc::mir::visit::{Visitor, PlaceContext};
use rustc::mir::interpret::{
- ConstEvalErr, EvalErrorKind, ScalarMaybeUndef, Scalar, GlobalId, EvalResult
+ ConstEvalErr, EvalErrorKind, Scalar, GlobalId, EvalResult
};
use rustc::ty::{TyCtxt, self, Instance};
-use interpret::{self, EvalContext, Value, OpTy, MemoryKind};
+use interpret::{self, EvalContext, Value, OpTy, MemoryKind, ScalarMaybeUndef};
use const_eval::{CompileTimeInterpreter, eval_promoted, mk_borrowck_eval_cx};
use transform::{MirPass, MirSource};
use syntax::source_map::{Span, DUMMY_SP};
// Make the base error.
let expected = source.descr_expected();
let path_str = names_to_string(path);
+ let item_str = path[path.len() - 1];
let code = source.error_code(def.is_some());
let (base_msg, fallback_label, base_span) = if let Some(def) = def {
(format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str),
format!("not a {}", expected),
span)
} else {
- let item_str = path[path.len() - 1];
let item_span = path[path.len() - 1].span;
let (mod_prefix, mod_str) = if path.len() == 1 {
(String::new(), "this scope".to_string())
let code = DiagnosticId::Error(code.into());
let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code);
+ // Emit help message for fake-self from other languages like `this`(javascript)
+ let fake_self: Vec<Ident> = ["this", "my"].iter().map(
+ |s| Ident::from_str(*s)
+ ).collect();
+ if fake_self.contains(&item_str)
+ && this.self_value_is_available(path[0].span, span) {
+ err.span_suggestion_with_applicability(
+ span,
+ "did you mean",
+ "self".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+
// Emit special messages for unresolved `Self` and `self`.
if is_self_type(path, ns) {
__diagnostic_used!(E0411);
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Stream {
+ type Item;
+ type Error;
+}
+
+pub trait ParseError<I> {
+ type Output;
+}
+
+impl ParseError<char> for u32 {
+ type Output = ();
+}
+
+impl Stream for () {
+ type Item = char;
+ type Error = u32;
+}
+
+pub struct Lex<'a, I>
+ where I: Stream,
+ I::Error: ParseError<char>,
+ <<I as Stream>::Error as ParseError<char>>::Output: 'a
+{
+ x: &'a <I::Error as ParseError<char>>::Output
+}
+
+pub struct Reserved<'a, I> where
+ I: Stream<Item=char> + 'a,
+ I::Error: ParseError<I::Item>,
+ <<I as Stream>::Error as ParseError<char>>::Output: 'a
+
+{
+ x: Lex<'a, I>
+}
+
+fn main() {
+ let r: Reserved<()> = Reserved {
+ x: Lex {
+ x: &()
+ }
+ };
+
+ let _v = r.x.x;
+}
const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR this constant cannot be used
-const FIELD_PATH: Struct = Struct { //~ ERROR this constant cannot be used
+const FIELD_PATH: Struct = Struct { //~ ERROR this constant likely exhibits undefined behavior
a: 42,
b: unsafe { UNION.field3 },
};
|
= note: #[deny(const_err)] on by default
-error: this constant cannot be used
+error[E0080]: this constant likely exhibits undefined behavior
--> $DIR/union-ice.rs:25:1
|
-LL | / const FIELD_PATH: Struct = Struct { //~ ERROR this constant cannot be used
+LL | / const FIELD_PATH: Struct = Struct { //~ ERROR this constant likely exhibits undefined behavior
LL | | a: 42,
LL | | b: unsafe { UNION.field3 },
LL | | };
- | |__^ attempted to read undefined bytes
+ | |__^ type validation failed: encountered undefined bytes at .b
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
error[E0080]: this constant likely exhibits undefined behavior
--> $DIR/union-ice.rs:35:1
--- /dev/null
+// compile-pass
+
+pub struct GstRc {
+ _obj: *const (),
+ _borrowed: bool,
+}
+
+const FOO: Option<GstRc> = None;
+
+fn main() {
+ let _meh = FOO;
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo {
+ x: i32,
+}
+
+impl Foo {
+ fn this1(&self) -> i32 {
+ let this = self;
+ let a = 1;
+ this.x
+ }
+
+ fn this2(&self) -> i32 {
+ let a = Foo {
+ x: 2
+ };
+ let this = a;
+ this.x
+ }
+
+ fn foo(&self) -> i32 {
+ this.x
+ //~^ ERROR cannot find value `this` in this scope
+ }
+
+ fn bar(&self) -> i32 {
+ this.foo()
+ //~^ ERROR cannot find value `this` in this scope
+ }
+
+ fn baz(&self) -> i32 {
+ my.bar()
+ //~^ ERROR cannot find value `my` in this scope
+ }
+}
+
+fn main() {
+ let this = vec![1, 2, 3];
+ let my = vec![1, 2, 3];
+ let len = this.len();
+ let len = my.len();
+}
+
--- /dev/null
+error[E0425]: cannot find value `this` in this scope
+ --> $DIR/suggest-self.rs:31:9
+ |
+LL | this.x
+ | ^^^^
+ | |
+ | not found in this scope
+ | help: did you mean: `self`
+
+error[E0425]: cannot find value `this` in this scope
+ --> $DIR/suggest-self.rs:36:9
+ |
+LL | this.foo()
+ | ^^^^
+ | |
+ | not found in this scope
+ | help: did you mean: `self`
+
+error[E0425]: cannot find value `my` in this scope
+ --> $DIR/suggest-self.rs:41:9
+ |
+LL | my.bar()
+ | ^^
+ | |
+ | not found in this scope
+ | help: did you mean: `self`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
-Subproject commit a72e786c5d8866d554effd246c30fb553b63fa06
+Subproject commit e69fe2fb19b7b2f3b07fe1178c536810dabf896f