diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d254d50e8bd05..dd2a3978d8844 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -611,7 +611,7 @@ pub enum BindingAnnotation { RefMut, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum RangeEnd { Included, Excluded, diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 9a061da177eba..dce1639b375b7 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -493,10 +493,6 @@ impl<'a, 'gcx, 'tcx> HashStable> for mir::L hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { - mir::Literal::Item { def_id, substs } => { - def_id.hash_stable(hcx, hasher); - substs.hash_stable(hcx, hasher); - } mir::Literal::Value { ref value } => { value.hash_stable(hcx, hasher); } diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 077905b3ac0ae..e933ca4c2b551 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -16,7 +16,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::hash as std_hash; use std::mem; -use syntax_pos::symbol::InternedString; use middle::region; use ty; @@ -236,6 +235,10 @@ impl<'a, 'gcx, 'tcx> HashStable> for ty::Pr def_id.hash_stable(hcx, hasher); closure_kind.hash_stable(hcx, hasher); } + ty::Predicate::ConstEvaluatable(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } } } } @@ -272,59 +275,69 @@ for ::middle::const_val::ConstVal<'gcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { - use middle::const_val::ConstVal; + use middle::const_val::ConstVal::*; + use middle::const_val::ConstAggregate::*; mem::discriminant(self).hash_stable(hcx, hasher); match *self { - ConstVal::Float(ref value) => { + Integral(ref value) => { value.hash_stable(hcx, hasher); } - ConstVal::Integral(ref value) => { + Float(ref value) => { value.hash_stable(hcx, hasher); } - ConstVal::Str(ref value) => { + Str(ref value) => { value.hash_stable(hcx, hasher); } - ConstVal::ByteStr(ref value) => { + ByteStr(ref value) => { value.hash_stable(hcx, hasher); } - ConstVal::Bool(value) => { + Bool(value) => { value.hash_stable(hcx, hasher); } - ConstVal::Char(value) => { + Char(value) => { value.hash_stable(hcx, hasher); } - ConstVal::Variant(def_id) => { + Variant(def_id) => { def_id.hash_stable(hcx, hasher); } - ConstVal::Function(def_id, substs) => { + Function(def_id, substs) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } - ConstVal::Struct(ref name_value_map) => { - let mut values: Vec<(InternedString, &ConstVal)> = - name_value_map.iter() - .map(|(name, val)| (name.as_str(), val)) - .collect(); - + Aggregate(Struct(ref name_values)) => { + let mut values = name_values.to_vec(); values.sort_unstable_by_key(|&(ref name, _)| name.clone()); values.hash_stable(hcx, hasher); } - ConstVal::Tuple(ref value) => { + Aggregate(Tuple(ref value)) => { value.hash_stable(hcx, hasher); } - ConstVal::Array(ref value) => { + Aggregate(Array(ref value)) => { value.hash_stable(hcx, hasher); } - ConstVal::Repeat(ref value, times) => { + Aggregate(Repeat(ref value, times)) => { value.hash_stable(hcx, hasher); times.hash_stable(hcx, hasher); } + Unevaluated(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } } } } +impl_stable_hash_for!(struct ::middle::const_val::ByteArray<'tcx> { + data +}); + +impl_stable_hash_for!(struct ty::Const<'tcx> { + ty, + val +}); + impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); impl_stable_hash_for!(struct ty::GeneratorInterior<'tcx> { witness }); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 3fe3a3dc58560..6ccf7e42fd5fd 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -442,6 +442,7 @@ macro_rules! impl_trans_normalize { impl_trans_normalize!('gcx, Ty<'gcx>, + &'gcx ty::Const<'gcx>, &'gcx Substs<'gcx>, ty::FnSig<'gcx>, ty::PolyFnSig<'gcx>, @@ -493,7 +494,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let param_env = ty::ParamEnv::empty(Reveal::All); let value = self.erase_regions(value); - if !value.has_projection_types() { + if !value.has_projections() { return value; } @@ -515,7 +516,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let value = self.erase_regions(value); - if !value.has_projection_types() { + if !value.has_projections() { return value; } diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index b6b1648f39687..7b23998046730 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -8,64 +8,66 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use self::ConstVal::*; pub use rustc_const_math::ConstInt; -use hir; -use hir::def::Def; use hir::def_id::DefId; -use traits::Reveal; use ty::{self, TyCtxt, layout}; use ty::subst::Substs; -use util::common::ErrorReported; use rustc_const_math::*; use graphviz::IntoCow; use errors::DiagnosticBuilder; +use serialize::{self, Encodable, Encoder, Decodable, Decoder}; use syntax::symbol::InternedString; use syntax::ast; use syntax_pos::Span; use std::borrow::Cow; -use std::collections::BTreeMap; -use std::rc::Rc; -pub type EvalResult<'tcx> = Result, ConstEvalErr<'tcx>>; +pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>; -#[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] pub enum ConstVal<'tcx> { - Float(ConstFloat), Integral(ConstInt), + Float(ConstFloat), Str(InternedString), - ByteStr(Rc>), + ByteStr(ByteArray<'tcx>), Bool(bool), Char(char), Variant(DefId), Function(DefId, &'tcx Substs<'tcx>), - Struct(BTreeMap>), - Tuple(Vec>), - Array(Vec>), - Repeat(Box>, u64), + Aggregate(ConstAggregate<'tcx>), + Unevaluated(DefId, &'tcx Substs<'tcx>), } -impl<'tcx> ConstVal<'tcx> { - pub fn description(&self) -> &'static str { - match *self { - Float(f) => f.description(), - Integral(i) => i.description(), - Str(_) => "string literal", - ByteStr(_) => "byte string literal", - Bool(_) => "boolean", - Char(..) => "char", - Variant(_) => "enum variant", - Struct(_) => "struct", - Tuple(_) => "tuple", - Function(..) => "function definition", - Array(..) => "array", - Repeat(..) => "repeat", - } +#[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)] +pub struct ByteArray<'tcx> { + pub data: &'tcx [u8], +} + +impl<'tcx> serialize::UseSpecializedDecodable for ByteArray<'tcx> {} + +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub enum ConstAggregate<'tcx> { + Struct(&'tcx [(ast::Name, &'tcx ty::Const<'tcx>)]), + Tuple(&'tcx [&'tcx ty::Const<'tcx>]), + Array(&'tcx [&'tcx ty::Const<'tcx>]), + Repeat(&'tcx ty::Const<'tcx>, u64), +} + +impl<'tcx> Encodable for ConstAggregate<'tcx> { + fn encode(&self, _: &mut S) -> Result<(), S::Error> { + bug!("should never encode ConstAggregate::{:?}", self) + } +} + +impl<'tcx> Decodable for ConstAggregate<'tcx> { + fn decode(_: &mut D) -> Result { + bug!("should never decode ConstAggregate") } +} +impl<'tcx> ConstVal<'tcx> { pub fn to_const_int(&self) -> Option { match *self { ConstVal::Integral(i) => Some(i), @@ -86,8 +88,6 @@ pub struct ConstEvalErr<'tcx> { pub enum ErrKind<'tcx> { CannotCast, MissingStructField, - NegateOn(ConstVal<'tcx>), - NotOn(ConstVal<'tcx>), NonConstPath, UnimplementedConstVal(&'static str), @@ -146,9 +146,6 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { match self.kind { CannotCast => simple!("can't cast this type"), - NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), - NotOn(ref const_val) => simple!("not on {}", const_val.description()), - MissingStructField => simple!("nonexistent struct field"), NonConstPath => simple!("non-constant path in constant expression"), UnimplementedConstVal(what) => @@ -221,37 +218,3 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { self.struct_error(tcx, primary_span, primary_kind).emit(); } } - -/// Returns the value of the length-valued expression -pub fn eval_length(tcx: TyCtxt, - count: hir::BodyId, - reason: &str) - -> Result -{ - let count_expr = &tcx.hir.body(count).value; - let count_def_id = tcx.hir.body_owner_def_id(count); - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); - let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id); - match tcx.at(count_expr.span).const_eval(param_env.and((count_def_id, substs))) { - Ok(Integral(Usize(count))) => { - let val = count.as_u64(tcx.sess.target.uint_type); - assert_eq!(val as usize as u64, val); - Ok(val as usize) - }, - Ok(_) | - Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported), - Err(err) => { - let mut diag = err.struct_error(tcx, count_expr.span, reason); - - if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { - if let Def::Local(..) = path.def { - diag.note(&format!("`{}` is a variable", - tcx.hir.node_to_pretty_string(count_expr.id))); - } - } - - diag.emit(); - Err(ErrorReported) - } - } -} diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index d4cee25bb8fa2..4de86b669160e 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -147,7 +147,8 @@ impl<'tcx> FreeRegionMap<'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) => { + ty::Predicate::TypeOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => { // No region bounds here } ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 8bf942c1ae34f..5102b41598d6f 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -876,7 +876,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Always promote `[T; 0]` (even when e.g. borrowed mutably). let promotable = match expr_ty.sty { - ty::TyArray(_, 0) => true, + ty::TyArray(_, len) if + len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true, _ => promotable, }; diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index e63162c68c0f1..38dfe010c153c 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1187,10 +1187,16 @@ impl<'tcx> Operand<'tcx> { substs: &'tcx Substs<'tcx>, span: Span, ) -> Self { + let ty = tcx.type_of(def_id).subst(tcx, substs); Operand::Constant(box Constant { span, - ty: tcx.type_of(def_id).subst(tcx, substs), - literal: Literal::Value { value: ConstVal::Function(def_id, substs) }, + ty, + literal: Literal::Value { + value: tcx.mk_const(ty::Const { + val: ConstVal::Function(def_id, substs), + ty + }) + }, }) } @@ -1473,12 +1479,8 @@ newtype_index!(Promoted, "promoted"); #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum Literal<'tcx> { - Item { - def_id: DefId, - substs: &'tcx Substs<'tcx>, - }, Value { - value: ConstVal<'tcx>, + value: &'tcx ty::Const<'tcx>, }, Promoted { // Index into the `promoted` vector of `Mir`. @@ -1496,12 +1498,9 @@ impl<'tcx> Debug for Literal<'tcx> { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { use self::Literal::*; match *self { - Item { def_id, substs } => { - ppaux::parameterized(fmt, substs, def_id, &[]) - } - Value { ref value } => { + Value { value } => { write!(fmt, "const ")?; - fmt_const_val(fmt, value) + fmt_const_val(fmt, &value.val) } Promoted { index } => { write!(fmt, "{:?}", index) @@ -1516,9 +1515,9 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { match *const_val { Float(f) => write!(fmt, "{:?}", f), Integral(n) => write!(fmt, "{}", n), - Str(ref s) => write!(fmt, "{:?}", s), - ByteStr(ref bytes) => { - let escaped: String = bytes + Str(s) => write!(fmt, "{:?}", s), + ByteStr(bytes) => { + let escaped: String = bytes.data .iter() .flat_map(|&ch| ascii::escape_default(ch).map(|c| c as char)) .collect(); @@ -1528,8 +1527,8 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { Char(c) => write!(fmt, "{:?}", c), Variant(def_id) | Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), - Struct(_) | Tuple(_) | Array(_) | Repeat(..) => - bug!("ConstVal `{:?}` should not be in MIR", const_val), + Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val), + Unevaluated(..) => write!(fmt, "{:?}", const_val) } } @@ -1996,17 +1995,16 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { - Literal::Item { def_id, substs } => Literal::Item { - def_id, - substs: substs.fold_with(folder) + Literal::Value { value } => Literal::Value { + value: value.fold_with(folder) }, - _ => self.clone() + Literal::Promoted { index } => Literal::Promoted { index } } } fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { - Literal::Item { substs, .. } => substs.visit_with(visitor), - _ => false + Literal::Value { value } => value.visit_with(visitor), + Literal::Promoted { .. } => false } } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index eb403442f4639..d645a00e15781 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -70,7 +70,9 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { LvalueTy::Ty { ty: match ty.sty { ty::TyArray(inner, size) => { - tcx.mk_array(inner, size-(from as usize)-(to as usize)) + let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let len = size - (from as u64) - (to as u64); + tcx.mk_array(inner, len) } ty::TySlice(..) => ty, _ => { @@ -146,11 +148,8 @@ impl<'tcx> Rvalue<'tcx> { { match *self { Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), - Rvalue::Repeat(ref operand, ref count) => { - let op_ty = operand.ty(local_decls, tcx); - let count = count.as_u64(tcx.sess.target.uint_type); - assert_eq!(count as usize as u64, count); - tcx.mk_array(op_ty, count as usize) + Rvalue::Repeat(ref operand, count) => { + tcx.mk_array_const_usize(operand.ty(local_decls, tcx), count) } Rvalue::Ref(reg, bk, ref lv) => { let lv_ty = lv.ty(local_decls, tcx).to_ty(tcx); @@ -193,7 +192,7 @@ impl<'tcx> Rvalue<'tcx> { Rvalue::Aggregate(ref ak, ref ops) => { match **ak { AggregateKind::Array(ty) => { - tcx.mk_array(ty, ops.len()) + tcx.mk_array(ty, ops.len() as u64) } AggregateKind::Tuple => { tcx.mk_tup( diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index f26505c6d0237..37c97ad3dad90 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::const_val::ConstVal; use hir::def_id::DefId; use ty::subst::Substs; use ty::{ClosureSubsts, Region, Ty, GeneratorInterior}; @@ -214,6 +213,18 @@ macro_rules! make_mir_visitor { self.super_ty(ty); } + fn visit_region(&mut self, + region: & $($mutability)* ty::Region<'tcx>, + _: Location) { + self.super_region(region); + } + + fn visit_const(&mut self, + constant: & $($mutability)* &'tcx ty::Const<'tcx>, + _: Location) { + self.super_const(constant); + } + fn visit_substs(&mut self, substs: & $($mutability)* &'tcx Substs<'tcx>, _: Location) { @@ -232,12 +243,6 @@ macro_rules! make_mir_visitor { self.super_generator_interior(interior); } - fn visit_const_val(&mut self, - const_val: & $($mutability)* ConstVal, - _: Location) { - self.super_const_val(const_val); - } - fn visit_const_int(&mut self, const_int: &ConstInt, _: Location) { @@ -517,9 +522,10 @@ macro_rules! make_mir_visitor { self.visit_const_usize(length, location); } - Rvalue::Ref(r, bk, ref $($mutability)* path) => { + Rvalue::Ref(ref $($mutability)* r, bk, ref $($mutability)* path) => { + self.visit_region(r, location); self.visit_lvalue(path, LvalueContext::Borrow { - region: r, + region: *r, kind: bk }, location); } @@ -718,13 +724,8 @@ macro_rules! make_mir_visitor { literal: & $($mutability)* Literal<'tcx>, location: Location) { match *literal { - Literal::Item { ref $($mutability)* def_id, - ref $($mutability)* substs } => { - self.visit_def_id(def_id, location); - self.visit_substs(substs, location); - } Literal::Value { ref $($mutability)* value } => { - self.visit_const_val(value, location); + self.visit_const(value, location); } Literal::Promoted { index: _ } => {} } @@ -749,6 +750,12 @@ macro_rules! make_mir_visitor { fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) { } + fn super_region(&mut self, _region: & $($mutability)* ty::Region<'tcx>) { + } + + fn super_const(&mut self, _const: & $($mutability)* &'tcx ty::Const<'tcx>) { + } + fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) { } @@ -760,9 +767,6 @@ macro_rules! make_mir_visitor { _substs: & $($mutability)* ClosureSubsts<'tcx>) { } - fn super_const_val(&mut self, _const_val: & $($mutability)* ConstVal) { - } - fn super_const_int(&mut self, _const_int: &ConstInt) { } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 577c905a1d5a6..b7e07f94f3df1 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -48,8 +48,8 @@ use std::path::PathBuf; pub struct Config { pub target: Target, - pub int_type: IntTy, - pub uint_type: UintTy, + pub isize_ty: IntTy, + pub usize_ty: UintTy, } #[derive(Clone, Hash, Debug)] @@ -1149,7 +1149,7 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config { } }; - let (int_type, uint_type) = match &target.target_pointer_width[..] { + let (isize_ty, usize_ty) = match &target.target_pointer_width[..] { "16" => (ast::IntTy::I16, ast::UintTy::U16), "32" => (ast::IntTy::I32, ast::UintTy::U32), "64" => (ast::IntTy::I64, ast::UintTy::U64), @@ -1159,8 +1159,8 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config { Config { target, - int_type, - uint_type, + isize_ty, + usize_ty, } } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index cfbd4ba055e3c..b491baadd7c2b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -19,6 +19,7 @@ use super::{ OnUnimplementedNote, OutputTypeParameterMismatch, TraitNotObjectSafe, + ConstEvalFailure, PredicateObligation, Reveal, SelectionContext, @@ -31,6 +32,7 @@ use hir; use hir::def_id::DefId; use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; +use middle::const_val; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; use syntax::ast; @@ -698,6 +700,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // (which may fail). span_bug!(span, "WF predicate not satisfied for {:?}", ty); } + + ty::Predicate::ConstEvaluatable(..) => { + // Errors for `ConstEvaluatable` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + span_bug!(span, + "const-evaluatable requirement gave wrong error: `{:?}`", obligation) + } } } @@ -762,6 +772,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.report_object_safety_error(span, did, violations) } + + ConstEvalFailure(ref err) => { + if let const_val::ErrKind::TypeckError = err.kind { + return; + } + err.struct_error(self.tcx, span, "constant expression") + } }; self.note_obligation_cause(&mut err, obligation); err.emit(); diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index fbc393cbd96f2..cc2506d1afc50 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -25,7 +25,7 @@ use super::{FulfillmentError, FulfillmentErrorCode}; use super::{ObligationCause, PredicateObligation, Obligation}; use super::project; use super::select::SelectionContext; -use super::Unimplemented; +use super::{Unimplemented, ConstEvalFailure}; impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { type Predicate = ty::Predicate<'tcx>; @@ -540,6 +540,29 @@ fn process_predicate<'a, 'gcx, 'tcx>( } } } + + ty::Predicate::ConstEvaluatable(def_id, substs) => { + match selcx.tcx().lift_to_global(&obligation.param_env) { + None => { + Ok(None) + } + Some(param_env) => { + match selcx.tcx().lift_to_global(&substs) { + None => { + pending_obligation.stalled_on = substs.types().collect(); + Ok(None) + } + Some(substs) => { + match selcx.tcx().at(obligation.cause.span) + .const_eval(param_env.and((def_id, substs))) { + Ok(_) => Ok(Some(vec![])), + Err(e) => Err(CodeSelectionError(ConstEvalFailure(e))) + } + } + } + } + } + } } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 22c92776c5e4e..fb71d9cc49b9e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -17,6 +17,7 @@ pub use self::ObligationCauseCode::*; use hir; use hir::def_id::DefId; +use middle::const_val::ConstEvalErr; use middle::region; use middle::free_region::FreeRegionMap; use ty::subst::Substs; @@ -218,6 +219,7 @@ pub enum SelectionError<'tcx> { ty::PolyTraitRef<'tcx>, ty::error::TypeError<'tcx>), TraitNotObjectSafe(DefId), + ConstEvalFailure(ConstEvalErr<'tcx>), } pub struct FulfillmentError<'tcx> { diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index fd6d5a86a7fd1..1e9816095ea2e 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -169,7 +169,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::Subtype(..) | - ty::Predicate::Equate(..) => { + ty::Predicate::Equate(..) | + ty::Predicate::ConstEvaluatable(..) => { false } } @@ -203,7 +204,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) => { + ty::Predicate::TypeOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => { false } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 9a0d76144368a..54e31aed272a3 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -27,10 +27,11 @@ use super::util; use hir::def_id::DefId; use infer::{InferCtxt, InferOk}; use infer::type_variable::TypeVariableOrigin; +use middle::const_val::ConstVal; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use syntax::ast; use syntax::symbol::Symbol; -use ty::subst::Subst; +use ty::subst::{Subst, Substs}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; @@ -260,7 +261,7 @@ impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> { fn fold>(&mut self, value: &T) -> T { let value = self.selcx.infcx().resolve_type_vars_if_possible(value); - if !value.has_projection_types() { + if !value.has_projections() { value.clone() } else { value.fold_with(self) @@ -332,6 +333,39 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, } } } + + fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + if let ConstVal::Unevaluated(def_id, substs) = constant.val { + if substs.needs_infer() { + let identity_substs = Substs::identity_for_item(self.tcx(), def_id); + let data = self.param_env.and((def_id, identity_substs)); + match self.tcx().lift_to_global(&data) { + Some(data) => { + match self.tcx().const_eval(data) { + Ok(evaluated) => { + let evaluated = evaluated.subst(self.tcx(), substs); + return self.fold_const(evaluated); + } + Err(_) => {} + } + } + None => {} + } + } else { + let data = self.param_env.and((def_id, substs)); + match self.tcx().lift_to_global(&data) { + Some(data) => { + match self.tcx().const_eval(data) { + Ok(evaluated) => return self.fold_const(evaluated), + Err(_) => {} + } + } + None => {} + } + } + } + constant + } } #[derive(Clone)] @@ -520,7 +554,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( depth, obligations); - let result = if projected_ty.has_projection_types() { + let result = if projected_ty.has_projections() { let mut normalizer = AssociatedTypeNormalizer::new(selcx, param_env, cause, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 98bb3fb0ba94a..f5f69ad0a7cec 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -732,6 +732,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } } + + ty::Predicate::ConstEvaluatable(def_id, substs) => { + match self.tcx().lift_to_global(&(obligation.param_env, substs)) { + Some((param_env, substs)) => { + match self.tcx().const_eval(param_env.and((def_id, substs))) { + Ok(_) => EvaluatedToOk, + Err(_) => EvaluatedToErr + } + } + None => { + // Inference variables still left in param_env or substs. + EvaluatedToAmbig + } + } + } } } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 674da297cd959..19ed03aa14917 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -173,6 +173,9 @@ 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(super::ConstEvalFailure) + } } } } diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index 827a5092c0042..9c4a260b35d49 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -120,7 +120,7 @@ impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> { } fn fold>(&mut self, value: &T) -> T { - if !value.has_projection_types() { + if !value.has_projections() { value.clone() } else { value.fold_with(self) @@ -134,7 +134,7 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { } fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { - if !ty.has_projection_types() { + if !ty.has_projections() { ty } else { self.tcx.trans_trait_caches.project_cache.memoize(ty, || { diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index b0d6f4d5a3130..42e0834e8e43b 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -48,6 +48,9 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::Predicate::Subtype(ref data) => ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::ConstEvaluatable(def_id, substs) => + ty::Predicate::ConstEvaluatable(def_id, substs), } } @@ -175,6 +178,10 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { ty::Predicate::ClosureKind(..) => { // Nothing to elaborate when waiting for a closure's kind to be inferred. } + ty::Predicate::ConstEvaluatable(..) => { + // Currently, we do not elaborate const-evaluatable + // predicates. + } ty::Predicate::RegionOutlives(..) => { // Nothing to elaborate from `'a: 'b`. diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 2a0dc455f470f..6d12731307d63 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -21,6 +21,7 @@ use hir::map as hir_map; use hir::map::DefPathHash; use lint::{self, Lint}; use ich::{self, StableHashingContext, NodeIdHashingMode}; +use middle::const_val::ConstVal; use middle::free_region::FreeRegionMap; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; @@ -32,7 +33,7 @@ use ty::ReprOptions; use traits; use ty::{self, Ty, TypeAndMut}; use ty::{TyS, TypeVariants, Slice}; -use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region}; +use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region, Const}; use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate}; use ty::RegionKind; use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; @@ -49,6 +50,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use arena::{TypedArena, DroplessArena}; +use rustc_const_math::{ConstInt, ConstUsize}; use rustc_data_structures::indexed_vec::IndexVec; use std::borrow::Borrow; use std::cell::{Cell, RefCell}; @@ -108,6 +110,7 @@ pub struct CtxtInterners<'tcx> { region: RefCell>>, existential_predicates: RefCell>>>>, predicates: RefCell>>>>, + const_: RefCell>>>, } impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { @@ -120,6 +123,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { region: RefCell::new(FxHashSet()), existential_predicates: RefCell::new(FxHashSet()), predicates: RefCell::new(FxHashSet()), + const_: RefCell::new(FxHashSet()), } } @@ -934,6 +938,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.global_arenas.adt_def.alloc(def) } + pub fn alloc_byte_array(self, bytes: &[u8]) -> &'gcx [u8] { + if bytes.is_empty() { + &[] + } else { + self.global_interners.arena.alloc_slice(bytes) + } + } + + pub fn alloc_const_slice(self, values: &[&'tcx ty::Const<'tcx>]) + -> &'tcx [&'tcx ty::Const<'tcx>] { + if values.is_empty() { + &[] + } else { + self.interners.arena.alloc_slice(values) + } + } + + pub fn alloc_name_const_slice(self, values: &[(ast::Name, &'tcx ty::Const<'tcx>)]) + -> &'tcx [(ast::Name, &'tcx ty::Const<'tcx>)] { + if values.is_empty() { + &[] + } else { + self.interners.arena.alloc_slice(values) + } + } + pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability { if let Some(st) = self.stability_interner.borrow().get(&stab) { return st; @@ -1160,18 +1190,6 @@ pub trait Lift<'tcx> { fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option; } -impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { - type Lifted = ty::ParamEnv<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { - self.caller_bounds.lift_to_tcx(tcx).and_then(|caller_bounds| { - Some(ty::ParamEnv { - reveal: self.reveal, - caller_bounds, - }) - }) - } -} - impl<'a, 'tcx> Lift<'tcx> for Ty<'a> { type Lifted = Ty<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { @@ -1187,13 +1205,10 @@ impl<'a, 'tcx> Lift<'tcx> for Ty<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> { - type Lifted = &'tcx Substs<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> { - if self.len() == 0 { - return Some(Slice::empty()); - } - if tcx.interners.arena.in_arena(&self[..] as *const _) { +impl<'a, 'tcx> Lift<'tcx> for Region<'a> { + type Lifted = Region<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { + if tcx.interners.arena.in_arena(*self as *const _) { return Some(unsafe { mem::transmute(*self) }); } // Also try in the global tcx if we're not that. @@ -1205,9 +1220,9 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for Region<'a> { - type Lifted = Region<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { +impl<'a, 'tcx> Lift<'tcx> for &'a Const<'a> { + type Lifted = &'tcx Const<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Const<'tcx>> { if tcx.interners.arena.in_arena(*self as *const _) { return Some(unsafe { mem::transmute(*self) }); } @@ -1220,6 +1235,24 @@ impl<'a, 'tcx> Lift<'tcx> for Region<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> { + type Lifted = &'tcx Substs<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> { + if self.len() == 0 { + return Some(Slice::empty()); + } + if tcx.interners.arena.in_arena(&self[..] as *const _) { + return Some(unsafe { mem::transmute(*self) }); + } + // Also try in the global tcx if we're not that. + if !tcx.is_global() { + self.lift_to_tcx(tcx.global_tcx()) + } else { + None + } + } +} + impl<'a, 'tcx> Lift<'tcx> for &'a Slice> { type Lifted = &'tcx Slice>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) @@ -1507,6 +1540,12 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Predicate<'lcx>]> } } +impl<'tcx: 'lcx, 'lcx> Borrow> for Interned<'tcx, Const<'tcx>> { + fn borrow<'a>(&'a self) -> &'a Const<'lcx> { + &self.0 + } +} + macro_rules! intern_method { ($lt_tcx:tt, $name:ident: $method:ident($alloc:ty, $alloc_method:ident, @@ -1587,7 +1626,8 @@ direct_interners!('tcx, &ty::ReVar(_) | &ty::ReSkolemized(..) => true, _ => false } - }) -> RegionKind + }) -> RegionKind, + const_: mk_const(|c: &Const| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx> ); macro_rules! slice_interners { @@ -1704,8 +1744,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_imm_ptr(self.mk_nil()) } - pub fn mk_array(self, ty: Ty<'tcx>, n: usize) -> Ty<'tcx> { - self.mk_ty(TyArray(ty, n)) + pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { + let n = ConstUsize::new(n, self.sess.target.usize_ty).unwrap(); + self.mk_array_const_usize(ty, n) + } + + pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> { + self.mk_ty(TyArray(ty, self.mk_const(ty::Const { + val: ConstVal::Integral(ConstInt::Usize(n)), + ty: self.types.usize + }))) } pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 49d7f40000f07..52a8389bd8f5f 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -10,6 +10,7 @@ use hir::def_id::DefId; use infer::type_variable; +use middle::const_val::ConstVal; use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt}; use std::fmt; @@ -18,6 +19,8 @@ use syntax::ast; use errors::DiagnosticBuilder; use syntax_pos::Span; +use rustc_const_math::ConstInt; + use hir; #[derive(Clone, Copy, Debug)] @@ -34,7 +37,7 @@ pub enum TypeError<'tcx> { AbiMismatch(ExpectedFound), Mutability, TupleSize(ExpectedFound), - FixedArraySize(ExpectedFound), + FixedArraySize(ExpectedFound), ArgCount, RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), @@ -179,7 +182,13 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(), ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), - ty::TyArray(_, n) => format!("array of {} elements", n), + ty::TyArray(_, n) => { + if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { + format!("array of {} elements", n) + } else { + "array".to_string() + } + } ty::TySlice(_) => "slice".to_string(), ty::TyRawPtr(_) => "*-ptr".to_string(), ty::TyRef(region, tymut) => { diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 27b8d245396c9..9ece719c76470 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::const_val::{ConstVal, ConstAggregate}; use ty::subst::Substs; use ty::{self, Ty, TypeFlags, TypeFoldable}; @@ -145,7 +146,12 @@ impl FlagComputation { self.add_region(r); } - &ty::TyArray(tt, _) | &ty::TySlice(tt) => { + &ty::TyArray(tt, len) => { + self.add_ty(tt); + self.add_const(len); + } + + &ty::TySlice(tt) => { self.add_ty(tt) } @@ -202,6 +208,40 @@ impl FlagComputation { } } + fn add_const(&mut self, constant: &ty::Const) { + self.add_ty(constant.ty); + match constant.val { + ConstVal::Integral(_) | + ConstVal::Float(_) | + ConstVal::Str(_) | + ConstVal::ByteStr(_) | + ConstVal::Bool(_) | + ConstVal::Char(_) | + ConstVal::Variant(_) => {} + ConstVal::Function(_, substs) => { + self.add_substs(substs); + } + ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { + for &(_, v) in fields { + self.add_const(v); + } + } + ConstVal::Aggregate(ConstAggregate::Tuple(fields)) | + ConstVal::Aggregate(ConstAggregate::Array(fields)) => { + for v in fields { + self.add_const(v); + } + } + ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { + self.add_const(v); + } + ConstVal::Unevaluated(_, substs) => { + self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_substs(substs); + } + } + } + fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection) { self.add_substs(projection.substs); self.add_ty(projection.ty); diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index a1cd92c760915..543e8f3e2f04d 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -39,6 +39,7 @@ //! These methods return true to indicate that the visitor has found what it is looking for //! and does not need to visit anything else. +use middle::const_val::ConstVal; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use std::fmt; @@ -67,7 +68,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn has_type_flags(&self, flags: TypeFlags) -> bool { self.visit_with(&mut HasTypeFlagsVisitor { flags: flags }) } - fn has_projection_types(&self) -> bool { + fn has_projections(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PROJECTION) } fn references_error(&self) -> bool { @@ -139,6 +140,10 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { r.super_fold_with(self) } + + fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + c.super_fold_with(self) + } } pub trait TypeVisitor<'tcx> : Sized { @@ -153,6 +158,10 @@ pub trait TypeVisitor<'tcx> : Sized { fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { r.super_visit_with(self) } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + c.super_visit_with(self) + } } /////////////////////////////////////////////////////////////////////////// @@ -603,6 +612,17 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); flags.intersects(self.flags) } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + if let ConstVal::Unevaluated(..) = c.val { + let projection_flags = TypeFlags::HAS_NORMALIZABLE_PROJECTION | + TypeFlags::HAS_PROJECTION; + if projection_flags.intersects(self.flags) { + return true; + } + } + c.super_visit_with(self) + } } /// Collects all the late-bound regions it finds into a hash set. diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 900197f3dbd17..a829814e0905b 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -205,7 +205,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { })) }, TyArray(ty, len) => { - if len == 0 { + if len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) { DefIdForest::empty() } else { ty.uninhabited_from(visited, tcx) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 2348c4ae76731..0106d98b64130 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -837,12 +837,22 @@ impl<'a, 'tcx> Struct { // Is this a fixed-size array of something non-zero // with at least one element? - (_, &ty::TyArray(ety, d)) if d > 0 => { - Struct::non_zero_field_paths( - tcx, - param_env, - Some(ety).into_iter(), - None) + (_, &ty::TyArray(ety, mut count)) => { + if count.has_projections() { + count = tcx.normalize_associated_type_in_env(&count, param_env); + if count.has_projections() { + return Err(LayoutError::Unknown(ty)); + } + } + if count.val.to_const_int().unwrap().to_u64().unwrap() != 0 { + Struct::non_zero_field_paths( + tcx, + param_env, + Some(ety).into_iter(), + None) + } else { + Ok(None) + } } (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => { @@ -1174,12 +1184,17 @@ impl<'a, 'tcx> Layout { } // Arrays and slices. - ty::TyArray(element, count) => { + ty::TyArray(element, mut count) => { + if count.has_projections() { + count = tcx.normalize_associated_type_in_env(&count, param_env); + if count.has_projections() { + return Err(LayoutError::Unknown(ty)); + } + } + let element = element.layout(tcx, param_env)?; let element_size = element.size(dl); - // FIXME(eddyb) Don't use host `usize` for array lengths. - let usize_count: usize = count; - let count = usize_count as u64; + let count = count.val.to_const_int().unwrap().to_u64().unwrap(); if element_size.checked_mul(count, dl).is_none() { return Err(LayoutError::SizeOverflow(ty)); } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 48b92d101edb3..83b4fbb4f803a 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -159,7 +159,7 @@ impl Key for (MirSuite, MirPassIndex, DefId) { } } -impl<'tcx, T: Clone + Hash + Eq + Debug> Key for ty::ParamEnvAnd<'tcx, T> { +impl<'tcx> Key for Ty<'tcx> { fn map_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -168,6 +168,15 @@ impl<'tcx, T: Clone + Hash + Eq + Debug> Key for ty::ParamEnvAnd<'tcx, T> { } } +impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { + fn map_crate(&self) -> CrateNum { + self.value.map_crate() + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.value.default_span(tcx) + } +} + trait Value<'tcx>: Sized { fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8b7ae79f151cc..bdd4c003de7ad 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -64,7 +64,7 @@ pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate}; pub use self::sty::{ClosureSubsts, GeneratorInterior, TypeAndMut}; pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef}; pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; -pub use self::sty::{ExistentialProjection, PolyExistentialProjection}; +pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const}; pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::RegionKind; pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid}; @@ -846,6 +846,9 @@ pub enum Predicate<'tcx> { /// `T1 <: T2` Subtype(PolySubtypePredicate<'tcx>), + + /// Constant initializer must evaluate successfully. + ConstEvaluatable(DefId, &'tcx Substs<'tcx>), } impl<'a, 'gcx, 'tcx> Predicate<'tcx> { @@ -938,6 +941,8 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { Predicate::ObjectSafe(trait_def_id), Predicate::ClosureKind(closure_def_id, kind) => Predicate::ClosureKind(closure_def_id, kind), + Predicate::ConstEvaluatable(def_id, const_substs) => + Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)), } } } @@ -1120,6 +1125,9 @@ impl<'tcx> Predicate<'tcx> { ty::Predicate::ClosureKind(_closure_def_id, _kind) => { vec![] } + ty::Predicate::ConstEvaluatable(_, substs) => { + substs.types().collect() + } }; // The only reason to collect into a vector here is that I was @@ -1142,7 +1150,8 @@ impl<'tcx> Predicate<'tcx> { Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | Predicate::ClosureKind(..) | - Predicate::TypeOutlives(..) => { + Predicate::TypeOutlives(..) | + Predicate::ConstEvaluatable(..) => { None } } @@ -1601,7 +1610,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { if let VariantDiscr::Explicit(expr_did) = v.discr { let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did); match tcx.const_eval(param_env.and((expr_did, substs))) { - Ok(ConstVal::Integral(v)) => { + Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => { discr = v; } err => { @@ -1641,7 +1650,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { ty::VariantDiscr::Explicit(expr_did) => { let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did); match tcx.const_eval(param_env.and((expr_did, substs))) { - Ok(ConstVal::Integral(v)) => { + Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => { explicit_value = v; break; } @@ -1665,11 +1674,11 @@ impl<'a, 'gcx, 'tcx> AdtDef { match repr_type { attr::UnsignedInt(ty) => { ConstInt::new_unsigned_truncating(discr, ty, - tcx.sess.target.uint_type) + tcx.sess.target.usize_ty) } attr::SignedInt(ty) => { ConstInt::new_signed_truncating(discr as i128, ty, - tcx.sess.target.int_type) + tcx.sess.target.isize_ty) } } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 0ff3199689c19..309880ba06333 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -14,9 +14,12 @@ //! type equality, etc. use hir::def_id::DefId; +use middle::const_val::ConstVal; +use traits::Reveal; use ty::subst::{Kind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; +use util::common::ErrorReported; use std::rc::Rc; use std::iter; use syntax::abi; @@ -428,10 +431,45 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, (&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) => { let t = relation.relate(&a_t, &b_t)?; - if sz_a == sz_b { - Ok(tcx.mk_array(t, sz_a)) - } else { - Err(TypeError::FixedArraySize(expected_found(relation, &sz_a, &sz_b))) + assert_eq!(sz_a.ty, tcx.types.usize); + assert_eq!(sz_b.ty, tcx.types.usize); + let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result { + match x.val { + ConstVal::Integral(x) => Ok(x.to_u64().unwrap()), + ConstVal::Unevaluated(def_id, substs) => { + // FIXME(eddyb) get the right param_env. + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + match tcx.lift_to_global(&substs) { + Some(substs) => { + match tcx.const_eval(param_env.and((def_id, substs))) { + Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => { + return Ok(x.to_u64().unwrap()); + } + _ => {} + } + } + None => {} + } + tcx.sess.delay_span_bug(tcx.def_span(def_id), + "array length could not be evaluated"); + Err(ErrorReported) + } + _ => bug!("arrays should not have {:?} as length", x) + } + }; + match (to_u64(sz_a), to_u64(sz_b)) { + (Ok(sz_a_u64), Ok(sz_b_u64)) => { + if sz_a_u64 == sz_b_u64 { + Ok(tcx.mk_ty(ty::TyArray(t, sz_a))) + } else { + Err(TypeError::FixedArraySize( + expected_found(relation, &sz_a_u64, &sz_b_u64))) + } + } + // We reported an error or will ICE, so we can return TyError. + (Err(ErrorReported), _) | (_, Err(ErrorReported)) => { + Ok(tcx.types.err) + } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 44b505e19658f..54d55748c8e3a 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -9,6 +9,7 @@ // except according to those terms. use infer::type_variable; +use middle::const_val::{self, ConstVal, ConstAggregate, ConstEvalErr}; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -58,6 +59,13 @@ impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result { } } +impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box { + type Lifted = Box; + fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { + tcx.lift(&**self).map(Box::new) + } +} + impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] { type Lifted = Vec; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { @@ -209,6 +217,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { ty::Predicate::ObjectSafe(trait_def_id) => { Some(ty::Predicate::ObjectSafe(trait_def_id)) } + ty::Predicate::ConstEvaluatable(def_id, substs) => { + tcx.lift(&substs).map(|substs| { + ty::Predicate::ConstEvaluatable(def_id, substs) + }) + } } } } @@ -220,6 +233,32 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder { } } +impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { + type Lifted = ty::ParamEnv<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.caller_bounds).map(|caller_bounds| { + ty::ParamEnv { + reveal: self.reveal, + caller_bounds, + } + }) + } +} + +impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::ParamEnvAnd<'a, T> { + type Lifted = ty::ParamEnvAnd<'tcx, T::Lifted>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.param_env).and_then(|param_env| { + tcx.lift(&self.value).map(|value| { + ty::ParamEnvAnd { + param_env, + value, + } + }) + }) + } +} + impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { type Lifted = ty::ClosureSubsts<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -394,6 +433,64 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> { + type Lifted = ConstEvalErr<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.kind).map(|kind| { + ConstEvalErr { + span: self.span, + kind, + } + }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> { + type Lifted = const_val::ErrKind<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + use middle::const_val::ErrKind::*; + + Some(match *self { + CannotCast => CannotCast, + MissingStructField => MissingStructField, + NonConstPath => NonConstPath, + UnimplementedConstVal(s) => UnimplementedConstVal(s), + ExpectedConstTuple => ExpectedConstTuple, + ExpectedConstStruct => ExpectedConstStruct, + IndexedNonVec => IndexedNonVec, + IndexNotUsize => IndexNotUsize, + IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index }, + MiscBinaryOp => MiscBinaryOp, + MiscCatchAll => MiscCatchAll, + IndexOpFeatureGated => IndexOpFeatureGated, + Math(ref e) => Math(e.clone()), + + LayoutError(ref e) => { + return tcx.lift(e).map(LayoutError) + } + ErroneousReferencedConstant(ref e) => { + return tcx.lift(e).map(ErroneousReferencedConstant) + } + + TypeckError => TypeckError, + }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::layout::LayoutError<'a> { + type Lifted = ty::layout::LayoutError<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + match *self { + ty::layout::LayoutError::Unknown(ref ty) => { + tcx.lift(ty).map(ty::layout::LayoutError::Unknown) + } + ty::layout::LayoutError::SizeOverflow(ref ty) => { + tcx.lift(ty).map(ty::layout::LayoutError::SizeOverflow) + } + } + } +} + /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. // @@ -408,6 +505,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { macro_rules! CopyImpls { ($($ty:ty),+) => { $( + impl<'tcx> Lift<'tcx> for $ty { + type Lifted = Self; + fn lift_to_tcx<'a, 'gcx>(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Option { + Some(*self) + } + } + impl<'tcx> TypeFoldable<'tcx> for $ty { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> $ty { *self @@ -551,7 +655,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let sty = match self.sty { ty::TyRawPtr(tm) => ty::TyRawPtr(tm.fold_with(folder)), - ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz), + ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz.fold_with(folder)), ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)), ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)), ty::TyDynamic(ref trait_ty, ref region) => @@ -589,7 +693,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match self.sty { ty::TyRawPtr(ref tm) => tm.visit_with(visitor), - ty::TyArray(typ, _sz) => typ.visit_with(visitor), + ty::TyArray(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor), ty::TySlice(typ) => typ.visit_with(visitor), ty::TyAdt(_, substs) => substs.visit_with(visitor), ty::TyDynamic(ref trait_ty, ref reg) => @@ -865,6 +969,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { ty::Predicate::ClosureKind(closure_def_id, kind), ty::Predicate::ObjectSafe(trait_def_id) => ty::Predicate::ObjectSafe(trait_def_id), + ty::Predicate::ConstEvaluatable(def_id, substs) => + ty::Predicate::ConstEvaluatable(def_id, substs.fold_with(folder)), } } @@ -879,6 +985,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { ty::Predicate::WellFormed(data) => data.visit_with(visitor), ty::Predicate::ClosureKind(_closure_def_id, _kind) => false, ty::Predicate::ObjectSafe(_trait_def_id) => false, + ty::Predicate::ConstEvaluatable(_def_id, substs) => substs.visit_with(visitor), } } } @@ -1101,3 +1208,107 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> { } } } + +impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + ConstVal::Integral(i) => ConstVal::Integral(i), + ConstVal::Float(f) => ConstVal::Float(f), + ConstVal::Str(s) => ConstVal::Str(s), + ConstVal::ByteStr(b) => ConstVal::ByteStr(b), + ConstVal::Bool(b) => ConstVal::Bool(b), + ConstVal::Char(c) => ConstVal::Char(c), + ConstVal::Variant(def_id) => ConstVal::Variant(def_id), + ConstVal::Function(def_id, substs) => { + ConstVal::Function(def_id, substs.fold_with(folder)) + } + ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { + let new_fields: Vec<_> = fields.iter().map(|&(name, v)| { + (name, v.fold_with(folder)) + }).collect(); + let fields = if new_fields == fields { + fields + } else { + folder.tcx().alloc_name_const_slice(&new_fields) + }; + ConstVal::Aggregate(ConstAggregate::Struct(fields)) + } + ConstVal::Aggregate(ConstAggregate::Tuple(fields)) => { + let new_fields: Vec<_> = fields.iter().map(|v| { + v.fold_with(folder) + }).collect(); + let fields = if new_fields == fields { + fields + } else { + folder.tcx().alloc_const_slice(&new_fields) + }; + ConstVal::Aggregate(ConstAggregate::Tuple(fields)) + } + ConstVal::Aggregate(ConstAggregate::Array(fields)) => { + let new_fields: Vec<_> = fields.iter().map(|v| { + v.fold_with(folder) + }).collect(); + let fields = if new_fields == fields { + fields + } else { + folder.tcx().alloc_const_slice(&new_fields) + }; + ConstVal::Aggregate(ConstAggregate::Array(fields)) + } + ConstVal::Aggregate(ConstAggregate::Repeat(v, count)) => { + let v = v.fold_with(folder); + ConstVal::Aggregate(ConstAggregate::Repeat(v, count)) + } + ConstVal::Unevaluated(def_id, substs) => { + ConstVal::Unevaluated(def_id, substs.fold_with(folder)) + } + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + ConstVal::Integral(_) | + ConstVal::Float(_) | + ConstVal::Str(_) | + ConstVal::ByteStr(_) | + ConstVal::Bool(_) | + ConstVal::Char(_) | + ConstVal::Variant(_) => false, + ConstVal::Function(_, substs) => substs.visit_with(visitor), + ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { + fields.iter().any(|&(_, v)| v.visit_with(visitor)) + } + ConstVal::Aggregate(ConstAggregate::Tuple(fields)) | + ConstVal::Aggregate(ConstAggregate::Array(fields)) => { + fields.iter().any(|v| v.visit_with(visitor)) + } + ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { + v.visit_with(visitor) + } + ConstVal::Unevaluated(_, substs) => substs.visit_with(visitor), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + let ty = self.ty.fold_with(folder); + let val = self.val.fold_with(folder); + folder.tcx().mk_const(ty::Const { + ty, + val + }) + } + + fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + folder.fold_const(*self) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.ty.visit_with(visitor) || self.val.visit_with(visitor) + } + + fn visit_with>(&self, visitor: &mut V) -> bool { + visitor.visit_const(self) + } +} diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 14ea66a1b67fa..f17f81ca06bea 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -12,6 +12,7 @@ use hir::def_id::DefId; +use middle::const_val::ConstVal; use middle::region; use ty::subst::{Substs, Subst}; use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; @@ -109,7 +110,7 @@ pub enum TypeVariants<'tcx> { TyStr, /// An array with the given length. Written as `[T; n]`. - TyArray(Ty<'tcx>, usize), + TyArray(Ty<'tcx>, &'tcx ty::Const<'tcx>), /// The pointee of an array slice. Written as `[T]`. TySlice(Ty<'tcx>), @@ -1458,3 +1459,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } } + +/// Typed constant value. +#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] +pub struct Const<'tcx> { + pub ty: Ty<'tcx>, + + // FIXME(eddyb) Replace this with a miri value. + pub val: ConstVal<'tcx>, +} + +impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index f21fc8414e78b..16ae3cdbf1796 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -13,6 +13,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; use ich::{StableHashingContext, NodeIdHashingMode}; +use middle::const_val::ConstVal; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeVisitor; @@ -53,7 +54,7 @@ macro_rules! typed_literal { SignedInt(ast::IntTy::I32) => ConstInt::I32($lit), SignedInt(ast::IntTy::I64) => ConstInt::I64($lit), SignedInt(ast::IntTy::I128) => ConstInt::I128($lit), - SignedInt(ast::IntTy::Is) => match $tcx.sess.target.int_type { + SignedInt(ast::IntTy::Is) => match $tcx.sess.target.isize_ty { ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)), ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)), ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)), @@ -64,7 +65,7 @@ macro_rules! typed_literal { UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit), UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit), UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit), - UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.uint_type { + UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.usize_ty { ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)), ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)), ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)), @@ -388,7 +389,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::RegionOutlives(..) => { + ty::Predicate::RegionOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => { None } ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { @@ -638,7 +640,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn const_usize(&self, val: u16) -> ConstInt { - match self.sess.target.uint_type { + match self.sess.target.usize_ty { ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(val as u16)), ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(val as u32)), ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(val as u64)), @@ -697,7 +699,14 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> TyInt(i) => self.hash(i), TyUint(u) => self.hash(u), TyFloat(f) => self.hash(f), - TyArray(_, n) => self.hash(n), + TyArray(_, n) => { + self.hash_discriminant_u8(&n.val); + match n.val { + ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()), + ConstVal::Unevaluated(def_id, _) => self.def_id(def_id), + _ => bug!("arrays should not have {:?} as length", n) + } + } TyRawPtr(m) | TyRef(_, m) => self.hash(m.mutbl), TyClosure(def_id, _) | diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index bfabacdb17214..df07844ccebaf 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -11,6 +11,7 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. +use middle::const_val::{ConstVal, ConstAggregate}; use ty::{self, Ty}; use rustc_data_structures::small_vec::SmallVec; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; @@ -83,7 +84,11 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => { } - ty::TyArray(ty, _) | ty::TySlice(ty) => { + ty::TyArray(ty, len) => { + push_const(stack, len); + stack.push(ty); + } + ty::TySlice(ty) => { stack.push(ty); } ty::TyRawPtr(ref mt) | ty::TyRef(_, ref mt) => { @@ -122,13 +127,42 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { ty::TyFnDef(_, substs) => { stack.extend(substs.types().rev()); } - ty::TyFnPtr(ft) => { - push_sig_subtypes(stack, ft); + ty::TyFnPtr(sig) => { + stack.push(sig.skip_binder().output()); + stack.extend(sig.skip_binder().inputs().iter().cloned().rev()); } } } -fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: ty::PolyFnSig<'tcx>) { - stack.push(sig.skip_binder().output()); - stack.extend(sig.skip_binder().inputs().iter().cloned().rev()); +fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) { + match constant.val { + ConstVal::Integral(_) | + ConstVal::Float(_) | + ConstVal::Str(_) | + ConstVal::ByteStr(_) | + ConstVal::Bool(_) | + ConstVal::Char(_) | + ConstVal::Variant(_) => {} + ConstVal::Function(_, substs) => { + stack.extend(substs.types().rev()); + } + ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { + for &(_, v) in fields.iter().rev() { + push_const(stack, v); + } + } + ConstVal::Aggregate(ConstAggregate::Tuple(fields)) | + ConstVal::Aggregate(ConstAggregate::Array(fields)) => { + for v in fields.iter().rev() { + push_const(stack, v); + } + } + ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { + push_const(stack, v); + } + ConstVal::Unevaluated(_, substs) => { + stack.extend(substs.types().rev()); + } + } + stack.push(constant.ty); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 3516f7dfb25b0..41e27fca3f320 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -9,6 +9,7 @@ // except according to those terms. use hir::def_id::DefId; +use middle::const_val::{ConstVal, ConstAggregate}; use infer::InferCtxt; use ty::subst::Substs; use traits; @@ -101,6 +102,14 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, wf.compute(data.skip_binder().a); // (*) wf.compute(data.skip_binder().b); // (*) } + ty::Predicate::ConstEvaluatable(def_id, substs) => { + let obligations = wf.nominal_obligations(def_id, substs); + wf.out.extend(obligations); + + for ty in substs.types() { + wf.compute(ty); + } + } } wf.normalize() @@ -207,6 +216,46 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } + /// Pushes the obligations required for a constant value to be WF + /// into `self.out`. + fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) { + self.require_sized(constant.ty, traits::ConstSized); + match constant.val { + ConstVal::Integral(_) | + ConstVal::Float(_) | + ConstVal::Str(_) | + ConstVal::ByteStr(_) | + ConstVal::Bool(_) | + ConstVal::Char(_) | + ConstVal::Variant(_) | + ConstVal::Function(..) => {} + ConstVal::Aggregate(ConstAggregate::Struct(fields)) => { + for &(_, v) in fields { + self.compute_const(v); + } + } + ConstVal::Aggregate(ConstAggregate::Tuple(fields)) | + ConstVal::Aggregate(ConstAggregate::Array(fields)) => { + for v in fields { + self.compute_const(v); + } + } + ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => { + self.compute_const(v); + } + ConstVal::Unevaluated(def_id, substs) => { + let obligations = self.nominal_obligations(def_id, substs); + self.out.extend(obligations); + + let predicate = ty::Predicate::ConstEvaluatable(def_id, substs); + let cause = self.cause(traits::MiscObligation); + self.out.push(traits::Obligation::new(cause, + self.param_env, + predicate)); + } + } + } + fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { if !subty.has_escaping_regions() { let cause = self.cause(cause); @@ -239,9 +288,14 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // WfScalar, WfParameter, etc } - ty::TySlice(subty) | - ty::TyArray(subty, _) => { + ty::TySlice(subty) => { + self.require_sized(subty, traits::SliceOrArrayElem); + } + + ty::TyArray(subty, len) => { self.require_sized(subty, traits::SliceOrArrayElem); + assert_eq!(len.ty, self.infcx.tcx.types.usize); + self.compute_const(len); } ty::TyTuple(ref tys, _) => { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 9cc978a057bf6..cf7a29d2845ac 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -10,6 +10,7 @@ use hir::def_id::DefId; use hir::map::definitions::DefPathData; +use middle::const_val::ConstVal; use middle::region::{self, BlockRemainder}; use ty::subst::{self, Subst}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; @@ -24,6 +25,7 @@ use std::cell::Cell; use std::fmt; use std::usize; +use rustc_const_math::ConstInt; use syntax::abi::Abi; use syntax::ast::CRATE_NODE_ID; use syntax::symbol::Symbol; @@ -428,6 +430,9 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { ty::Predicate::ClosureKind(closure_def_id, kind) => { write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind) } + ty::Predicate::ConstEvaluatable(def_id, substs) => { + write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) + } } } } @@ -886,7 +891,21 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { write!(f, "]") }), - TyArray(ty, sz) => write!(f, "[{}; {}]", ty, sz), + TyArray(ty, sz) => { + write!(f, "[{}; ", ty)?; + match sz.val { + ConstVal::Integral(ConstInt::Usize(sz)) => { + write!(f, "{}", sz)?; + } + ConstVal::Unevaluated(_def_id, substs) => { + write!(f, "", &substs[..])?; + } + _ => { + write!(f, "{:?}", sz)?; + } + } + write!(f, "]") + } TySlice(ty) => write!(f, "[{}]", ty) } } @@ -1035,6 +1054,11 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { write!(f, "the closure `{}` implements the trait `{}`", tcx.item_path_str(closure_def_id), kind) }), + ty::Predicate::ConstEvaluatable(def_id, substs) => { + write!(f, "the constant `")?; + parameterized(f, substs, def_id, &[])?; + write!(f, "` can be evaluated") + } } } } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index bc9aa9665c103..b836b71e74bf6 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -182,13 +182,16 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { self.byte_array_map.entry(pat).or_insert_with(|| { match pat.kind { box PatternKind::Constant { - value: ConstVal::ByteStr(ref data) + value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => { - data.iter().map(|c| &*pattern_arena.alloc(Pattern { + b.data.iter().map(|&b| &*pattern_arena.alloc(Pattern { ty: tcx.types.u8, span: pat.span, kind: box PatternKind::Constant { - value: ConstVal::Integral(ConstInt::U8(*c)) + value: tcx.mk_const(ty::Const { + val: ConstVal::Integral(ConstInt::U8(b)), + ty: tcx.types.u8 + }) } })).collect() } @@ -228,11 +231,11 @@ pub enum Constructor<'tcx> { /// Enum variants. Variant(DefId), /// Literal values. - ConstantValue(ConstVal<'tcx>), + ConstantValue(&'tcx ty::Const<'tcx>), /// Ranges of literal values (`2...5` and `2..5`). - ConstantRange(ConstVal<'tcx>, ConstVal<'tcx>, RangeEnd), + ConstantRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd), /// Array patterns of length n. - Slice(usize), + Slice(u64), } impl<'tcx> Constructor<'tcx> { @@ -273,7 +276,7 @@ pub enum WitnessPreference { #[derive(Copy, Clone, Debug)] struct PatternContext<'tcx> { ty: Ty<'tcx>, - max_slice_length: usize, + max_slice_length: u64, } /// A stack of patterns in reverse order of construction @@ -327,8 +330,8 @@ impl<'tcx> Witness<'tcx> { { let arity = constructor_arity(cx, ctor, ty); let pat = { - let len = self.0.len(); - let mut pats = self.0.drain(len-arity..).rev(); + let len = self.0.len() as u64; + let mut pats = self.0.drain((len-arity) as usize..).rev(); match ty.sty { ty::TyAdt(..) | @@ -370,7 +373,7 @@ impl<'tcx> Witness<'tcx> { _ => { match *ctor { - ConstantValue(ref v) => PatternKind::Constant { value: v.clone() }, + ConstantValue(value) => PatternKind::Constant { value }, _ => PatternKind::Wild, } } @@ -404,8 +407,24 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, { debug!("all_constructors({:?})", pcx.ty); match pcx.ty.sty { - ty::TyBool => - [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(), + ty::TyBool => { + [true, false].iter().map(|&b| { + ConstantValue(cx.tcx.mk_const(ty::Const { + val: ConstVal::Bool(b), + ty: cx.tcx.types.bool + })) + }).collect() + } + ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => { + let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + if len != 0 && cx.is_uninhabited(sub_ty) { + vec![] + } else { + vec![Slice(len)] + } + } + // Treat arrays of a constant but unknown length like slices. + ty::TyArray(ref sub_ty, _) | ty::TySlice(ref sub_ty) => { if cx.is_uninhabited(sub_ty) { vec![Slice(0)] @@ -413,13 +432,6 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect() } } - ty::TyArray(ref sub_ty, length) => { - if length > 0 && cx.is_uninhabited(sub_ty) { - vec![] - } else { - vec![Slice(length)] - } - } ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => { def.variants.iter() .filter(|v| !cx.is_variant_uninhabited(v, substs)) @@ -438,7 +450,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( _cx: &mut MatchCheckCtxt<'a, 'tcx>, - patterns: I) -> usize + patterns: I) -> u64 where I: Iterator> { // The exhaustiveness-checking paper does not include any details on @@ -511,16 +523,16 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>( for row in patterns { match *row.kind { - PatternKind::Constant { value: ConstVal::ByteStr(ref data) } => { - max_fixed_len = cmp::max(max_fixed_len, data.len()); + PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => { + max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64); } PatternKind::Slice { ref prefix, slice: None, ref suffix } => { - let fixed_len = prefix.len() + suffix.len(); + let fixed_len = prefix.len() as u64 + suffix.len() as u64; max_fixed_len = cmp::max(max_fixed_len, fixed_len); } PatternKind::Slice { ref prefix, slice: Some(_), ref suffix } => { - max_prefix_len = cmp::max(max_prefix_len, prefix.len()); - max_suffix_len = cmp::max(max_suffix_len, suffix.len()); + max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64); + max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64); } _ => {} } @@ -715,16 +727,18 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, Some(vec![Single]), PatternKind::Variant { adt_def, variant_index, .. } => Some(vec![Variant(adt_def.variants[variant_index].did)]), - PatternKind::Constant { ref value } => - Some(vec![ConstantValue(value.clone())]), - PatternKind::Range { ref lo, ref hi, ref end } => - Some(vec![ConstantRange(lo.clone(), hi.clone(), end.clone())]), + PatternKind::Constant { value } => + Some(vec![ConstantValue(value)]), + PatternKind::Range { lo, hi, end } => + Some(vec![ConstantRange(lo, hi, end)]), PatternKind::Array { .. } => match pcx.ty.sty { - ty::TyArray(_, length) => Some(vec![Slice(length)]), + ty::TyArray(_, length) => Some(vec![ + Slice(length.val.to_const_int().unwrap().to_u64().unwrap()) + ]), _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) }, PatternKind::Slice { ref prefix, ref slice, ref suffix } => { - let pat_len = prefix.len() + suffix.len(); + let pat_len = prefix.len() as u64 + suffix.len() as u64; if slice.is_some() { Some((pat_len..pcx.max_slice_length+1).map(Slice).collect()) } else { @@ -739,10 +753,10 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt, /// /// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. /// A struct pattern's arity is the number of fields it contains, etc. -fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize { +fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 { debug!("constructor_arity({:?}, {:?})", ctor, ty); match ty.sty { - ty::TyTuple(ref fs, _) => fs.len(), + ty::TyTuple(ref fs, _) => fs.len() as u64, ty::TySlice(..) | ty::TyArray(..) => match *ctor { Slice(length) => length, ConstantValue(_) => 0, @@ -750,7 +764,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize }, ty::TyRef(..) => 1, ty::TyAdt(adt, _) => { - adt.variants[ctor.variant_index_for_adt(adt)].fields.len() + adt.variants[ctor.variant_index_for_adt(adt)].fields.len() as u64 } _ => 0 } @@ -768,7 +782,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, match ty.sty { ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(), ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor { - Slice(length) => repeat(ty).take(length).collect(), + Slice(length) => (0..length).map(|_| ty).collect(), ConstantValue(_) => vec![], _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) }, @@ -806,7 +820,7 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, suffix: &[Pattern]) -> Result { let data = match *ctor { - ConstantValue(ConstVal::ByteStr(ref data)) => data, + ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data, _ => bug!() }; @@ -820,7 +834,7 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, data[data.len()-suffix.len()..].iter().zip(suffix)) { match pat.kind { - box PatternKind::Constant { ref value } => match *value { + box PatternKind::Constant { value } => match value.val { ConstVal::Integral(ConstInt::U8(u)) => { if u != *ch { return Ok(false); @@ -843,23 +857,23 @@ fn constructor_covered_by_range(tcx: TyCtxt, span: Span, let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less); let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to); match *ctor { - ConstantValue(ref value) => { - let to = cmp_to(value)?; + ConstantValue(value) => { + let to = cmp_to(&value.val)?; let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(cmp_from(value)? && end) + Ok(cmp_from(&value.val)? && end) }, - ConstantRange(ref from, ref to, RangeEnd::Included) => { - let to = cmp_to(to)?; + ConstantRange(from, to, RangeEnd::Included) => { + let to = cmp_to(&to.val)?; let end = (to == Ordering::Less) || (end == RangeEnd::Included && to == Ordering::Equal); - Ok(cmp_from(from)? && end) + Ok(cmp_from(&from.val)? && end) }, - ConstantRange(ref from, ref to, RangeEnd::Excluded) => { - let to = cmp_to(to)?; + ConstantRange(from, to, RangeEnd::Excluded) => { + let to = cmp_to(&to.val)?; let end = (to == Ordering::Less) || (end == RangeEnd::Excluded && to == Ordering::Equal); - Ok(cmp_from(from)? && end) + Ok(cmp_from(&from.val)? && end) } Single => Ok(true), _ => bug!(), @@ -919,11 +933,11 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( Some(vec![subpattern]) } - PatternKind::Constant { ref value } => { + PatternKind::Constant { value } => { match *constructor { - Slice(..) => match *value { - ConstVal::ByteStr(ref data) => { - if wild_patterns.len() == data.len() { + Slice(..) => match value.val { + ConstVal::ByteStr(b) => { + if wild_patterns.len() == b.data.len() { Some(cx.lower_byte_str_pattern(pat)) } else { None @@ -934,7 +948,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( }, _ => { match constructor_covered_by_range( - cx.tcx, pat.span, constructor, value, value, RangeEnd::Included + cx.tcx, pat.span, constructor, &value.val, &value.val, RangeEnd::Included ) { Ok(true) => Some(vec![]), Ok(false) => None, @@ -944,9 +958,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( } } - PatternKind::Range { ref lo, ref hi, ref end } => { + PatternKind::Range { lo, hi, ref end } => { match constructor_covered_by_range( - cx.tcx, pat.span, constructor, lo, hi, end.clone() + cx.tcx, pat.span, constructor, &lo.val, &hi.val, end.clone() ) { Ok(true) => Some(vec![]), Ok(false) => None, diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index d832ad0ab1d20..0339969f2b45a 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -140,7 +140,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { fn check_match( &self, scrut: &hir::Expr, - arms: &[hir::Arm], + arms: &'tcx [hir::Arm], source: hir::MatchSource) { for arm in arms { @@ -231,7 +231,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { } } - fn check_irrefutable(&self, pat: &Pat, origin: &str) { + fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) { let module = self.tcx.hir.get_module_parent(pat.id); MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| { let mut patcx = PatternContext::new(self.tcx, diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index 56d08184a0f17..d01b3c45f7fd1 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -565,7 +565,7 @@ See also https://github.com/rust-lang/rust/issues/14587 register_diagnostics! { - E0298, // cannot compare constants +// E0298, // cannot compare constants // E0299, // mismatched types between arms // E0471, // constant evaluation error (in pattern) } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index c71c121ca50c3..61eb5dfd18b9c 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -9,8 +9,9 @@ // except according to those terms. use rustc::middle::const_val::ConstVal::*; +use rustc::middle::const_val::ConstAggregate::*; use rustc::middle::const_val::ErrKind::*; -use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind}; +use rustc::middle::const_val::{ByteArray, ConstVal, ConstEvalErr, EvalResult, ErrKind}; use rustc::hir::map as hir_map; use rustc::hir::map::blocks::FnLikeNode; @@ -88,7 +89,7 @@ pub struct ConstContext<'a, 'tcx: 'a> { tables: &'a ty::TypeckTables<'tcx>, param_env: ty::ParamEnv<'tcx>, substs: &'tcx Substs<'tcx>, - fn_args: Option>> + fn_args: Option>> } impl<'a, 'tcx> ConstContext<'a, 'tcx> { @@ -107,7 +108,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { /// Evaluate a constant expression in a context where the expression isn't /// guaranteed to be evaluable. - pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> { + pub fn eval(&self, e: &'tcx Expr) -> EvalResult<'tcx> { if self.tables.tainted_by_errors { signal!(e, TypeckError); } @@ -118,9 +119,10 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { type CastResult<'tcx> = Result, ErrKind<'tcx>>; fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, - e: &Expr) -> EvalResult<'tcx> { + e: &'tcx Expr) -> EvalResult<'tcx> { let tcx = cx.tcx; - let ety = cx.tables.expr_ty(e).subst(tcx, cx.substs); + let ty = cx.tables.expr_ty(e).subst(tcx, cx.substs); + let mk_const = |val| tcx.mk_const(ty::Const { val, ty }); let result = match e.node { hir::ExprUnary(hir::UnNeg, ref inner) => { @@ -133,57 +135,66 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128; const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128; const I128_OVERFLOW: u128 = i128::min_value() as u128; - match (&lit.node, &ety.sty) { + let negated = match (&lit.node, &ty.sty) { (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) | (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => { - return Ok(Integral(I8(i8::min_value()))) + Some(I8(i8::min_value())) }, (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) | (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => { - return Ok(Integral(I16(i16::min_value()))) + Some(I16(i16::min_value())) }, (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) | (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => { - return Ok(Integral(I32(i32::min_value()))) + Some(I32(i32::min_value())) }, (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) | (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => { - return Ok(Integral(I64(i64::min_value()))) + Some(I64(i64::min_value())) }, (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) | (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => { - return Ok(Integral(I128(i128::min_value()))) + Some(I128(i128::min_value())) }, (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) | (&LitKind::Int(n, Signed(IntTy::Is)), _) => { - match tcx.sess.target.int_type { + match tcx.sess.target.isize_ty { IntTy::I16 => if n == I16_OVERFLOW { - return Ok(Integral(Isize(Is16(i16::min_value())))); + Some(Isize(Is16(i16::min_value()))) + } else { + None }, IntTy::I32 => if n == I32_OVERFLOW { - return Ok(Integral(Isize(Is32(i32::min_value())))); + Some(Isize(Is32(i32::min_value()))) + } else { + None }, IntTy::I64 => if n == I64_OVERFLOW { - return Ok(Integral(Isize(Is64(i64::min_value())))); + Some(Isize(Is64(i64::min_value()))) + } else { + None }, _ => span_bug!(e.span, "typeck error") } }, - _ => {}, + _ => None + }; + if let Some(i) = negated { + return Ok(mk_const(Integral(i))); } } - match cx.eval(inner)? { + mk_const(match cx.eval(inner)?.val { Float(f) => Float(-f), Integral(i) => Integral(math!(e, -i)), - const_val => signal!(e, NegateOn(const_val)), - } + _ => signal!(e, TypeckError) + }) } hir::ExprUnary(hir::UnNot, ref inner) => { - match cx.eval(inner)? { + mk_const(match cx.eval(inner)?.val { Integral(i) => Integral(math!(e, !i)), Bool(b) => Bool(!b), - const_val => signal!(e, NotOn(const_val)), - } + _ => signal!(e, TypeckError) + }) } hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")), hir::ExprBinary(op, ref a, ref b) => { @@ -191,7 +202,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, // gives us a type through a type-suffix, cast or const def type // we need to re-eval the other value of the BinOp if it was // not inferred - match (cx.eval(a)?, cx.eval(b)?) { + mk_const(match (cx.eval(a)?.val, cx.eval(b)?.val) { (Float(a), Float(b)) => { use std::cmp::Ordering::*; match op.node { @@ -260,16 +271,16 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } _ => signal!(e, MiscBinaryOp), - } + }) } hir::ExprCast(ref base, _) => { let base_val = cx.eval(base)?; let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs); - if ety == base_ty { + if ty == base_ty { base_val } else { - match cast_const(tcx, base_val, ety) { - Ok(val) => val, + match cast_const(tcx, base_val.val, ty) { + Ok(val) => mk_const(val), Err(kind) => signal!(e, kind), } } @@ -291,52 +302,53 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } }, Def::VariantCtor(variant_def, CtorKind::Const) => { - Variant(variant_def) + mk_const(Variant(variant_def)) } Def::VariantCtor(_, CtorKind::Fn) => { signal!(e, UnimplementedConstVal("enum variants")); } Def::StructCtor(_, CtorKind::Const) => { - ConstVal::Struct(Default::default()) + mk_const(Aggregate(Struct(&[]))) } Def::StructCtor(_, CtorKind::Fn) => { signal!(e, UnimplementedConstVal("tuple struct constructors")) } Def::Local(id) => { debug!("Def::Local({:?}): {:?}", id, cx.fn_args); - if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&id)) { - val.clone() + if let Some(&val) = cx.fn_args.as_ref().and_then(|args| args.get(&id)) { + val } else { signal!(e, NonConstPath); } }, - Def::Method(id) | Def::Fn(id) => Function(id, substs), + Def::Method(id) | Def::Fn(id) => mk_const(Function(id, substs)), Def::Err => span_bug!(e.span, "typeck error"), _ => signal!(e, NonConstPath), } } hir::ExprCall(ref callee, ref args) => { - let (def_id, substs) = match cx.eval(callee)? { + let (def_id, substs) = match cx.eval(callee)?.val { Function(def_id, substs) => (def_id, substs), _ => signal!(e, TypeckError), }; if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic { let layout_of = |ty: Ty<'tcx>| { - ty.layout(tcx, cx.param_env).map_err(|err| { + let ty = tcx.erase_regions(&ty); + tcx.at(e.span).layout_raw(cx.param_env.reveal_all().and(ty)).map_err(|err| { ConstEvalErr { span: e.span, kind: LayoutError(err) } }) }; match &tcx.item_name(def_id)[..] { "size_of" => { - let size = layout_of(substs.type_at(0))?.size(tcx); - return Ok(Integral(Usize(ConstUsize::new(size.bytes(), - tcx.sess.target.uint_type).unwrap()))); + let size = layout_of(substs.type_at(0))?.size(tcx).bytes(); + return Ok(mk_const(Integral(Usize(ConstUsize::new(size, + tcx.sess.target.usize_ty).unwrap())))); } "min_align_of" => { - let align = layout_of(substs.type_at(0))?.align(tcx); - return Ok(Integral(Usize(ConstUsize::new(align.abi(), - tcx.sess.target.uint_type).unwrap()))); + let align = layout_of(substs.type_at(0))?.align(tcx).abi(); + return Ok(mk_const(Integral(Usize(ConstUsize::new(align, + tcx.sess.target.usize_ty).unwrap())))); } _ => signal!(e, TypeckError) } @@ -384,84 +396,83 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, }; callee_cx.eval(&body.value)? }, - hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) { - Ok(val) => val, + hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) { + Ok(val) => mk_const(val), Err(err) => signal!(e, err), }, hir::ExprBlock(ref block) => { match block.expr { Some(ref expr) => cx.eval(expr)?, - None => Tuple(vec![]), + None => mk_const(Aggregate(Tuple(&[]))), } } hir::ExprType(ref e, _) => cx.eval(e)?, hir::ExprTup(ref fields) => { - Tuple(fields.iter().map(|e| cx.eval(e)).collect::>()?) + let values = fields.iter().map(|e| cx.eval(e)).collect::, _>>()?; + mk_const(Aggregate(Tuple(tcx.alloc_const_slice(&values)))) } hir::ExprStruct(_, ref fields, _) => { - Struct(fields.iter().map(|f| { + mk_const(Aggregate(Struct(tcx.alloc_name_const_slice(&fields.iter().map(|f| { cx.eval(&f.expr).map(|v| (f.name.node, v)) - }).collect::>()?) + }).collect::, _>>()?)))) } hir::ExprIndex(ref arr, ref idx) => { if !tcx.sess.features.borrow().const_indexing { signal!(e, IndexOpFeatureGated); } let arr = cx.eval(arr)?; - let idx = match cx.eval(idx)? { - Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type), + let idx = match cx.eval(idx)?.val { + Integral(Usize(i)) => i.as_u64(), _ => signal!(idx, IndexNotUsize), }; assert_eq!(idx as usize as u64, idx); - match arr { - Array(ref v) => { - if let Some(elem) = v.get(idx as usize) { - elem.clone() + match arr.val { + Aggregate(Array(v)) => { + if let Some(&elem) = v.get(idx as usize) { + elem } else { let n = v.len() as u64; - assert_eq!(n as usize as u64, n); signal!(e, IndexOutOfBounds { len: n, index: idx }) } } - Repeat(.., n) if idx >= n => { + Aggregate(Repeat(.., n)) if idx >= n => { signal!(e, IndexOutOfBounds { len: n, index: idx }) } - Repeat(ref elem, _) => (**elem).clone(), + Aggregate(Repeat(elem, _)) => elem, - ByteStr(ref data) if idx >= data.len() as u64 => { - signal!(e, IndexOutOfBounds { len: data.len() as u64, index: idx }) + ByteStr(b) if idx >= b.data.len() as u64 => { + signal!(e, IndexOutOfBounds { len: b.data.len() as u64, index: idx }) } - ByteStr(data) => { - Integral(U8(data[idx as usize])) + ByteStr(b) => { + mk_const(Integral(U8(b.data[idx as usize]))) }, _ => signal!(e, IndexedNonVec), } } hir::ExprArray(ref v) => { - Array(v.iter().map(|e| cx.eval(e)).collect::>()?) + let values = v.iter().map(|e| cx.eval(e)).collect::, _>>()?; + mk_const(Aggregate(Array(tcx.alloc_const_slice(&values)))) } hir::ExprRepeat(ref elem, _) => { - let n = match ety.sty { - ty::TyArray(_, n) => n as u64, + let n = match ty.sty { + ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(), _ => span_bug!(e.span, "typeck error") }; - Repeat(Box::new(cx.eval(elem)?), n) + mk_const(Aggregate(Repeat(cx.eval(elem)?, n))) }, hir::ExprTupField(ref base, index) => { - let c = cx.eval(base)?; - if let Tuple(ref fields) = c { - fields[index.node].clone() + if let Aggregate(Tuple(fields)) = cx.eval(base)?.val { + fields[index.node] } else { signal!(base, ExpectedConstTuple); } } hir::ExprField(ref base, field_name) => { - let c = cx.eval(base)?; - if let Struct(ref fields) = c { - if let Some(f) = fields.get(&field_name.node) { - f.clone() + if let Aggregate(Struct(fields)) = cx.eval(base)?.val { + if let Some(&(_, f)) = fields.iter().find(|&&(name, _)| name == field_name.node) { + f } else { signal!(e, MissingStructField); } @@ -551,7 +562,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))), ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))), ty::TyInt(ast::IntTy::Is) => { - Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.int_type)))) + Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.isize_ty)))) }, ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))), ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))), @@ -559,7 +570,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))), ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))), ty::TyUint(ast::UintTy::Us) => { - Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type)))) + Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.usize_ty)))) }, ty::TyFloat(fty) => { if let Some(i) = val.to_u128() { @@ -625,7 +636,14 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr")) }, ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { - ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)), + ty::TyArray(ty, n) => { + let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + if ty == tcx.types.u8 && n == b.data.len() as u64 { + Ok(val) + } else { + Err(CannotCast) + } + } ty::TySlice(_) => { Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice")) }, @@ -645,7 +663,7 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind, +fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, tcx: TyCtxt<'a, 'tcx, 'tcx>, mut ty: Ty<'tcx>) -> Result, ErrKind<'tcx>> { @@ -660,19 +678,19 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind, match *lit { LitKind::Str(ref s, _) => Ok(Str(s.as_str())), - LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())), + LitKind::ByteStr(ref data) => Ok(ByteStr(ByteArray { data })), LitKind::Byte(n) => Ok(Integral(U8(n))), LitKind::Int(n, hint) => { match (&ty.sty, hint) { (&ty::TyInt(ity), _) | (_, Signed(ity)) => { Ok(Integral(ConstInt::new_signed_truncating(n as i128, - ity, tcx.sess.target.int_type))) + ity, tcx.sess.target.isize_ty))) } (&ty::TyUint(uty), _) | (_, Unsigned(uty)) => { Ok(Integral(ConstInt::new_unsigned_truncating(n as u128, - uty, tcx.sess.target.uint_type))) + uty, tcx.sess.target.usize_ty))) } _ => bug!() } @@ -708,8 +726,8 @@ pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal) (&Float(a), &Float(b)) => a.try_cmp(b).ok(), (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)), (&Bool(a), &Bool(b)) => Some(a.cmp(&b)), - (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)), - (&Char(a), &Char(ref b)) => Some(a.cmp(b)), + (&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)), + (&Char(a), &Char(b)) => Some(a.cmp(&b)), _ => None, }; @@ -717,10 +735,8 @@ pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal) Some(result) => Ok(result), None => { // FIXME: can this ever be reached? - span_err!(tcx.sess, span, E0298, - "type mismatch comparing {} and {}", - a.description(), - b.description()); + tcx.sess.delay_span_bug(span, + &format!("type mismatch comparing {:?} and {:?}", a, b)); Err(ErrorReported) } } @@ -729,8 +745,8 @@ pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal) impl<'a, 'tcx> ConstContext<'a, 'tcx> { pub fn compare_lit_exprs(&self, span: Span, - a: &Expr, - b: &Expr) -> Result { + a: &'tcx Expr, + b: &'tcx Expr) -> Result { let tcx = self.tcx; let a = match self.eval(a) { Ok(a) => a, @@ -746,7 +762,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { return Err(ErrorReported); } }; - compare_const_vals(tcx, span, &a, &b) + compare_const_vals(tcx, span, &a.val, &b.val) } } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index 692778f94e758..a87fa0c2746a3 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -83,12 +83,12 @@ pub enum PatternKind<'tcx> { }, Constant { - value: ConstVal<'tcx>, + value: &'tcx ty::Const<'tcx>, }, Range { - lo: ConstVal<'tcx>, - hi: ConstVal<'tcx>, + lo: &'tcx ty::Const<'tcx>, + hi: &'tcx ty::Const<'tcx>, end: RangeEnd, }, @@ -112,15 +112,13 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { ConstVal::Float(ref x) => write!(f, "{}", x), ConstVal::Integral(ref i) => write!(f, "{}", i), ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]), - ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]), + ConstVal::ByteStr(b) => write!(f, "{:?}", b.data), ConstVal::Bool(b) => write!(f, "{:?}", b), ConstVal::Char(c) => write!(f, "{:?}", c), ConstVal::Variant(_) | - ConstVal::Struct(_) | - ConstVal::Tuple(_) | ConstVal::Function(..) | - ConstVal::Array(..) | - ConstVal::Repeat(..) => bug!("{:?} not printable in a pattern", value) + ConstVal::Aggregate(_) | + ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value) } } @@ -230,16 +228,16 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { } write!(f, "{}", subpattern) } - PatternKind::Constant { ref value } => { - print_const_val(value, f) + PatternKind::Constant { value } => { + print_const_val(&value.val, f) } - PatternKind::Range { ref lo, ref hi, ref end } => { - print_const_val(lo, f)?; - match *end { + PatternKind::Range { lo, hi, end } => { + print_const_val(&lo.val, f)?; + match end { RangeEnd::Included => write!(f, "...")?, RangeEnd::Excluded => write!(f, "..")?, } - print_const_val(hi, f) + print_const_val(&hi.val, f) } PatternKind::Slice { ref prefix, ref slice, ref suffix } | PatternKind::Array { ref prefix, ref slice, ref suffix } => { @@ -278,7 +276,7 @@ impl<'a, 'tcx> Pattern<'tcx> { pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>, tables: &'a ty::TypeckTables<'tcx>, - pat: &hir::Pat) -> Self { + pat: &'tcx hir::Pat) -> Self { let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables); let result = pcx.lower_pattern(pat); if !pcx.errors.is_empty() { @@ -302,7 +300,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } - pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> { + pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> { let mut ty = self.tables.node_id_to_type(pat.hir_id); let kind = match pat.node { @@ -310,11 +308,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatKind::Lit(ref value) => self.lower_lit(value), - PatKind::Range(ref lo, ref hi, ref end) => { + PatKind::Range(ref lo, ref hi, end) => { match (self.lower_lit(lo), self.lower_lit(hi)) { (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { - PatternKind::Range { lo: lo, hi: hi, end: end.clone() } + PatternKind::Range { lo, hi, end } } _ => PatternKind::Wild } @@ -474,11 +472,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } - fn lower_patterns(&mut self, pats: &[P]) -> Vec> { + fn lower_patterns(&mut self, pats: &'tcx [P]) -> Vec> { pats.iter().map(|p| self.lower_pattern(p)).collect() } - fn lower_opt_pattern(&mut self, pat: &Option>) -> Option> + fn lower_opt_pattern(&mut self, pat: &'tcx Option>) -> Option> { pat.as_ref().map(|p| self.lower_pattern(p)) } @@ -521,9 +519,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { &mut self, span: Span, ty: Ty<'tcx>, - prefix: &[P], - slice: &Option>, - suffix: &[P]) + prefix: &'tcx [P], + slice: &'tcx Option>, + suffix: &'tcx [P]) -> PatternKind<'tcx> { let prefix = self.lower_patterns(prefix); @@ -540,7 +538,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyArray(_, len) => { // fixed-length array - assert!(len >= prefix.len() + suffix.len()); + let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } } @@ -631,17 +630,17 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } } - fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> { + fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> { let const_cx = eval::ConstContext::new(self.tcx, self.param_env.and(self.substs), self.tables); match const_cx.eval(expr) { Ok(value) => { - if let ConstVal::Variant(def_id) = value { + if let ConstVal::Variant(def_id) = value.val { let ty = self.tables.expr_ty(expr); self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![]) } else { - PatternKind::Constant { value: value } + PatternKind::Constant { value } } } Err(e) => { @@ -652,7 +651,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } fn lower_const_expr(&mut self, - expr: &hir::Expr, + expr: &'tcx hir::Expr, pat_id: ast::NodeId, span: Span) -> Pattern<'tcx> { @@ -819,8 +818,8 @@ macro_rules! CloneImpls { } CloneImpls!{ <'tcx> - Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region<'tcx>, - Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef, + Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>, + Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef, &'tcx Substs<'tcx>, &'tcx Kind<'tcx> } @@ -892,18 +891,18 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { subpattern: subpattern.fold_with(folder), }, PatternKind::Constant { - ref value + value } => PatternKind::Constant { value: value.fold_with(folder) }, PatternKind::Range { - ref lo, - ref hi, - ref end, + lo, + hi, + end, } => PatternKind::Range { lo: lo.fold_with(folder), hi: hi.fold_with(folder), - end: end.clone(), + end, }, PatternKind::Slice { ref prefix, diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs index 65471416e8007..08473d729e4e5 100644 --- a/src/librustc_const_math/int.rs +++ b/src/librustc_const_math/int.rs @@ -311,17 +311,13 @@ impl ::std::fmt::Display for ConstInt { I32(i) => write!(fmt, "{}i32", i), I64(i) => write!(fmt, "{}i64", i), I128(i) => write!(fmt, "{}i128", i), - Isize(ConstIsize::Is64(i)) => write!(fmt, "{}isize", i), - Isize(ConstIsize::Is32(i)) => write!(fmt, "{}isize", i), - Isize(ConstIsize::Is16(i)) => write!(fmt, "{}isize", i), + Isize(i) => write!(fmt, "{}isize", i), U8(i) => write!(fmt, "{}u8", i), U16(i) => write!(fmt, "{}u16", i), U32(i) => write!(fmt, "{}u32", i), U64(i) => write!(fmt, "{}u64", i), U128(i) => write!(fmt, "{}u128", i), - Usize(ConstUsize::Us64(i)) => write!(fmt, "{}usize", i), - Usize(ConstUsize::Us32(i)) => write!(fmt, "{}usize", i), - Usize(ConstUsize::Us16(i)) => write!(fmt, "{}usize", i), + Usize(i) => write!(fmt, "{}usize", i), } } } diff --git a/src/librustc_const_math/is.rs b/src/librustc_const_math/is.rs index 8f28ba14c6aef..50dfb60112991 100644 --- a/src/librustc_const_math/is.rs +++ b/src/librustc_const_math/is.rs @@ -21,18 +21,22 @@ pub enum ConstIsize { } pub use self::ConstIsize::*; +impl ::std::fmt::Display for ConstIsize { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + write!(fmt, "{}", self.as_i64()) + } +} + impl ConstIsize { - pub fn as_i64(self, target_int_ty: ast::IntTy) -> i64 { - match (self, target_int_ty) { - (Is16(i), ast::IntTy::I16) => i as i64, - (Is32(i), ast::IntTy::I32) => i as i64, - (Is64(i), ast::IntTy::I64) => i, - _ => panic!("unable to convert self ({:?}) to target isize ({:?})", - self, target_int_ty), + pub fn as_i64(self) -> i64 { + match self { + Is16(i) => i as i64, + Is32(i) => i as i64, + Is64(i) => i, } } - pub fn new(i: i64, target_int_ty: ast::IntTy) -> Result { - match target_int_ty { + pub fn new(i: i64, isize_ty: ast::IntTy) -> Result { + match isize_ty { ast::IntTy::I16 if i as i16 as i64 == i => Ok(Is16(i as i16)), ast::IntTy::I16 => Err(LitOutOfRange(ast::IntTy::Is)), ast::IntTy::I32 if i as i32 as i64 == i => Ok(Is32(i as i32)), @@ -41,8 +45,8 @@ impl ConstIsize { _ => unreachable!(), } } - pub fn new_truncating(i: i128, target_int_ty: ast::IntTy) -> Self { - match target_int_ty { + pub fn new_truncating(i: i128, isize_ty: ast::IntTy) -> Self { + match isize_ty { ast::IntTy::I16 => Is16(i as i16), ast::IntTy::I32 => Is32(i as i32), ast::IntTy::I64 => Is64(i as i64), diff --git a/src/librustc_const_math/us.rs b/src/librustc_const_math/us.rs index 76443f584abac..9876bc4d779a0 100644 --- a/src/librustc_const_math/us.rs +++ b/src/librustc_const_math/us.rs @@ -21,18 +21,22 @@ pub enum ConstUsize { } pub use self::ConstUsize::*; +impl ::std::fmt::Display for ConstUsize { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + write!(fmt, "{}", self.as_u64()) + } +} + impl ConstUsize { - pub fn as_u64(self, target_uint_ty: ast::UintTy) -> u64 { - match (self, target_uint_ty) { - (Us16(i), ast::UintTy::U16) => i as u64, - (Us32(i), ast::UintTy::U32) => i as u64, - (Us64(i), ast::UintTy::U64) => i, - _ => panic!("unable to convert self ({:?}) to target usize ({:?})", - self, target_uint_ty), + pub fn as_u64(self) -> u64 { + match self { + Us16(i) => i as u64, + Us32(i) => i as u64, + Us64(i) => i, } } - pub fn new(i: u64, target_uint_ty: ast::UintTy) -> Result { - match target_uint_ty { + pub fn new(i: u64, usize_ty: ast::UintTy) -> Result { + match usize_ty { ast::UintTy::U16 if i as u16 as u64 == i => Ok(Us16(i as u16)), ast::UintTy::U16 => Err(ULitOutOfRange(ast::UintTy::Us)), ast::UintTy::U32 if i as u32 as u64 == i => Ok(Us32(i as u32)), @@ -41,8 +45,8 @@ impl ConstUsize { _ => unreachable!(), } } - pub fn new_truncating(i: u128, target_uint_ty: ast::UintTy) -> Self { - match target_uint_ty { + pub fn new_truncating(i: u128, usize_ty: ast::UintTy) -> Self { + match usize_ty { ast::UintTy::U16 => Us16(i as u16), ast::UintTy::U32 => Us32(i as u32), ast::UintTy::U64 => Us64(i as u64), diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 8038045f762d5..9259474ee27c4 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -801,13 +801,13 @@ fn walk_ty() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { let tcx = env.infcx.tcx; let int_ty = tcx.types.isize; - let uint_ty = tcx.types.usize; - let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty], false); - let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty], false); + let usize_ty = tcx.types.usize; + let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty], false); + let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty], false); let walked: Vec<_> = tup2_ty.walk().collect(); assert_eq!(walked, - [tup2_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, tup1_ty, int_ty, - uint_ty, int_ty, uint_ty, uint_ty]); + [tup2_ty, tup1_ty, int_ty, usize_ty, int_ty, usize_ty, tup1_ty, int_ty, + usize_ty, int_ty, usize_ty, usize_ty]); }) } @@ -816,20 +816,20 @@ fn walk_ty_skip_subtree() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { let tcx = env.infcx.tcx; let int_ty = tcx.types.isize; - let uint_ty = tcx.types.usize; - let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty], false); - let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty], false); + let usize_ty = tcx.types.usize; + let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty], false); + let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty], false); // types we expect to see (in order), plus a boolean saying // whether to skip the subtree. let mut expected = vec![(tup2_ty, false), (tup1_ty, false), (int_ty, false), - (uint_ty, false), + (usize_ty, false), (int_ty, false), - (uint_ty, false), + (usize_ty, false), (tup1_ty, true), // skip the isize/usize/isize/usize - (uint_ty, false)]; + (usize_ty, false)]; expected.reverse(); let mut walker = tup2_ty.walk(); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index ccd3194b5e388..d3a5d52b295af 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -76,7 +76,7 @@ impl LintPass for TypeLimits { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { - fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { match e.node { hir::ExprUnary(hir::UnNeg, ref expr) => { // propagate negation, if the negation itself isn't negated @@ -93,8 +93,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { if binop.node.is_shift() { let opt_ty_bits = match cx.tables.node_id_to_type(l.hir_id).sty { - ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)), - ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)), + ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.isize_ty)), + ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.usize_ty)), _ => None, }; @@ -117,7 +117,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { cx.param_env.and(substs), cx.tables); match const_cx.eval(&r) { - Ok(ConstVal::Integral(i)) => { + Ok(&ty::Const { val: ConstVal::Integral(i), .. }) => { i.is_negative() || i.to_u64() .map(|i| i >= bits) @@ -141,7 +141,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => { let int_type = if let ast::IntTy::Is = t { - cx.sess().target.int_type + cx.sess().target.isize_ty } else { t }; @@ -164,7 +164,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { } ty::TyUint(t) => { let uint_type = if let ast::UintTy::Us = t { - cx.sess().target.uint_type + cx.sess().target.usize_ty } else { t }; @@ -250,9 +250,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { } } - fn int_ty_bits(int_ty: ast::IntTy, target_int_ty: ast::IntTy) -> u64 { + fn int_ty_bits(int_ty: ast::IntTy, isize_ty: ast::IntTy) -> u64 { match int_ty { - ast::IntTy::Is => int_ty_bits(target_int_ty, target_int_ty), + ast::IntTy::Is => int_ty_bits(isize_ty, isize_ty), ast::IntTy::I8 => 8, ast::IntTy::I16 => 16 as u64, ast::IntTy::I32 => 32, @@ -261,9 +261,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { } } - fn uint_ty_bits(uint_ty: ast::UintTy, target_uint_ty: ast::UintTy) -> u64 { + fn uint_ty_bits(uint_ty: ast::UintTy, usize_ty: ast::UintTy) -> u64 { match uint_ty { - ast::UintTy::Us => uint_ty_bits(target_uint_ty, target_uint_ty), + ast::UintTy::Us => uint_ty_bits(usize_ty, usize_ty), ast::UintTy::U8 => 8, ast::UintTy::U16 => 16, ast::UintTy::U32 => 32, diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 73f1ae253cd29..689f9f5b24430 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -16,6 +16,7 @@ use schema::*; use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc::hir; +use rustc::middle::const_val::ByteArray; use rustc::middle::cstore::LinkagePreference; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -377,6 +378,20 @@ impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice } } +impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + Ok(ByteArray { + data: self.tcx().alloc_byte_array(&Vec::decode(self)?) + }) + } +} + +impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Const<'tcx>> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { + Ok(self.tcx().mk_const(Decodable::decode(self)?)) + } +} + impl<'a, 'tcx> MetadataBlob { pub fn is_compatible(&self) -> bool { self.raw_bytes().starts_with(METADATA_HEADER) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 3b07177b1b5c8..c96615064c80b 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1521,9 +1521,16 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { } fn encode_info_for_ty(&mut self, ty: &hir::Ty) { - if let hir::TyImplTrait(_) = ty.node { - let def_id = self.tcx.hir.local_def_id(ty.id); - self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id); + match ty.node { + hir::TyImplTrait(_) => { + let def_id = self.tcx.hir.local_def_id(ty.id); + self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id); + } + hir::TyArray(_, len) => { + let def_id = self.tcx.hir.body_owner_def_id(len); + self.record(def_id, IsolatedEncoder::encode_info_for_embedded_const, def_id); + } + _ => {} } } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index c83283ee38e1f..eeae4bce335ca 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -197,7 +197,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: expr_span, ty: this.hir.tcx().types.u32, literal: Literal::Value { - value: ConstVal::Integral(ConstInt::U32(0)), + value: this.hir.tcx().mk_const(ty::Const { + val: ConstVal::Integral(ConstInt::U32(0)), + ty: this.hir.tcx().types.u32 + }), }, })); box AggregateKind::Generator(closure_id, substs, interior) @@ -385,13 +388,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast::IntTy::I64 => ConstInt::I64(-1), ast::IntTy::I128 => ConstInt::I128(-1), ast::IntTy::Is => { - let int_ty = self.hir.tcx().sess.target.int_type; + let int_ty = self.hir.tcx().sess.target.isize_ty; let val = ConstIsize::new(-1, int_ty).unwrap(); ConstInt::Isize(val) } }; - Literal::Value { value: ConstVal::Integral(val) } + Literal::Value { + value: self.hir.tcx().mk_const(ty::Const { + val: ConstVal::Integral(val), + ty + }) + } } _ => { span_bug!(span, "Invalid type for neg_1_literal: `{:?}`", ty) @@ -412,7 +420,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast::IntTy::I64 => ConstInt::I64(i64::min_value()), ast::IntTy::I128 => ConstInt::I128(i128::min_value()), ast::IntTy::Is => { - let int_ty = self.hir.tcx().sess.target.int_type; + let int_ty = self.hir.tcx().sess.target.isize_ty; let min = match int_ty { ast::IntTy::I16 => std::i16::MIN as i64, ast::IntTy::I32 => std::i32::MIN as i64, @@ -424,7 +432,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } }; - Literal::Value { value: ConstVal::Integral(val) } + Literal::Value { + value: self.hir.tcx().mk_const(ty::Const { + val: ConstVal::Integral(val), + ty + }) + } } _ => { span_bug!(span, "Invalid type for minval_literal: `{:?}`", ty) diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index ec2e487b4e74c..f560fa426e22e 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -16,8 +16,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::bitvec::BitVector; -use rustc::middle::const_val::ConstVal; -use rustc::ty::{AdtDef, Ty}; +use rustc::ty::{self, Ty}; use rustc::mir::*; use rustc::hir; use hair::*; @@ -294,20 +293,20 @@ pub struct MatchPair<'pat, 'tcx:'pat> { enum TestKind<'tcx> { // test the branches of enum Switch { - adt_def: &'tcx AdtDef, + adt_def: &'tcx ty::AdtDef, variants: BitVector, }, // test the branches of enum SwitchInt { switch_ty: Ty<'tcx>, - options: Vec>, - indices: FxHashMap, usize>, + options: Vec<&'tcx ty::Const<'tcx>>, + indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>, }, // test for equality Eq { - value: ConstVal<'tcx>, + value: &'tcx ty::Const<'tcx>, ty: Ty<'tcx>, }, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 0b91e08fc6d70..7b91c43aa3722 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -61,24 +61,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - PatternKind::Constant { ref value } => { + PatternKind::Constant { value } => { Test { span: match_pair.pattern.span, kind: TestKind::Eq { - value: value.clone(), + value, ty: match_pair.pattern.ty.clone() } } } - PatternKind::Range { ref lo, ref hi, ref end } => { + PatternKind::Range { lo, hi, end } => { Test { span: match_pair.pattern.span, kind: TestKind::Range { - lo: Literal::Value { value: lo.clone() }, - hi: Literal::Value { value: hi.clone() }, + lo: Literal::Value { value: lo }, + hi: Literal::Value { value: hi }, ty: match_pair.pattern.ty.clone(), - end: end.clone(), + end, }, } } @@ -112,8 +112,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { test_lvalue: &Lvalue<'tcx>, candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, - options: &mut Vec>, - indices: &mut FxHashMap, usize>) + options: &mut Vec<&'tcx ty::Const<'tcx>>, + indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>) -> bool { let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) { @@ -122,13 +122,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; match *match_pair.pattern.kind { - PatternKind::Constant { ref value } => { + PatternKind::Constant { value } => { // if the lvalues match, the type should match assert_eq!(match_pair.pattern.ty, switch_ty); - indices.entry(value.clone()) + indices.entry(value) .or_insert_with(|| { - options.push(value.clone()); + options.push(value); options.len() - 1 }); true @@ -228,9 +228,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert!(options.len() > 0 && options.len() <= 2); let (true_bb, false_bb) = (self.cfg.start_new_block(), self.cfg.start_new_block()); - let ret = match &options[0] { - &ConstVal::Bool(true) => vec![true_bb, false_bb], - &ConstVal::Bool(false) => vec![false_bb, true_bb], + let ret = match options[0].val { + ConstVal::Bool(true) => vec![true_bb, false_bb], + ConstVal::Bool(false) => vec![false_bb, true_bb], v => span_bug!(test.span, "expected boolean value but got {:?}", v) }; (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Consume(lvalue.clone()), @@ -245,7 +245,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .chain(Some(otherwise)) .collect(); let values: Vec<_> = options.iter().map(|v| - v.to_const_int().expect("switching on integral") + v.val.to_const_int().expect("switching on integral") ).collect(); (targets.clone(), TerminatorKind::SwitchInt { discr: Operand::Consume(lvalue.clone()), @@ -258,12 +258,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ret } - TestKind::Eq { ref value, mut ty } => { + TestKind::Eq { value, mut ty } => { let mut val = Operand::Consume(lvalue.clone()); // If we're using b"..." as a pattern, we need to insert an // unsizing coercion, as the byte string has the type &[u8; N]. - let expect = if let ConstVal::ByteStr(ref bytes) = *value { + let expect = if let ConstVal::ByteStr(bytes) = value.val { let tcx = self.hir.tcx(); // Unsize the lvalue to &[u8], too, if necessary. @@ -279,10 +279,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { assert!(ty.is_slice()); - let array_ty = tcx.mk_array(tcx.types.u8, bytes.len()); + let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len() as u64); let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty); let array = self.literal_operand(test.span, array_ref, Literal::Value { - value: value.clone() + value }); let slice = self.temp(ty, test.span); @@ -291,7 +291,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Operand::Consume(slice) } else { self.literal_operand(test.span, ty, Literal::Value { - value: value.clone() + value }) }; diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 0e4aac4299111..1976b70ac0a23 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -59,7 +59,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty::TyBool => { self.hir.false_literal() } - ty::TyChar => Literal::Value { value: ConstVal::Char('\0') }, + ty::TyChar => { + Literal::Value { + value: self.hir.tcx().mk_const(ty::Const { + val: ConstVal::Char('\0'), + ty + }) + } + } ty::TyUint(ity) => { let val = match ity { ast::UintTy::U8 => ConstInt::U8(0), @@ -68,13 +75,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast::UintTy::U64 => ConstInt::U64(0), ast::UintTy::U128 => ConstInt::U128(0), ast::UintTy::Us => { - let uint_ty = self.hir.tcx().sess.target.uint_type; + let uint_ty = self.hir.tcx().sess.target.usize_ty; let val = ConstUsize::new(0, uint_ty).unwrap(); ConstInt::Usize(val) } }; - Literal::Value { value: ConstVal::Integral(val) } + Literal::Value { + value: self.hir.tcx().mk_const(ty::Const { + val: ConstVal::Integral(val), + ty + }) + } } ty::TyInt(ity) => { let val = match ity { @@ -84,13 +96,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast::IntTy::I64 => ConstInt::I64(0), ast::IntTy::I128 => ConstInt::I128(0), ast::IntTy::Is => { - let int_ty = self.hir.tcx().sess.target.int_type; + let int_ty = self.hir.tcx().sess.target.isize_ty; let val = ConstIsize::new(0, int_ty).unwrap(); ConstInt::Isize(val) } }; - Literal::Value { value: ConstVal::Integral(val) } + Literal::Value { + value: self.hir.tcx().mk_const(ty::Const { + val: ConstVal::Integral(val), + ty + }) + } } _ => { span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index a245411002f8a..be6f8c9e56c40 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -11,7 +11,6 @@ use build; use hair::cx::Cx; -use hair::Pattern; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::middle::region; @@ -167,6 +166,26 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> { } } + fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) { + if let Some(lifted) = self.tcx.lift(region) { + *region = lifted; + } else { + span_bug!(self.span, + "found region `{:?}` with inference types/regions in MIR", + region); + } + } + + fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) { + if let Some(lifted) = self.tcx.lift(constant) { + *constant = lifted; + } else { + span_bug!(self.span, + "found constant `{:?}` with inference types/regions in MIR", + constant); + } + } + fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, _: Location) { if let Some(lifted) = self.tcx.lift(substs) { *substs = lifted; @@ -537,10 +556,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let lvalue = Lvalue::Local(Local::new(index + 1)); if let Some(pattern) = pattern { - let pattern = Pattern::from_hir(self.hir.tcx().global_tcx(), - self.hir.param_env.and(self.hir.identity_substs), - self.hir.tables(), - pattern); + let pattern = self.hir.pattern_from_hir(pattern); scope = self.declare_bindings(scope, ast_body.span, &pattern); unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue)); } diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 8b3031a3800a5..f6b847d6d6de5 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -64,10 +64,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, first_statement_index: index as u32, }); - let pattern = Pattern::from_hir(cx.tcx.global_tcx(), - cx.param_env.and(cx.identity_substs), - cx.tables(), - &local.pat); + let pattern = cx.pattern_from_hir(&local.pat); result.push(StmtRef::Mirror(Box::new(Stmt { kind: StmtKind::Let { remainder_scope: remainder_scope, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 9de5262cd888c..45449103c8083 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -473,7 +473,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let def_id = cx.tcx.hir.body_owner_def_id(count); let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id); let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) { - Ok(ConstVal::Integral(ConstInt::Usize(u))) => u, + Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u, Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") }; @@ -591,13 +591,17 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, (cx.tables().type_dependent_defs()[expr.hir_id].def_id(), cx.tables().node_substs(expr.hir_id)) }); + let ty = cx.tcx().mk_fn_def(def_id, substs); Expr { temp_lifetime, - ty: cx.tcx().mk_fn_def(def_id, substs), + ty, span: expr.span, kind: ExprKind::Literal { literal: Literal::Value { - value: ConstVal::Function(def_id, substs), + value: cx.tcx.mk_const(ty::Const { + val: ConstVal::Function(def_id, substs), + ty + }), }, }, } @@ -612,12 +616,7 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind { fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> { Arm { - patterns: arm.pats.iter().map(|p| { - Pattern::from_hir(cx.tcx.global_tcx(), - cx.param_env.and(cx.identity_substs), - cx.tables(), - p) - }).collect(), + patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(), guard: arm.guard.to_ref(), body: arm.body.to_ref(), } @@ -635,15 +634,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::StructCtor(def_id, CtorKind::Fn) | Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal { literal: Literal::Value { - value: ConstVal::Function(def_id, substs), + value: cx.tcx.mk_const(ty::Const { + val: ConstVal::Function(def_id, substs), + ty: cx.tables().node_id_to_type(expr.hir_id) + }), }, }, Def::Const(def_id) | Def::AssociatedConst(def_id) => ExprKind::Literal { - literal: Literal::Item { - def_id, - substs, + literal: Literal::Value { + value: cx.tcx.mk_const(ty::Const { + val: ConstVal::Unevaluated(def_id, substs), + ty: cx.tables().node_id_to_type(expr.hir_id) + }), }, }, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 3cabd8f18c19e..f5e15979006af 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -112,8 +112,15 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> { - match ConstUsize::new(value, self.tcx.sess.target.uint_type) { - Ok(val) => Literal::Value { value: ConstVal::Integral(ConstInt::Usize(val)) }, + match ConstUsize::new(value, self.tcx.sess.target.usize_ty) { + Ok(val) => { + Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: ConstVal::Integral(ConstInt::Usize(val)), + ty: self.tcx.types.usize + }) + } + } Err(_) => bug!("usize literal out of range for target"), } } @@ -127,11 +134,21 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } pub fn true_literal(&mut self) -> Literal<'tcx> { - Literal::Value { value: ConstVal::Bool(true) } + Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: ConstVal::Bool(true), + ty: self.tcx.types.bool + }) + } } pub fn false_literal(&mut self) -> Literal<'tcx> { - Literal::Value { value: ConstVal::Bool(false) } + Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: ConstVal::Bool(false), + ty: self.tcx.types.bool + }) + } } pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> { @@ -139,12 +156,24 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let const_cx = ConstContext::new(tcx, self.param_env.and(self.identity_substs), self.tables()); - match const_cx.eval(e) { - Ok(value) => Literal::Value { value: value }, + match const_cx.eval(tcx.hir.expect_expr(e.id)) { + Ok(value) => Literal::Value { value }, Err(s) => self.fatal_const_eval_err(&s, e.span, "expression") } } + pub fn pattern_from_hir(&mut self, p: &hir::Pat) -> Pattern<'tcx> { + let tcx = self.tcx.global_tcx(); + let p = match tcx.hir.get(p.id) { + hir::map::NodePat(p) | hir::map::NodeBinding(p) => p, + node => bug!("pattern became {:?}", node) + }; + Pattern::from_hir(tcx, + self.param_env.and(self.identity_substs), + self.tables(), + p) + } + pub fn fatal_const_eval_err(&mut self, err: &ConstEvalErr<'tcx>, primary_span: Span, @@ -170,7 +199,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let method_ty = method_ty.subst(self.tcx, substs); return (method_ty, Literal::Value { - value: ConstVal::Function(item.def_id, substs), + value: self.tcx.mk_const(ty::Const { + val: ConstVal::Function(item.def_id, substs), + ty: method_ty + }), }); } } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index ec545443bcd90..00ee417e02b55 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -292,7 +292,10 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, match self_ty.sty { _ if is_copy => builder.copy_shim(), - ty::TyArray(ty, len) => builder.array_shim(ty, len), + ty::TyArray(ty, len) => { + let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + builder.array_shim(ty, len) + } ty::TyTuple(tys, _) => builder.tuple_shim(tys), _ => { bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty); @@ -403,11 +406,15 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ); // `func == Clone::clone(&ty) -> ty` + let func_ty = tcx.mk_fn_def(self.def_id, substs); let func = Operand::Constant(box Constant { span: self.span, - ty: tcx.mk_fn_def(self.def_id, substs), + ty: func_ty, literal: Literal::Value { - value: ConstVal::Function(self.def_id, substs), + value: tcx.mk_const(ty::Const { + val: ConstVal::Function(self.def_id, substs), + ty: func_ty + }), }, }); @@ -466,18 +473,21 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ); } - fn make_usize(&self, value: usize) -> Box> { - let value = ConstUsize::new(value as u64, self.tcx.sess.target.uint_type).unwrap(); + fn make_usize(&self, value: u64) -> Box> { + let value = ConstUsize::new(value, self.tcx.sess.target.usize_ty).unwrap(); box Constant { span: self.span, ty: self.tcx.types.usize, literal: Literal::Value { - value: ConstVal::Integral(ConstInt::Usize(value)) + value: self.tcx.mk_const(ty::Const { + val: ConstVal::Integral(ConstInt::Usize(value)), + ty: self.tcx.types.usize, + }) } } } - fn array_shim(&mut self, ty: ty::Ty<'tcx>, len: usize) { + fn array_shim(&mut self, ty: ty::Ty<'tcx>, len: u64) { let tcx = self.tcx; let span = self.span; let rcvr = Lvalue::Local(Local::new(1+0)).deref(); @@ -706,17 +716,21 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, let (callee, mut args) = match call_kind { CallKind::Indirect => (rcvr, vec![]), - CallKind::Direct(def_id) => ( - Operand::Constant(box Constant { + CallKind::Direct(def_id) => { + let ty = tcx.type_of(def_id); + (Operand::Constant(box Constant { span, - ty: tcx.type_of(def_id), + ty, literal: Literal::Value { - value: ConstVal::Function(def_id, - Substs::identity_for_item(tcx, def_id)), + value: tcx.mk_const(ty::Const { + val: ConstVal::Function(def_id, + Substs::identity_for_item(tcx, def_id)), + ty + }), }, - }), - vec![rcvr] - ) + }), + vec![rcvr]) + } }; if let Some(untuple_args) = untuple_args { diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index d6477f2babf76..1077f3b014616 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -520,7 +520,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { Rvalue::Use(Operand::Constant(Box::new(Constant { span, ty: self.tcx.types.bool, - literal: Literal::Value { value: ConstVal::Bool(val) } + literal: Literal::Value { + value: self.tcx.mk_const(ty::Const { + val: ConstVal::Bool(val), + ty: self.tcx.types.bool + }) + } }))) } diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index fa51cd91be1b6..dc18cdd8f0dd6 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -15,7 +15,7 @@ //! "types-as-contracts"-validation, namely, AcquireValid, ReleaseValid, and EndRegion. use rustc::ty::subst::Substs; -use rustc::ty::{Ty, TyCtxt, ClosureSubsts}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::mir::*; use rustc::mir::visit::{MutVisitor, Lookup}; use rustc::mir::transform::{MirPass, MirSource}; @@ -37,38 +37,25 @@ impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> { impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: Lookup) { if !self.in_validation_statement { - *ty = self.tcx.erase_regions(&{*ty}); + *ty = self.tcx.erase_regions(ty); } self.super_ty(ty); } - fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, _: Location) { - *substs = self.tcx.erase_regions(&{*substs}); + fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) { + *region = self.tcx.types.re_erased; } - fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { - match *rvalue { - Rvalue::Ref(ref mut r, _, _) => { - *r = self.tcx.types.re_erased; - } - Rvalue::Use(..) | - Rvalue::Repeat(..) | - Rvalue::Len(..) | - Rvalue::Cast(..) | - Rvalue::BinaryOp(..) | - Rvalue::CheckedBinaryOp(..) | - Rvalue::UnaryOp(..) | - Rvalue::Discriminant(..) | - Rvalue::NullaryOp(..) | - Rvalue::Aggregate(..) => { - // These variants don't contain regions. - } - } - self.super_rvalue(rvalue, location); + fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) { + *constant = self.tcx.erase_regions(constant); + } + + fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, _: Location) { + *substs = self.tcx.erase_regions(substs); } fn visit_closure_substs(&mut self, - substs: &mut ClosureSubsts<'tcx>, + substs: &mut ty::ClosureSubsts<'tcx>, _: Location) { *substs = self.tcx.erase_regions(substs); } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 0fb34c96b062d..a52656becd745 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -175,7 +175,10 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { span: source_info.span, ty: self.tcx.types.u32, literal: Literal::Value { - value: ConstVal::Integral(ConstInt::U32(state_disc)), + value: self.tcx.mk_const(ty::Const { + val: ConstVal::Integral(ConstInt::U32(state_disc)), + ty: self.tcx.types.u32 + }), }, }); Statement { @@ -553,7 +556,10 @@ fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: mir.span, ty: tcx.types.bool, literal: Literal::Value { - value: ConstVal::Bool(false), + value: tcx.mk_const(ty::Const { + val: ConstVal::Bool(false), + ty: tcx.types.bool + }), }, }), expected: true, @@ -603,7 +609,10 @@ fn create_generator_resume_function<'a, 'tcx>( span: mir.span, ty: tcx.types.bool, literal: Literal::Value { - value: ConstVal::Bool(false), + value: tcx.mk_const(ty::Const { + val: ConstVal::Bool(false), + ty: tcx.types.bool + }), }, }), expected: true, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index f891c991321c8..5550fb2788eaf 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -20,6 +20,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc::hir; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; +use rustc::middle::const_val::ConstVal; use rustc::traits::{self, Reveal}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; use rustc::ty::cast::CastTy; @@ -622,10 +623,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } Operand::Constant(ref constant) => { - if let Literal::Item { def_id, substs: _ } = constant.literal { + if let Literal::Value { + value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty } + } = constant.literal { // Don't peek inside trait associated constants. if self.tcx.trait_of_item(def_id).is_some() { - self.add_type(constant.ty); + self.add_type(ty); } else { let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(def_id); @@ -635,7 +638,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Just in case the type is more specific than // the definition, e.g. impl associated const // with type parameters, take it into account. - self.qualif.restrict(constant.ty, self.tcx, self.param_env); + self.qualif.restrict(ty, self.tcx, self.param_env); } // Let `const fn` transitively have destructors, @@ -695,8 +698,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } _ => false } - } else if let ty::TyArray(_, 0) = ty.sty { - self.mode == Mode::Fn + } else if let ty::TyArray(_, len) = ty.sty { + len.val.to_const_int().unwrap().to_u64().unwrap() == 0 && + self.mode == Mode::Fn } else { false }; diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 1dcacb29c3ecc..0dff145ecbce9 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -10,7 +10,7 @@ //! A pass that simplifies branches when their condition is known. -use rustc::ty::TyCtxt; +use rustc::ty::{self, TyCtxt}; use rustc::middle::const_val::ConstVal; use rustc::mir::transform::{MirPass, MirSource}; use rustc::mir::*; @@ -40,7 +40,7 @@ impl MirPass for SimplifyBranches { TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant { literal: Literal::Value { ref value }, .. }), ref values, ref targets, .. } => { - if let Some(ref constint) = value.to_const_int() { + if let Some(ref constint) = value.val.to_const_int() { let (otherwise, targets) = targets.split_last().unwrap(); let mut ret = TerminatorKind::Goto { target: *otherwise }; for (v, t) in values.iter().zip(targets.iter()) { @@ -56,7 +56,7 @@ impl MirPass for SimplifyBranches { }, TerminatorKind::Assert { target, cond: Operand::Constant(box Constant { literal: Literal::Value { - value: ConstVal::Bool(cond) + value: &ty::Const { val: ConstVal::Bool(cond), .. } }, .. }), expected, .. } if cond == expected => { TerminatorKind::Goto { target: target } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 7fbeb9610f471..ab5998a34805b 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -209,7 +209,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { LvalueTy::Ty { ty: match base_ty.sty { ty::TyArray(inner, size) => { - let min_size = (from as usize) + (to as usize); + let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let min_size = (from as u64) + (to as u64); if let Some(rest_size) = size.checked_sub(min_size) { tcx.mk_array(inner, rest_size) } else { @@ -572,7 +573,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match operand { &Operand::Constant(box Constant { literal: Literal::Value { - value: ConstVal::Function(def_id, _), .. + value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, .. }, .. }) => { Some(def_id) == self.tcx().lang_items().box_free_fn() diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 8ea47c2991009..4a11ac1168090 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -922,7 +922,12 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> Operand::Constant(box Constant { span: self.source_info.span, ty: self.tcx().types.usize, - literal: Literal::Value { value: ConstVal::Integral(self.tcx().const_usize(val)) } + literal: Literal::Value { + value: self.tcx().mk_const(ty::Const { + val: ConstVal::Integral(self.tcx().const_usize(val)), + ty: self.tcx().types.usize + }) + } }) } diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index 3273d66dd4f51..1fa49614580a3 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -13,7 +13,6 @@ // completely accurate (some things might be counted twice, others missed). use rustc_const_math::{ConstUsize}; -use rustc::middle::const_val::{ConstVal}; use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData}; use rustc::mir::{Constant, Literal, Location, LocalDecl}; use rustc::mir::{Lvalue, LvalueElem, LvalueProjection}; @@ -21,7 +20,7 @@ use rustc::mir::{Mir, Operand, ProjectionElem}; use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData}; use rustc::mir::visit as mir_visit; -use rustc::ty::{ClosureSubsts, TyCtxt}; +use rustc::ty::{self, ClosureSubsts, TyCtxt}; use rustc::util::nodemap::{FxHashMap}; struct NodeData { @@ -236,7 +235,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { location: Location) { self.record("Literal", literal); self.record(match *literal { - Literal::Item { .. } => "Literal::Item", Literal::Value { .. } => "Literal::Value", Literal::Promoted { .. } => "Literal::Promoted", }, literal); @@ -256,11 +254,11 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { self.super_closure_substs(substs); } - fn visit_const_val(&mut self, - const_val: &ConstVal, - _: Location) { - self.record("ConstVal", const_val); - self.super_const_val(const_val); + fn visit_const(&mut self, + constant: &&'tcx ty::Const<'tcx>, + _: Location) { + self.record("Const", constant); + self.super_const(constant); } fn visit_const_usize(&mut self, diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 5e50696b56009..4211c8df5ca03 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -11,7 +11,7 @@ use llvm::{self, ValueRef, AttributePlace}; use base; use builder::Builder; -use common::{instance_ty, ty_fn_sig, type_is_fat_ptr, C_uint}; +use common::{instance_ty, ty_fn_sig, type_is_fat_ptr, C_usize}; use context::CrateContext; use cabi_x86; use cabi_x86_64; @@ -527,7 +527,7 @@ impl<'a, 'tcx> ArgType<'tcx> { } let ccx = bcx.ccx; if self.is_indirect() { - let llsz = C_uint(ccx, self.layout.size(ccx).bytes()); + let llsz = C_usize(ccx, self.layout.size(ccx).bytes()); let llalign = self.layout.align(ccx).abi(); base::call_memcpy(bcx, dst, val, llsz, llalign as u32); } else if let Some(ty) = self.cast { @@ -564,7 +564,7 @@ impl<'a, 'tcx> ArgType<'tcx> { base::call_memcpy(bcx, bcx.pointercast(dst, Type::i8p(ccx)), bcx.pointercast(llscratch, Type::i8p(ccx)), - C_uint(ccx, self.layout.size(ccx).bytes()), + C_usize(ccx, self.layout.size(ccx).bytes()), cmp::min(self.layout.align(ccx).abi() as u32, llalign_of_min(ccx, ty))); diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 11db23732fba3..23a45a7962abf 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -397,11 +397,11 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu match *l { layout::CEnum{ discr, min, max, .. } => { assert_discr_in_range(min, max, to); - bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true), + bcx.store(C_int(Type::from_integer(bcx.ccx, discr), to as i64), val, None); } layout::General{ discr, .. } => { - bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true), + bcx.store(C_int(Type::from_integer(bcx.ccx, discr), to as i64), bcx.struct_gep(val, 0), None); } layout::Univariant { .. } @@ -423,7 +423,7 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu // than storing null to single target field. let llptr = bcx.pointercast(val, Type::i8(bcx.ccx).ptr_to()); let fill_byte = C_u8(bcx.ccx, 0); - let size = C_uint(bcx.ccx, nonnull.stride().bytes()); + let size = C_usize(bcx.ccx, nonnull.stride().bytes()); let align = C_i32(bcx.ccx, nonnull.align.abi() as i32); base::call_memset(bcx, llptr, fill_byte, size, align, false); } else { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 6cfde9c7bbc73..73209affe994b 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -53,7 +53,7 @@ use mir::lvalue::LvalueRef; use attributes; use builder::Builder; use callee; -use common::{C_bool, C_bytes_in_context, C_i32, C_uint}; +use common::{C_bool, C_bytes_in_context, C_i32, C_usize}; use collector::{self, TransItemCollectionMode}; use common::{C_struct_in_context, C_u64, C_undef, C_array}; use common::CrateContext; @@ -201,7 +201,9 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, -> ValueRef { let (source, target) = ccx.tcx().struct_lockstep_tails(source, target); match (&source.sty, &target.sty) { - (&ty::TyArray(_, len), &ty::TySlice(_)) => C_uint(ccx, len), + (&ty::TyArray(_, len), &ty::TySlice(_)) => { + C_usize(ccx, len.val.to_const_int().unwrap().to_u64().unwrap()) + } (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { // For now, upcasts are limited to changes in marker // traits, and hence never actually require an actual @@ -524,7 +526,7 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>, let memcpy = ccx.get_intrinsic(&key); let src_ptr = b.pointercast(src, Type::i8p(ccx)); let dst_ptr = b.pointercast(dst, Type::i8p(ccx)); - let size = b.intcast(n_bytes, ccx.int_type(), false); + let size = b.intcast(n_bytes, ccx.isize_ty(), false); let align = C_i32(ccx, align as i32); let volatile = C_bool(ccx, false); b.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None); @@ -545,7 +547,7 @@ pub fn memcpy_ty<'a, 'tcx>( } let align = align.unwrap_or_else(|| ccx.align_of(t)); - call_memcpy(bcx, dst, src, C_uint(ccx, size), align); + call_memcpy(bcx, dst, src, C_usize(ccx, size), align); } pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>, @@ -696,7 +698,7 @@ fn maybe_create_entry_wrapper(ccx: &CrateContext) { sp: Span, rust_main: ValueRef, use_start_lang_item: bool) { - let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()], &ccx.int_type()); + let llfty = Type::func(&[ccx.isize_ty(), Type::i8p(ccx).ptr_to()], &ccx.isize_ty()); if declare::get_defined_value(ccx, "main").is_some() { // FIXME: We should be smart and show a better diagnostic here. diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index b56fa34e348e5..3bf709ff7ba9d 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -193,6 +193,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; +use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items::{ExchangeMallocFnLangItem}; use rustc::traits; use rustc::ty::subst::Substs; @@ -564,24 +565,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_rvalue(rvalue, location); } - fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) { - debug!("visiting constant {:?} @ {:?}", *constant, location); + fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { + debug!("visiting const {:?} @ {:?}", *constant, location); - if let ty::TyFnDef(..) = constant.ty.sty { - // function definitions are zero-sized, and only generate - // IR when they are called/reified. - self.super_constant(constant, location); - return - } - - if let mir::Literal::Item { def_id, substs } = constant.literal { + if let ConstVal::Unevaluated(def_id, substs) = constant.val { let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs, &substs); let instance = monomorphize::resolve(self.scx, def_id, substs); collect_neighbours(self.scx, instance, true, self.output); } - self.super_constant(constant, location); + self.super_const(constant); } fn visit_terminator_kind(&mut self, diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index d947cd8e71974..67c95b92e523b 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -221,9 +221,15 @@ pub fn C_undef(t: Type) -> ValueRef { } } -pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { +pub fn C_int(t: Type, i: i64) -> ValueRef { unsafe { - llvm::LLVMConstInt(t.to_ref(), u, sign_extend as Bool) + llvm::LLVMConstInt(t.to_ref(), i as u64, True) + } +} + +pub fn C_uint(t: Type, i: u64) -> ValueRef { + unsafe { + llvm::LLVMConstInt(t.to_ref(), i, False) } } @@ -239,49 +245,34 @@ pub fn C_nil(ccx: &CrateContext) -> ValueRef { } pub fn C_bool(ccx: &CrateContext, val: bool) -> ValueRef { - C_integral(Type::i1(ccx), val as u64, false) + C_uint(Type::i1(ccx), val as u64) } pub fn C_i32(ccx: &CrateContext, i: i32) -> ValueRef { - C_integral(Type::i32(ccx), i as u64, true) + C_int(Type::i32(ccx), i as i64) } pub fn C_u32(ccx: &CrateContext, i: u32) -> ValueRef { - C_integral(Type::i32(ccx), i as u64, false) + C_uint(Type::i32(ccx), i as u64) } pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef { - C_integral(Type::i64(ccx), i, false) + C_uint(Type::i64(ccx), i) } -pub fn C_uint(ccx: &CrateContext, i: I) -> ValueRef { - let v = i.as_u64(); - - let bit_size = machine::llbitsize_of_real(ccx, ccx.int_type()); +pub fn C_usize(ccx: &CrateContext, i: u64) -> ValueRef { + let bit_size = machine::llbitsize_of_real(ccx, ccx.isize_ty()); if bit_size < 64 { // make sure it doesn't overflow - assert!(v < (1< i64; } -pub trait AsU64 { fn as_u64(self) -> u64; } - -// FIXME: remove the intptr conversions, because they -// are host-architecture-dependent -impl AsI64 for i64 { fn as_i64(self) -> i64 { self as i64 }} -impl AsI64 for i32 { fn as_i64(self) -> i64 { self as i64 }} -impl AsI64 for isize { fn as_i64(self) -> i64 { self as i64 }} - -impl AsU64 for u64 { fn as_u64(self) -> u64 { self as u64 }} -impl AsU64 for u32 { fn as_u64(self) -> u64 { self as u64 }} -impl AsU64 for usize { fn as_u64(self) -> u64 { self as u64 }} - pub fn C_u8(ccx: &CrateContext, i: u8) -> ValueRef { - C_integral(Type::i8(ccx), i as u64, false) + C_uint(Type::i8(ccx), i as u64) } @@ -315,7 +306,7 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef { let len = s.len(); let cs = consts::ptrcast(C_cstr(cx, s, false), Type::i8p(cx)); - C_named_struct(cx.str_slice_type(), &[cs, C_uint(cx, len)]) + C_named_struct(cx.str_slice_type(), &[cs, C_usize(cx, len as u64)]) } pub fn C_struct(cx: &CrateContext, elts: &[ValueRef], packed: bool) -> ValueRef { @@ -482,9 +473,9 @@ pub fn shift_mask_val<'a, 'tcx>( // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc. let val = llty.int_width() - 1; if invert { - C_integral(mask_llty, !val, true) + C_int(mask_llty, !val as i64) } else { - C_integral(mask_llty, val, false) + C_uint(mask_llty, val) } }, TypeKind::Vector => { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index a5830eb17edb1..77bddc7731b5b 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -136,7 +136,7 @@ pub struct LocalCrateContext<'a, 'tcx: 'a> { used_statics: RefCell>, lltypes: RefCell, Type>>, - int_type: Type, + isize_ty: Type, opaque_vec_type: Type, str_slice_type: Type, @@ -398,7 +398,7 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { statics_to_rauw: RefCell::new(Vec::new()), used_statics: RefCell::new(Vec::new()), lltypes: RefCell::new(FxHashMap()), - int_type: Type::from_ref(ptr::null_mut()), + isize_ty: Type::from_ref(ptr::null_mut()), opaque_vec_type: Type::from_ref(ptr::null_mut()), str_slice_type: Type::from_ref(ptr::null_mut()), dbg_cx, @@ -410,23 +410,23 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { placeholder: PhantomData, }; - let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = { + let (isize_ty, opaque_vec_type, str_slice_ty, mut local_ccx) = { // Do a little dance to create a dummy CrateContext, so we can // create some things in the LLVM module of this codegen unit let mut local_ccxs = vec![local_ccx]; - let (int_type, opaque_vec_type, str_slice_ty) = { + let (isize_ty, opaque_vec_type, str_slice_ty) = { let dummy_ccx = LocalCrateContext::dummy_ccx(shared, local_ccxs.as_mut_slice()); let mut str_slice_ty = Type::named_struct(&dummy_ccx, "str_slice"); str_slice_ty.set_struct_body(&[Type::i8p(&dummy_ccx), - Type::int(&dummy_ccx)], + Type::isize(&dummy_ccx)], false); - (Type::int(&dummy_ccx), Type::opaque_vec(&dummy_ccx), str_slice_ty) + (Type::isize(&dummy_ccx), Type::opaque_vec(&dummy_ccx), str_slice_ty) }; - (int_type, opaque_vec_type, str_slice_ty, local_ccxs.pop().unwrap()) + (isize_ty, opaque_vec_type, str_slice_ty, local_ccxs.pop().unwrap()) }; - local_ccx.int_type = int_type; + local_ccx.isize_ty = isize_ty; local_ccx.opaque_vec_type = opaque_vec_type; local_ccx.str_slice_type = str_slice_ty; @@ -549,8 +549,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().stats } - pub fn int_type(&self) -> Type { - self.local().int_type + pub fn isize_ty(&self) -> Type { + self.local().isize_ty } pub fn str_slice_type(&self) -> Type { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 8bd835ac5d114..3c87bc293b5b5 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -366,7 +366,7 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, -> bool { member_llvm_types.len() == 2 && member_llvm_types[0] == type_of::type_of(cx, element_type).ptr_to() && - member_llvm_types[1] == cx.int_type() + member_llvm_types[1] == cx.isize_ty() } } @@ -530,7 +530,8 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, MetadataCreationResult::new(basic_type_metadata(cx, t), false) } ty::TyArray(typ, len) => { - fixed_vec_metadata(cx, unique_type_id, typ, Some(len as u64), usage_site_span) + let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + fixed_vec_metadata(cx, unique_type_id, typ, Some(len), usage_site_span) } ty::TySlice(typ) => { fixed_vec_metadata(cx, unique_type_id, typ, None, usage_site_span) diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 6eda865751933..7bf9d39ea2f25 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -96,7 +96,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyArray(inner_type, len) => { output.push('['); push_debuginfo_type_name(cx, inner_type, true, output); - output.push_str(&format!("; {}", len)); + output.push_str(&format!("; {}", len.val.to_const_int().unwrap().to_u64().unwrap())); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index c2f44c089a2d6..8dd0b4e466ce4 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -70,8 +70,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf let align = bcx.ccx.align_of(t); debug!("size_and_align_of_dst t={} info={:?} size: {} align: {}", t, Value(info), size, align); - let size = C_uint(bcx.ccx, size); - let align = C_uint(bcx.ccx, align); + let size = C_usize(bcx.ccx, size); + let align = C_usize(bcx.ccx, align as u64); return (size, align); } assert!(!info.is_null()); @@ -96,8 +96,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf }; debug!("DST {} statically sized prefix size: {} align: {}", t, sized_size, sized_align); - let sized_size = C_uint(ccx, sized_size); - let sized_align = C_uint(ccx, sized_align); + let sized_size = C_usize(ccx, sized_size); + let sized_align = C_usize(ccx, sized_align); // Recurse to get the size of the dynamically sized field (must be // the last field). @@ -128,7 +128,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf (Some(sized_align), Some(unsized_align)) => { // If both alignments are constant, (the sized_align should always be), then // pick the correct alignment statically. - C_uint(ccx, std::cmp::max(sized_align, unsized_align) as u64) + C_usize(ccx, std::cmp::max(sized_align, unsized_align) as u64) } _ => bcx.select(bcx.icmp(llvm::IntUGT, sized_align, unsized_align), sized_align, @@ -146,7 +146,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf // // `(size + (align-1)) & -align` - let addend = bcx.sub(align, C_uint(bcx.ccx, 1_u64)); + let addend = bcx.sub(align, C_usize(bcx.ccx, 1)); let size = bcx.and(bcx.add(size, addend), bcx.neg(align)); (size, align) @@ -159,8 +159,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf let unit = t.sequence_element_type(bcx.tcx()); // The info in this case is the length of the str, so the size is that // times the unit size. - (bcx.mul(info, C_uint(bcx.ccx, bcx.ccx.size_of(unit))), - C_uint(bcx.ccx, bcx.ccx.align_of(unit))) + (bcx.mul(info, C_usize(bcx.ccx, bcx.ccx.size_of(unit))), + C_usize(bcx.ccx, bcx.ccx.align_of(unit) as u64)) } _ => bug!("Unexpected unsized type, found {}", t) } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 8f968a8a6c609..f78d80a197ca9 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -135,7 +135,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, "size_of" => { let tp_ty = substs.type_at(0); let lltp_ty = type_of::type_of(ccx, tp_ty); - C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) + C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) } "size_of_val" => { let tp_ty = substs.type_at(0); @@ -145,12 +145,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, llsize } else { let lltp_ty = type_of::type_of(ccx, tp_ty); - C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) + C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) } } "min_align_of" => { let tp_ty = substs.type_at(0); - C_uint(ccx, ccx.align_of(tp_ty)) + C_usize(ccx, ccx.align_of(tp_ty) as u64) } "min_align_of_val" => { let tp_ty = substs.type_at(0); @@ -159,13 +159,13 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]); llalign } else { - C_uint(ccx, ccx.align_of(tp_ty)) + C_usize(ccx, ccx.align_of(tp_ty) as u64) } } "pref_align_of" => { let tp_ty = substs.type_at(0); let lltp_ty = type_of::type_of(ccx, tp_ty); - C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)) + C_usize(ccx, machine::llalign_of_pref(ccx, lltp_ty) as u64) } "type_name" => { let tp_ty = substs.type_at(0); @@ -182,7 +182,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, // If we store a zero constant, LLVM will drown in vreg allocation for large data // structures, and the generated code will be awful. (A telltale sign of this is // large quantities of `mov [byte ptr foo],0` in the generated code.) - memset_intrinsic(bcx, false, ty, llresult, C_u8(ccx, 0), C_uint(ccx, 1usize)); + memset_intrinsic(bcx, false, ty, llresult, C_u8(ccx, 0), C_usize(ccx, 1)); } C_nil(ccx) } @@ -386,10 +386,10 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, "align_offset" => { // `ptr as usize` - let ptr_val = bcx.ptrtoint(llargs[0], bcx.ccx.int_type()); + let ptr_val = bcx.ptrtoint(llargs[0], bcx.ccx.isize_ty()); // `ptr_val % align` let offset = bcx.urem(ptr_val, llargs[1]); - let zero = C_null(bcx.ccx.int_type()); + let zero = C_null(bcx.ccx.isize_ty()); // `offset == 0` let is_zero = bcx.icmp(llvm::IntPredicate::IntEQ, offset, zero); // `if offset == 0 { 0 } else { offset - align }` @@ -688,7 +688,7 @@ fn copy_intrinsic<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let lltp_ty = type_of::type_of(ccx, tp_ty); let align = C_i32(ccx, ccx.align_of(tp_ty) as i32); let size = machine::llsize_of(ccx, lltp_ty); - let int_size = machine::llbitsize_of_real(ccx, ccx.int_type()); + let int_size = machine::llbitsize_of_real(ccx, ccx.isize_ty()); let operation = if allow_overlap { "memmove" diff --git a/src/librustc_trans/machine.rs b/src/librustc_trans/machine.rs index cd31f02842add..bc383abc7e0ec 100644 --- a/src/librustc_trans/machine.rs +++ b/src/librustc_trans/machine.rs @@ -48,7 +48,7 @@ pub fn llsize_of(cx: &CrateContext, ty: Type) -> ValueRef { // there's no need for that contrivance. The instruction // selection DAG generator would flatten that GEP(1) node into a // constant of the type's alloc size, so let's save it some work. - return C_uint(cx, llsize_of_alloc(cx, ty)); + return C_usize(cx, llsize_of_alloc(cx, ty)); } // Returns the preferred alignment of the given type for the current target. diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index f5f924178589a..6eedd53974e70 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> VirtualIndex { // Load the data pointer from the object. debug!("get_int({:?}, {:?})", Value(llvtable), self); - let llvtable = bcx.pointercast(llvtable, Type::int(bcx.ccx).ptr_to()); + let llvtable = bcx.pointercast(llvtable, Type::isize(bcx.ccx).ptr_to()); let ptr = bcx.load(bcx.gepi(llvtable, &[self.0]), None); // Vtable loads are invariant bcx.set_invariant_load(ptr); @@ -81,8 +81,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let mut components: Vec<_> = [ callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)), - C_uint(ccx, ccx.size_of(ty)), - C_uint(ccx, ccx.align_of(ty)) + C_usize(ccx, ccx.size_of(ty)), + C_usize(ccx, ccx.align_of(ty) as u64) ].iter().cloned().collect(); if let Some(trait_ref) = trait_ref { diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 949b9fe71ca64..1017ec6b3c3f8 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal; use rustc::mir::{self, Location, TerminatorKind, Literal}; use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; +use rustc::ty; use common; use super::MirContext; @@ -110,7 +111,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { mir::TerminatorKind::Call { func: mir::Operand::Constant(box mir::Constant { literal: Literal::Value { - value: ConstVal::Function(def_id, _), .. + value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, .. }, .. }), ref args, .. diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1109f34a1482e..4c3326a466d3a 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -26,8 +26,8 @@ use abi::{self, Abi}; use callee; use builder::Builder; use common::{self, CrateContext, const_get_elt, val_ty}; -use common::{C_array, C_bool, C_bytes, C_integral, C_big_integral, C_u32, C_u64}; -use common::{C_null, C_struct, C_str_slice, C_undef, C_uint, C_vector, is_undef}; +use common::{C_array, C_bool, C_bytes, C_int, C_uint, C_big_integral, C_u32, C_u64}; +use common::{C_null, C_struct, C_str_slice, C_undef, C_usize, C_vector, is_undef}; use common::const_to_opt_u128; use consts; use monomorphize; @@ -66,35 +66,29 @@ impl<'tcx> Const<'tcx> { -> Const<'tcx> { let tcx = ccx.tcx(); let (llval, ty) = match *ci { - I8(v) => (C_integral(Type::i8(ccx), v as u64, true), tcx.types.i8), - I16(v) => (C_integral(Type::i16(ccx), v as u64, true), tcx.types.i16), - I32(v) => (C_integral(Type::i32(ccx), v as u64, true), tcx.types.i32), - I64(v) => (C_integral(Type::i64(ccx), v as u64, true), tcx.types.i64), + I8(v) => (C_int(Type::i8(ccx), v as i64), tcx.types.i8), + I16(v) => (C_int(Type::i16(ccx), v as i64), tcx.types.i16), + I32(v) => (C_int(Type::i32(ccx), v as i64), tcx.types.i32), + I64(v) => (C_int(Type::i64(ccx), v as i64), tcx.types.i64), I128(v) => (C_big_integral(Type::i128(ccx), v as u128), tcx.types.i128), - Isize(v) => { - let i = v.as_i64(ccx.tcx().sess.target.int_type); - (C_integral(Type::int(ccx), i as u64, true), tcx.types.isize) - }, - U8(v) => (C_integral(Type::i8(ccx), v as u64, false), tcx.types.u8), - U16(v) => (C_integral(Type::i16(ccx), v as u64, false), tcx.types.u16), - U32(v) => (C_integral(Type::i32(ccx), v as u64, false), tcx.types.u32), - U64(v) => (C_integral(Type::i64(ccx), v, false), tcx.types.u64), + Isize(v) => (C_int(Type::isize(ccx), v.as_i64()), tcx.types.isize), + U8(v) => (C_uint(Type::i8(ccx), v as u64), tcx.types.u8), + U16(v) => (C_uint(Type::i16(ccx), v as u64), tcx.types.u16), + U32(v) => (C_uint(Type::i32(ccx), v as u64), tcx.types.u32), + U64(v) => (C_uint(Type::i64(ccx), v), tcx.types.u64), U128(v) => (C_big_integral(Type::i128(ccx), v), tcx.types.u128), - Usize(v) => { - let u = v.as_u64(ccx.tcx().sess.target.uint_type); - (C_integral(Type::int(ccx), u, false), tcx.types.usize) - }, + Usize(v) => (C_uint(Type::isize(ccx), v.as_u64()), tcx.types.usize), }; Const { llval: llval, ty: ty } } /// Translate ConstVal into a LLVM constant value. pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>, - cv: ConstVal, + cv: &ConstVal, ty: Ty<'tcx>) -> Const<'tcx> { let llty = type_of::type_of(ccx, ty); - let val = match cv { + let val = match *cv { ConstVal::Float(v) => { let bits = match v.ty { ast::FloatTy::F32 => C_u32(ccx, v.bits as u32), @@ -105,12 +99,12 @@ impl<'tcx> Const<'tcx> { ConstVal::Bool(v) => C_bool(ccx, v), ConstVal::Integral(ref i) => return Const::from_constint(ccx, i), ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()), - ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"), - ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false), + ConstVal::ByteStr(v) => consts::addr_of(ccx, C_bytes(ccx, v.data), 1, "byte_str"), + ConstVal::Char(c) => C_uint(Type::char(ccx), c as u64), ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)), ConstVal::Variant(_) | - ConstVal::Struct(_) | ConstVal::Tuple(_) | - ConstVal::Array(..) | ConstVal::Repeat(..) => { + ConstVal::Aggregate(..) | + ConstVal::Unevaluated(..) => { bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) } }; @@ -207,7 +201,9 @@ impl<'tcx> ConstLvalue<'tcx> { pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef { match self.ty.sty { - ty::TyArray(_, n) => C_uint(ccx, n), + ty::TyArray(_, n) => { + C_usize(ccx, n.val.to_const_int().unwrap().to_u64().unwrap()) + } ty::TySlice(_) | ty::TyStr => { assert!(self.llextra != ptr::null_mut()); self.llextra @@ -367,13 +363,13 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let result = if fn_ty.fn_sig(tcx).abi() == Abi::RustIntrinsic { match &tcx.item_name(def_id)[..] { "size_of" => { - let llval = C_uint(self.ccx, + let llval = C_usize(self.ccx, self.ccx.size_of(substs.type_at(0))); Ok(Const::new(llval, tcx.types.usize)) } "min_align_of" => { - let llval = C_uint(self.ccx, - self.ccx.align_of(substs.type_at(0))); + let llval = C_usize(self.ccx, + self.ccx.align_of(substs.type_at(0)) as u64); Ok(Const::new(llval, tcx.types.usize)) } _ => span_bug!(span, "{:?} in constant", terminator.kind) @@ -514,16 +510,17 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::Operand::Constant(ref constant) => { let ty = self.monomorphize(&constant.ty); match constant.literal.clone() { - mir::Literal::Item { def_id, substs } => { - let substs = self.monomorphize(&substs); - MirConstContext::trans_def(self.ccx, def_id, substs, IndexVec::new()) - } mir::Literal::Promoted { index } => { let mir = &self.mir.promoted[index]; MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans() } mir::Literal::Value { value } => { - Ok(Const::from_constval(self.ccx, value, ty)) + if let ConstVal::Unevaluated(def_id, substs) = value.val { + let substs = self.monomorphize(&substs); + MirConstContext::trans_def(self.ccx, def_id, substs, IndexVec::new()) + } else { + Ok(Const::from_constval(self.ccx, &value.val, ty)) + } } } } @@ -557,9 +554,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let val = match *rvalue { mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?, - mir::Rvalue::Repeat(ref elem, ref count) => { + mir::Rvalue::Repeat(ref elem, count) => { let elem = self.const_operand(elem, span)?; - let size = count.as_u64(tcx.sess.target.uint_type); + let size = count.as_u64(); + assert_eq!(size as usize as u64, size); let fields = vec![elem.llval; size as usize]; self.const_array(dest_ty, &fields) } @@ -836,7 +834,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => { assert!(self.ccx.shared().type_is_sized(ty)); - let llval = C_uint(self.ccx, self.ccx.size_of(ty)); + let llval = C_usize(self.ccx, self.ccx.size_of(ty)); Const::new(llval, tcx.types.usize) } @@ -854,10 +852,10 @@ fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option { match t.sty { ty::TyInt(int_type) => const_to_opt_u128(value, true) .and_then(|input| ConstInt::new_signed(input as i128, int_type, - tcx.sess.target.int_type)), + tcx.sess.target.isize_ty)), ty::TyUint(uint_type) => const_to_opt_u128(value, false) .and_then(|input| ConstInt::new_unsigned(input, uint_type, - tcx.sess.target.uint_type)), + tcx.sess.target.usize_ty)), _ => None } @@ -963,16 +961,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { debug!("trans_constant({:?})", constant); let ty = self.monomorphize(&constant.ty); let result = match constant.literal.clone() { - mir::Literal::Item { def_id, substs } => { - let substs = self.monomorphize(&substs); - MirConstContext::trans_def(bcx.ccx, def_id, substs, IndexVec::new()) - } mir::Literal::Promoted { index } => { let mir = &self.mir.promoted[index]; MirConstContext::new(bcx.ccx, mir, self.param_substs, IndexVec::new()).trans() } mir::Literal::Value { value } => { - Ok(Const::from_constval(bcx.ccx, value, ty)) + if let ConstVal::Unevaluated(def_id, substs) = value.val { + let substs = self.monomorphize(&substs); + MirConstContext::trans_def(bcx.ccx, def_id, substs, IndexVec::new()) + } else { + Ok(Const::from_constval(bcx.ccx, &value.val, ty)) + } } }; @@ -1038,11 +1037,11 @@ fn trans_const<'a, 'tcx>( }; assert_eq!(vals.len(), 0); adt::assert_discr_in_range(min, max, discr); - C_integral(Type::from_integer(ccx, d), discr, true) + C_int(Type::from_integer(ccx, d), discr as i64) } layout::General { discr: d, ref variants, .. } => { let variant = &variants[variant_index]; - let lldiscr = C_integral(Type::from_integer(ccx, d), variant_index as u64, true); + let lldiscr = C_int(Type::from_integer(ccx, d), variant_index as i64); let mut vals_with_discr = vec![lldiscr]; vals_with_discr.extend_from_slice(vals); let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]); diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 8155303b0d3fc..6799e52904d34 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -16,7 +16,7 @@ use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; use adt; use builder::Builder; -use common::{self, CrateContext, C_uint}; +use common::{self, CrateContext, C_usize}; use consts; use machine; use type_of; @@ -106,7 +106,9 @@ impl<'a, 'tcx> LvalueRef<'tcx> { pub fn len(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef { let ty = self.ty.to_ty(ccx.tcx()); match ty.sty { - ty::TyArray(_, n) => common::C_uint(ccx, n), + ty::TyArray(_, n) => { + common::C_usize(ccx, n.val.to_const_int().unwrap().to_u64().unwrap()) + } ty::TySlice(_) | ty::TyStr => { assert!(self.llextra != ptr::null_mut()); self.llextra @@ -186,7 +188,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> { let offset = st.offsets[ix].bytes(); - let unaligned_offset = C_uint(bcx.ccx, offset); + let unaligned_offset = C_usize(bcx.ccx, offset); // Get the alignment of the field let (_, align) = glue::size_and_align_of_dst(bcx, fty, meta); @@ -197,7 +199,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> { // (unaligned offset + (align - 1)) & -align // Calculate offset - let align_sub_1 = bcx.sub(align, C_uint(bcx.ccx, 1u64)); + let align_sub_1 = bcx.sub(align, C_usize(bcx.ccx, 1)); let offset = bcx.and(bcx.add(unaligned_offset, align_sub_1), bcx.neg(align)); @@ -276,7 +278,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> { // Slices already point to the array element type. bcx.inbounds_gep(self.llval, &[llindex]) } else { - let zero = common::C_uint(bcx.ccx, 0u64); + let zero = common::C_usize(bcx.ccx, 0); bcx.inbounds_gep(self.llval, &[zero, llindex]) } } @@ -342,19 +344,19 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => { - let lloffset = C_uint(bcx.ccx, offset); + let lloffset = C_usize(bcx.ccx, offset as u64); ((tr_base.project_index(bcx, lloffset), align), ptr::null_mut()) } mir::ProjectionElem::ConstantIndex { offset, from_end: true, min_length: _ } => { - let lloffset = C_uint(bcx.ccx, offset); + let lloffset = C_usize(bcx.ccx, offset as u64); let lllen = tr_base.len(bcx.ccx); let llindex = bcx.sub(lllen, lloffset); ((tr_base.project_index(bcx, llindex), align), ptr::null_mut()) } mir::ProjectionElem::Subslice { from, to } => { - let llbase = tr_base.project_index(bcx, C_uint(bcx.ccx, from)); + let llbase = tr_base.project_index(bcx, C_usize(bcx.ccx, from as u64)); let base_ty = tr_base.ty.to_ty(bcx.tcx()); match base_ty.sty { @@ -369,7 +371,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { ty::TySlice(..) => { assert!(tr_base.llextra != ptr::null_mut()); let lllen = bcx.sub(tr_base.llextra, - C_uint(bcx.ccx, from+to)); + C_usize(bcx.ccx, (from as u64)+(to as u64))); ((llbase, align), lllen) } _ => bug!("unexpected type {:?} in Subslice", base_ty) @@ -397,11 +399,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { /// nmatsakis: is this still necessary? Not sure. fn prepare_index(&mut self, bcx: &Builder<'a, 'tcx>, llindex: ValueRef) -> ValueRef { let index_size = machine::llbitsize_of_real(bcx.ccx, common::val_ty(llindex)); - let int_size = machine::llbitsize_of_real(bcx.ccx, bcx.ccx.int_type()); + let int_size = machine::llbitsize_of_real(bcx.ccx, bcx.ccx.isize_ty()); if index_size < int_size { - bcx.zext(llindex, bcx.ccx.int_type()) + bcx.zext(llindex, bcx.ccx.isize_ty()) } else if index_size > int_size { - bcx.trunc(llindex, bcx.ccx.int_type()) + bcx.trunc(llindex, bcx.ccx.isize_ty()) } else { llindex } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 34dec57543a2b..20ed4ab50a00f 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -19,8 +19,7 @@ use rustc::middle::lang_items::ExchangeMallocFnLangItem; use base; use builder::Builder; use callee; -use common::{self, val_ty, C_bool, C_null, C_uint}; -use common::{C_integral, C_i32}; +use common::{self, val_ty, C_bool, C_i32, C_null, C_usize, C_uint}; use adt; use machine; use monomorphize; @@ -92,7 +91,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx } - mir::Rvalue::Repeat(ref elem, ref count) => { + mir::Rvalue::Repeat(ref elem, count) => { let dest_ty = dest.ty.to_ty(bcx.tcx()); // No need to inizialize memory of a zero-sized slice @@ -101,8 +100,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } let tr_elem = self.trans_operand(&bcx, elem); - let size = count.as_u64(bcx.tcx().sess.target.uint_type); - let size = C_uint(bcx.ccx, size); + let size = count.as_u64(); + let size = C_usize(bcx.ccx, size); let base = base::get_dataptr(&bcx, dest.llval); let align = dest.alignment.to_align(); @@ -113,7 +112,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let align = C_i32(bcx.ccx, align as i32); let ty = type_of::type_of(bcx.ccx, dest_ty); let size = machine::llsize_of(bcx.ccx, ty); - let fill = C_integral(Type::i8(bcx.ccx), 0, false); + let fill = C_uint(Type::i8(bcx.ccx), 0); base::call_memset(&bcx, base, fill, size, align, false); return bcx; } @@ -301,7 +300,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { base::call_assume(&bcx, bcx.icmp( llvm::IntULE, llval, - C_integral(common::val_ty(llval), max, false) + C_uint(common::val_ty(llval), max) )); } @@ -464,7 +463,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => { assert!(bcx.ccx.shared().type_is_sized(ty)); - let val = C_uint(bcx.ccx, bcx.ccx.size_of(ty)); + let val = C_usize(bcx.ccx, bcx.ccx.size_of(ty)); let tcx = bcx.tcx(); (bcx, OperandRef { val: OperandValue::Immediate(val), @@ -477,7 +476,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let llty = type_of::type_of(bcx.ccx, content_ty); let llsize = machine::llsize_of(bcx.ccx, llty); let align = bcx.ccx.align_of(content_ty); - let llalign = C_uint(bcx.ccx, align); + let llalign = C_usize(bcx.ccx, align as u64); let llty_ptr = llty.ptr_to(); let box_ty = bcx.tcx().mk_box(content_ty); @@ -522,7 +521,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { if let LocalRef::Operand(Some(op)) = self.locals[index] { if common::type_is_zero_size(bcx.ccx, op.ty) { if let ty::TyArray(_, n) = op.ty.sty { - return common::C_uint(bcx.ccx, n); + let n = n.val.to_const_int().unwrap().to_u64().unwrap(); + return common::C_usize(bcx.ccx, n); } } } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 672fa32aa8591..1f27eb9fcb309 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -446,7 +446,8 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { ty::TyArray(inner_type, len) => { output.push('['); self.push_type_name(inner_type, output); - write!(output, "; {}", len).unwrap(); + write!(output, "; {}", + len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap(); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs index de4d217c73534..da4a4e55a67f4 100644 --- a/src/librustc_trans/tvec.rs +++ b/src/librustc_trans/tvec.rs @@ -34,7 +34,7 @@ pub fn slice_for_each<'a, 'tcx, F>( let next_bcx = bcx.build_sibling_block("slice_loop_next"); let start = if zst { - C_uint(bcx.ccx, 0usize) + C_usize(bcx.ccx, 1) } else { data_ptr }; @@ -46,7 +46,7 @@ pub fn slice_for_each<'a, 'tcx, F>( let keep_going = header_bcx.icmp(llvm::IntNE, current, end); header_bcx.cond_br(keep_going, body_bcx.llbb(), next_bcx.llbb()); - let next = add(&body_bcx, current, C_uint(bcx.ccx, 1usize)); + let next = add(&body_bcx, current, C_usize(bcx.ccx, 1)); f(&body_bcx, if zst { data_ptr } else { current }, header_bcx.llbb()); header_bcx.add_incoming_to_phi(current, next, body_bcx.llbb()); next_bcx diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index b8a8068d36af7..e5e532703d7d0 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -131,7 +131,7 @@ impl Type { Type::i8_llcx(llcx).ptr_to() } - pub fn int(ccx: &CrateContext) -> Type { + pub fn isize(ccx: &CrateContext) -> Type { match &ccx.tcx().sess.target.target.target_pointer_width[..] { "16" => Type::i16(ccx), "32" => Type::i32(ccx), @@ -142,7 +142,7 @@ impl Type { pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type { match t { - ast::IntTy::Is => ccx.int_type(), + ast::IntTy::Is => ccx.isize_ty(), ast::IntTy::I8 => Type::i8(ccx), ast::IntTy::I16 => Type::i16(ccx), ast::IntTy::I32 => Type::i32(ccx), @@ -153,7 +153,7 @@ impl Type { pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type { match t { - ast::UintTy::Us => ccx.int_type(), + ast::UintTy::Us => ccx.isize_ty(), ast::UintTy::U8 => Type::i8(ccx), ast::UintTy::U16 => Type::i16(ccx), ast::UintTy::U32 => Type::i32(ccx), @@ -207,7 +207,7 @@ impl Type { pub fn vec(ccx: &CrateContext, ty: &Type) -> Type { Type::struct_(ccx, - &[Type::array(ty, 0), Type::int(ccx)], + &[Type::array(ty, 0), Type::isize(ccx)], false) } diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 38c49833e0d75..992c74b9020c3 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -148,8 +148,8 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> } ty::TyArray(ty, size) => { - let size = size as u64; let llty = in_memory_type_of(cx, ty); + let size = size.val.to_const_int().unwrap().to_u64().unwrap(); Type::array(&llty, size) } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 2583d18652dc5..8f8663385b020 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -12,7 +12,7 @@ //! representation. The main routine here is `ast_ty_to_ty()`: each use //! is parameterized by an instance of `AstConv`. -use rustc::middle::const_val::eval_length; +use rustc::middle::const_val::ConstVal; use rustc_data_structures::accumulate_vec::AccumulateVec; use hir; use hir::def::Def; @@ -1082,11 +1082,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0 } hir::TyArray(ref ty, length) => { - if let Ok(length) = eval_length(tcx, length, "array length") { - tcx.mk_array(self.ast_ty_to_ty(&ty), length) - } else { - self.tcx().types.err - } + let length_def_id = tcx.hir.body_owner_def_id(length); + let substs = Substs::identity_for_item(tcx, length_def_id); + let length = tcx.mk_const(ty::Const { + val: ConstVal::Unevaluated(length_def_id, substs), + ty: tcx.types.usize + }); + let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length)); + self.normalize_ty(ast_ty.span, array_ty) } hir::TyTypeof(ref _e) => { struct_span_err!(tcx.sess, ast_ty.span, E0516, diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index cc84f73a42c80..cbf58209d056a 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -264,7 +264,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expected_ty = self.structurally_resolved_type(pat.span, expected); let (inner_ty, slice_ty) = match expected_ty.sty { ty::TyArray(inner_ty, size) => { - let min_len = before.len() + after.len(); + let size = size.val.to_const_int().unwrap().to_u64().unwrap(); + let min_len = before.len() as u64 + after.len() as u64; if slice.is_none() { if min_len != size { struct_span_err!( diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index aa2b9c1e03815..07159770d5ba2 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -192,6 +192,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::Predicate::TypeOutlives(..) => None, ty::Predicate::WellFormed(..) => None, ty::Predicate::ObjectSafe(..) => None, + ty::Predicate::ConstEvaluatable(..) => None, // NB: This predicate is created by breaking down a // `ClosureType: FnFoo()` predicate, where diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 6fee7e58633fc..fa8d3b9bcc1cb 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -360,7 +360,7 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match name["simd_shuffle".len()..].parse() { Ok(n) => { let params = vec![param(0), param(0), - tcx.mk_ty(ty::TyArray(tcx.types.u32, n))]; + tcx.mk_array(tcx.types.u32, n)]; (2, params, param(1)) } Err(_) => { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 3771d330f6dd3..7b94781832512 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -590,7 +590,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) => None, + ty::Predicate::TypeOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => None, } }) .collect(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 19879ff8b150f..ae2430990ba57 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -128,7 +128,6 @@ use rustc::hir::map::Node; use rustc::hir::{self, PatKind}; use rustc::middle::lang_items; use rustc_back::slice; -use rustc::middle::const_val::eval_length; use rustc_const_math::ConstInt; mod autoderef; @@ -2636,7 +2635,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ast::LitKind::Str(..) => tcx.mk_static_str(), ast::LitKind::ByteStr(ref v) => { tcx.mk_imm_ref(tcx.types.re_static, - tcx.mk_array(tcx.types.u8, v.len())) + tcx.mk_array(tcx.types.u8, v.len() as u64)) } ast::LitKind::Byte(_) => tcx.types.u8, ast::LitKind::Char(_) => tcx.types.char, @@ -3895,11 +3894,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span)) }; - tcx.mk_array(element_ty, args.len()) + tcx.mk_array(element_ty, args.len() as u64) } hir::ExprRepeat(ref element, count) => { - let count = eval_length(self.tcx, count, "repeat count") - .unwrap_or(0); + let count_def_id = tcx.hir.body_owner_def_id(count); + let param_env = ty::ParamEnv::empty(traits::Reveal::UserFacing); + let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id); + let count = tcx.const_eval(param_env.and((count_def_id, substs))); + + if let Err(ref err) = count { + err.report(tcx, tcx.def_span(count_def_id), "constant expression"); + } let uty = match expected { ExpectHasType(uty) => { @@ -3923,17 +3928,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - if count > 1 { - // For [foo, ..n] where n > 1, `foo` must have - // Copy type: - let lang_item = self.tcx.require_lang_item(lang_items::CopyTraitLangItem); - self.require_type_meets(t, expr.span, traits::RepeatVec, lang_item); + if let Ok(count) = count { + let zero_or_one = count.val.to_const_int().and_then(|count| { + count.to_u64().map(|count| count <= 1) + }).unwrap_or(false); + if !zero_or_one { + // For [foo, ..n] where n > 1, `foo` must have + // Copy type: + let lang_item = self.tcx.require_lang_item(lang_items::CopyTraitLangItem); + self.require_type_meets(t, expr.span, traits::RepeatVec, lang_item); + } } if element_ty.references_error() { tcx.types.err + } else if let Ok(count) = count { + tcx.mk_ty(ty::TyArray(t, count)) } else { - tcx.mk_array(t, count) + tcx.types.err } } hir::ExprTup(ref elts) => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index d475c37ed8c94..609af638e97c6 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -511,7 +511,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Subtype(..) | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::ObjectSafe(..) => + ty::Predicate::ObjectSafe(..) | + ty::Predicate::ConstEvaluatable(..) => vec![], ty::Predicate::WellFormed(subty) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e4ca0f82ea1a0..1735ec7cc698c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -572,7 +572,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } match result { - Ok(ConstVal::Integral(x)) => Some(x), + Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => Some(x), _ => None } } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 88a0d3ad4ac1e..ce3bf896256ec 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -27,11 +27,13 @@ use syntax::ptr::P; use syntax::symbol::keywords; use syntax_pos::{self, DUMMY_SP, Pos}; +use rustc::middle::const_val::ConstVal; use rustc::middle::privacy::AccessLevels; use rustc::middle::resolve_lifetime as rl; use rustc::middle::lang_items; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc::traits::Reveal; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind}; use rustc::middle::stability; @@ -40,6 +42,7 @@ use rustc_typeck::hir_ty_to_ty; use rustc::hir; +use rustc_const_math::ConstInt; use std::{mem, slice, vec}; use std::path::PathBuf; use std::rc::Rc; @@ -934,6 +937,7 @@ impl<'a> Clean for ty::Predicate<'a> { Predicate::WellFormed(_) => panic!("not user writable"), Predicate::ObjectSafe(_) => panic!("not user writable"), Predicate::ClosureKind(..) => panic!("not user writable"), + Predicate::ConstEvaluatable(..) => panic!("not user writable"), } } } @@ -1555,7 +1559,7 @@ pub enum Type { BareFunction(Box), Tuple(Vec), Slice(Box), - Array(Box, usize), + Array(Box, String), Never, Unique(Box), RawPointer(Mutability, Box), @@ -1782,9 +1786,16 @@ impl Clean for hir::Ty { type_: box m.ty.clean(cx)} } TySlice(ref ty) => Slice(box ty.clean(cx)), - TyArray(ref ty, length) => { - use rustc::middle::const_val::eval_length; - let n = eval_length(cx.tcx, length, "array length").unwrap(); + TyArray(ref ty, n) => { + let def_id = cx.tcx.hir.body_owner_def_id(n); + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + let substs = Substs::identity_for_item(cx.tcx, def_id); + let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap(); + let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { + n.to_string() + } else { + format!("{:?}", n) + }; Array(box ty.clean(cx), n) }, TyTup(ref tys) => Tuple(tys.clean(cx)), @@ -1895,7 +1906,14 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyFloat(float_ty) => Primitive(float_ty.into()), ty::TyStr => Primitive(PrimitiveType::Str), ty::TySlice(ty) => Slice(box ty.clean(cx)), - ty::TyArray(ty, n) => Array(box ty.clean(cx), n), + ty::TyArray(ty, n) => { + let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val { + n.to_string() + } else { + format!("{:?}", n) + }; + Array(box ty.clean(cx), n) + } ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)), ty::TyRef(r, mt) => BorrowedRef { lifetime: r.clean(cx), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 10a3878073e97..6303fd662bf2b 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -633,7 +633,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt: fmt::Display::fmt(t, f)?; primitive_link(f, PrimitiveType::Slice, "]") } - clean::Array(ref t, n) => { + clean::Array(ref t, ref n) => { primitive_link(f, PrimitiveType::Array, "[")?; fmt::Display::fmt(t, f)?; primitive_link(f, PrimitiveType::Array, &format!("; {}]", n)) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d04b6d3417a5a..9563ccfcc65fd 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -32,6 +32,7 @@ extern crate html_diff; extern crate libc; extern crate rustc; extern crate rustc_data_structures; +extern crate rustc_const_math; extern crate rustc_trans; extern crate rustc_driver; extern crate rustc_resolve; diff --git a/src/test/compile-fail/const-block-non-item-statement-3.rs b/src/test/compile-fail/const-block-non-item-statement-3.rs new file mode 100644 index 0000000000000..707037911015c --- /dev/null +++ b/src/test/compile-fail/const-block-non-item-statement-3.rs @@ -0,0 +1,15 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type Array = [u32; { let x = 2; 5 }]; +//~^ ERROR: blocks in constants are limited to items and tail expressions +//~^^ ERROR: blocks in constants are limited to items and tail expressions + +pub fn main() {} diff --git a/src/test/compile-fail/const-block-non-item-statement.rs b/src/test/compile-fail/const-block-non-item-statement.rs index bdc69c937c637..802e660b9048d 100644 --- a/src/test/compile-fail/const-block-non-item-statement.rs +++ b/src/test/compile-fail/const-block-non-item-statement.rs @@ -14,8 +14,4 @@ enum Foo { //~^^ ERROR: blocks in constants are limited to items and tail expressions } -type Array = [u32; { let x = 2; 5 }]; -//~^ ERROR: blocks in constants are limited to items and tail expressions -//~^^ ERROR: blocks in constants are limited to items and tail expressions - pub fn main() {} diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs index dd0f058f2c95c..385daef44dfe5 100644 --- a/src/test/compile-fail/const-fn-error.rs +++ b/src/test/compile-fail/const-fn-error.rs @@ -23,5 +23,5 @@ const fn f(x: usize) -> usize { #[allow(unused_variables)] fn main() { - let a : [i32; f(X)]; //~ NOTE for array length here + let a : [i32; f(X)]; //~ NOTE for constant expression here } diff --git a/src/test/compile-fail/const-len-underflow-separate-spans.rs b/src/test/compile-fail/const-len-underflow-separate-spans.rs index c01bb82676304..3c84810554214 100644 --- a/src/test/compile-fail/const-len-underflow-separate-spans.rs +++ b/src/test/compile-fail/const-len-underflow-separate-spans.rs @@ -20,5 +20,5 @@ const LEN: usize = ONE - TWO; fn main() { let a: [i8; LEN] = unimplemented!(); - //~^ NOTE for array length here + //~^ NOTE for constant expression here } diff --git a/src/test/compile-fail/const-size_of-cycle.rs b/src/test/compile-fail/const-size_of-cycle.rs index a58be33b1ae6c..cbeafdfe6acc9 100644 --- a/src/test/compile-fail/const-size_of-cycle.rs +++ b/src/test/compile-fail/const-size_of-cycle.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// error-pattern: unsupported cyclic reference between types/traits detected + #![feature(const_fn)] struct Foo { bytes: [u8; std::mem::size_of::()] - //~^ ERROR unsupported cyclic reference between types/traits detected } fn main() {} diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs index c78e1f7f53095..97456c2da87fe 100644 --- a/src/test/compile-fail/issue-22933-2.rs +++ b/src/test/compile-fail/issue-22933-2.rs @@ -15,7 +15,4 @@ enum Delicious { //~^ ERROR no associated item named `PIE` found for type `Delicious` } -const FOO: [u32; u8::MIN as usize] = []; -//~^ ERROR no associated item named `MIN` found for type `u8` - fn main() {} diff --git a/src/test/compile-fail/issue-22933-3.rs b/src/test/compile-fail/issue-22933-3.rs new file mode 100644 index 0000000000000..62adae41adfc8 --- /dev/null +++ b/src/test/compile-fail/issue-22933-3.rs @@ -0,0 +1,14 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const FOO: [u32; u8::MIN as usize] = []; +//~^ ERROR no associated item named `MIN` found for type `u8` + +fn main() {} diff --git a/src/test/compile-fail/issue-39559.rs b/src/test/compile-fail/issue-39559.rs index 8bc1cc7bd1ace..2da21fb14bd3c 100644 --- a/src/test/compile-fail/issue-39559.rs +++ b/src/test/compile-fail/issue-39559.rs @@ -21,8 +21,9 @@ impl Dim for Dim3 { } pub struct Vector { - entries: [T; D::dim()] + entries: [T; D::dim()], //~^ ERROR no function or associated item named `dim` found for type `D` in the current scope + _dummy: D, } fn main() {} diff --git a/src/test/ui/issue-38875/issue_38875.stderr b/src/test/ui/issue-38875/issue_38875.stderr index 10bb61ee22a61..d49741f25b9f5 100644 --- a/src/test/ui/issue-38875/issue_38875.stderr +++ b/src/test/ui/issue-38875/issue_38875.stderr @@ -4,7 +4,7 @@ error[E0080]: constant evaluation error 11 | pub const FOO: usize = *&0; | ^^^ unimplemented constant expression: deref operation | -note: for repeat count here +note: for constant expression here --> $DIR/issue_38875.rs:16:22 | 16 | let test_x = [0; issue_38875_b::FOO];