]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #58670 - saleemjaffer:refactor_typecast_check_kinds, r=oli-obk
authorMazdak Farrokhzad <twingoow@gmail.com>
Sat, 9 Mar 2019 16:18:17 +0000 (17:18 +0100)
committerGitHub <noreply@github.com>
Sat, 9 Mar 2019 16:18:17 +0000 (17:18 +0100)
fixes rust-lang#52482

1  2 
src/librustc/ty/context.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_passes/rvalue_promotion.rs
src/librustc_typeck/check/writeback.rs

index 274721b45cba02ca5179ca7ca4c2f8b1b232dab7,621a596118371407d961059ca636d921e27b0c3c..04d503d993db773e160b64cf9c8e8117bb0e3af4
@@@ -21,8 -21,8 +21,8 @@@ use crate::middle::lang_items
  use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
  use crate::middle::stability;
  use crate::mir::{self, Mir, interpret, ProjectionKind};
 -use crate::mir::interpret::Allocation;
 -use crate::ty::subst::{Kind, InternalSubsts, Subst, SubstsRef};
 +use crate::mir::interpret::{ConstValue, Allocation};
 +use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, Subst};
  use crate::ty::ReprOptions;
  use crate::traits;
  use crate::traits::{Clause, Clauses, GoalKind, Goal, Goals};
@@@ -31,9 -31,8 +31,9 @@@ use crate::ty::{TyS, TyKind, List}
  use crate::ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const, LazyConst};
  use crate::ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate};
  use crate::ty::RegionKind;
 -use crate::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
 +use crate::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid, ConstVid};
  use crate::ty::TyKind::*;
 +use crate::ty::{InferConst, ParamConst};
  use crate::ty::GenericParamDefKind;
  use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx};
  use crate::ty::query;
@@@ -41,7 -40,7 +41,7 @@@ use crate::ty::steal::Steal
  use crate::ty::subst::{UserSubsts, UnpackedKind};
  use crate::ty::{BoundVar, BindingMode};
  use crate::ty::CanonicalPolyFnSig;
- use crate::util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap};
+ use crate::util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap, ItemLocalSet};
  use crate::util::nodemap::{FxHashMap, FxHashSet};
  use errors::DiagnosticBuilder;
  use rustc_data_structures::interner::HashInterner;
@@@ -51,7 -50,7 +51,7 @@@ use rustc_data_structures::stable_hashe
                                             StableVec};
  use arena::{TypedArena, SyncDroplessArena};
  use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 -use rustc_data_structures::sync::{self, Lrc, Lock, WorkerLocal};
 +use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal};
  use std::any::Any;
  use std::borrow::Borrow;
  use std::cmp::Ordering;
@@@ -60,12 -59,13 +60,12 @@@ use std::hash::{Hash, Hasher}
  use std::fmt;
  use std::mem;
  use std::ops::{Deref, Bound};
 -use std::ptr;
  use std::iter;
  use std::sync::mpsc;
  use std::sync::Arc;
  use std::marker::PhantomData;
  use rustc_target::spec::abi;
 -use syntax::ast::{self, NodeId};
 +use syntax::ast;
  use syntax::attr;
  use syntax::source_map::MultiSpan;
  use syntax::edition::Edition;
@@@ -171,7 -171,7 +171,7 @@@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'t
  
                  // Make sure we don't end up with inference
                  // types/regions in the global interner
 -                if ptr::eq(local, global) {
 +                if ptr_eq(local, global) {
                      bug!("Attempted to intern `{:?}` which contains \
                          inference types/regions in the global type context",
                          &ty_struct);
@@@ -409,9 -409,9 +409,9 @@@ pub struct TypeckTables<'tcx> 
      /// MIR construction and hence is not serialized to metadata.
      fru_field_types: ItemLocalMap<Vec<Ty<'tcx>>>,
  
-     /// Maps a cast expression to its kind. This is keyed on the
-     /// *from* expression of the cast, not the cast itself.
-     cast_kinds: ItemLocalMap<ty::cast::CastKind>,
+     /// For every coercion cast we add the HIR node ID of the cast
+     /// expression to this set.
+     coercion_casts: ItemLocalSet,
  
      /// Set of trait imports actually used in the method resolution.
      /// This is used for warning unused imports. During type
@@@ -456,7 -456,7 +456,7 @@@ impl<'tcx> TypeckTables<'tcx> 
              closure_kind_origins: Default::default(),
              liberated_fn_sigs: Default::default(),
              fru_field_types: Default::default(),
-             cast_kinds: Default::default(),
+             coercion_casts: Default::default(),
              used_trait_imports: Lrc::new(Default::default()),
              tainted_by_errors: false,
              free_region_map: Default::default(),
          }
      }
  
-     pub fn cast_kinds(&self) -> LocalTableInContext<'_, ty::cast::CastKind> {
-         LocalTableInContext {
-             local_id_root: self.local_id_root,
-             data: &self.cast_kinds
-         }
+     pub fn is_coercion_cast(&self, hir_id: hir::HirId) -> bool {
+         validate_hir_id_for_typeck_tables(self.local_id_root, hir_id, true);
+         self.coercion_casts.contains(&hir_id.local_id)
      }
  
-     pub fn cast_kinds_mut(&mut self) -> LocalTableInContextMut<'_, ty::cast::CastKind> {
-         LocalTableInContextMut {
-             local_id_root: self.local_id_root,
-             data: &mut self.cast_kinds
-         }
+     pub fn set_coercion_cast(&mut self, id: ItemLocalId) {
+         self.coercion_casts.insert(id);
+     }
+     pub fn coercion_casts(&self) -> &ItemLocalSet {
+         &self.coercion_casts
      }
  }
  
  impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
              ref liberated_fn_sigs,
              ref fru_field_types,
  
-             ref cast_kinds,
+             ref coercion_casts,
  
              ref used_trait_imports,
              tainted_by_errors,
              closure_kind_origins.hash_stable(hcx, hasher);
              liberated_fn_sigs.hash_stable(hcx, hasher);
              fru_field_types.hash_stable(hcx, hasher);
-             cast_kinds.hash_stable(hcx, hasher);
+             coercion_casts.hash_stable(hcx, hasher);
              used_trait_imports.hash_stable(hcx, hasher);
              tainted_by_errors.hash_stable(hcx, hasher);
              free_region_map.hash_stable(hcx, hasher);
@@@ -873,18 -873,6 +873,18 @@@ impl CanonicalUserType<'gcx> 
                              }
                              _ => false,
                          },
 +
 +                        UnpackedKind::Const(ct) => match ct {
 +                            ty::LazyConst::Evaluated(ty::Const {
 +                                val: ConstValue::Infer(InferConst::Canonical(debruijn, b)),
 +                                ..
 +                            }) => {
 +                                // We only allow a `ty::INNERMOST` index in substitutions.
 +                                assert_eq!(*debruijn, ty::INNERMOST);
 +                                cvar == *b
 +                            }
 +                            _ => false,
 +                        },
                      }
                  })
              },
@@@ -1175,7 -1163,7 +1175,7 @@@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, '
  
      /// Returns `true` if self is the same as self.global_tcx().
      fn is_global(self) -> bool {
 -        ptr::eq(self.interners, &self.global_interners)
 +        ptr_eq(self.interners, &self.global_interners)
      }
  
      /// Creates a type context and call the closure with a `TyCtxt` reference
  
          let gcx = arenas.global_ctxt.as_ref().unwrap();
  
 -        sync::assert_send_val(&gcx);
 -
          let r = tls::enter_global(gcx, f);
  
          gcx.queries.record_computed_queries(s);
              _ => return None, // not a free region
          };
  
 -        let node_id = self.hir()
 -            .as_local_node_id(suitable_region_binding_scope)
 +        let hir_id = self.hir()
 +            .as_local_hir_id(suitable_region_binding_scope)
              .unwrap();
 -        let is_impl_item = match self.hir().find(node_id) {
 +        let is_impl_item = match self.hir().find_by_hir_id(hir_id) {
              Some(Node::Item(..)) | Some(Node::TraitItem(..)) => false,
              Some(Node::ImplItem(..)) => {
                  self.is_bound_region_in_impl_item(suitable_region_binding_scope)
          scope_def_id: DefId,
      ) -> Option<Ty<'tcx>> {
          // HACK: `type_of_def_id()` will fail on these (#55796), so return None
 -        let node_id = self.hir().as_local_node_id(scope_def_id).unwrap();
 -        match self.hir().get(node_id) {
 +        let hir_id = self.hir().as_local_hir_id(scope_def_id).unwrap();
 +        match self.hir().get_by_hir_id(hir_id) {
              Node::Item(item) => {
                  match item.node {
                      ItemKind::Fn(..) => { /* type_of_def_id() will work */ }
@@@ -1829,11 -1819,12 +1829,11 @@@ impl<'a, 'tcx> Lift<'tcx> for &'a mir::
  }
  
  pub mod tls {
 -    use super::{GlobalCtxt, TyCtxt};
 +    use super::{GlobalCtxt, TyCtxt, ptr_eq};
  
      use std::fmt;
      use std::mem;
      use std::marker::PhantomData;
 -    use std::ptr;
      use syntax_pos;
      use crate::ty::query;
      use errors::{Diagnostic, TRACK_DIAGNOSTICS};
          rayon_core::tlv::get()
      }
  
 -    /// A thread local variable which stores a pointer to the current ImplicitCtxt
      #[cfg(not(parallel_compiler))]
 -    thread_local!(static TLV: Cell<usize> = Cell::new(0));
 +    thread_local! {
 +        /// A thread local variable which stores a pointer to the current ImplicitCtxt.
 +        static TLV: Cell<usize> = Cell::new(0);
 +    }
  
      /// Sets TLV to `value` during the call to `f`.
      /// It is restored to its previous value after.
          })
      }
  
 -    /// Stores a pointer to the GlobalCtxt if one is available.
 -    /// This is used to access the GlobalCtxt in the deadlock handler
 -    /// given to Rayon.
 -    scoped_thread_local!(pub static GCX_PTR: Lock<usize>);
 +    scoped_thread_local! {
 +        /// Stores a pointer to the GlobalCtxt if one is available.
 +        /// This is used to access the GlobalCtxt in the deadlock handler given to Rayon.
 +        pub static GCX_PTR: Lock<usize>
 +    }
  
      /// Creates a TyCtxt and ImplicitCtxt based on the GCX_PTR thread local.
      /// This is used in the deadlock handler.
      {
          with_context(|context| {
              unsafe {
 -                assert!(ptr::eq(context.tcx.gcx, tcx.gcx));
 +                assert!(ptr_eq(context.tcx.gcx, tcx.gcx));
                  let context: &ImplicitCtxt<'_, '_, '_> = mem::transmute(context);
                  f(context)
              }
      {
          with_context(|context| {
              unsafe {
 -                assert!(ptr::eq(context.tcx.gcx, tcx.gcx));
 -                assert!(ptr::eq(context.tcx.interners, tcx.interners));
 +                assert!(ptr_eq(context.tcx.gcx, tcx.gcx));
 +                assert!(ptr_eq(context.tcx.interners, tcx.interners));
                  let context: &ImplicitCtxt<'_, '_, '_> = mem::transmute(context);
                  f(context)
              }
@@@ -2136,19 -2124,15 +2136,19 @@@ macro_rules! sty_debug_print 
              #[derive(Copy, Clone)]
              struct DebugStat {
                  total: usize,
 -                region_infer: usize,
 +                lt_infer: usize,
                  ty_infer: usize,
 -                both_infer: usize,
 +                ct_infer: usize,
 +                all_infer: usize,
              }
  
              pub fn go(tcx: TyCtxt<'_, '_, '_>) {
                  let mut total = DebugStat {
                      total: 0,
 -                    region_infer: 0, ty_infer: 0, both_infer: 0,
 +                    lt_infer: 0,
 +                    ty_infer: 0,
 +                    ct_infer: 0,
 +                    all_infer: 0,
                  };
                  $(let mut $variant = total;)*
  
                          ty::Error => /* unimportant */ continue,
                          $(ty::$variant(..) => &mut $variant,)*
                      };
 -                    let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
 +                    let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
                      let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
 +                    let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER);
  
                      variant.total += 1;
                      total.total += 1;
 -                    if region { total.region_infer += 1; variant.region_infer += 1 }
 +                    if lt { total.lt_infer += 1; variant.lt_infer += 1 }
                      if ty { total.ty_infer += 1; variant.ty_infer += 1 }
 -                    if region && ty { total.both_infer += 1; variant.both_infer += 1 }
 +                    if ct { total.ct_infer += 1; variant.ct_infer += 1 }
 +                    if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 }
                  }
 -                println!("Ty interner             total           ty region  both");
 +                println!("Ty interner             total           ty lt ct all");
                  $(println!("    {:18}: {uses:6} {usespc:4.1}%, \
 -                            {ty:4.1}% {region:5.1}% {both:4.1}%",
 -                           stringify!($variant),
 -                           uses = $variant.total,
 -                           usespc = $variant.total as f64 * 100.0 / total.total as f64,
 -                           ty = $variant.ty_infer as f64 * 100.0  / total.total as f64,
 -                           region = $variant.region_infer as f64 * 100.0  / total.total as f64,
 -                           both = $variant.both_infer as f64 * 100.0  / total.total as f64);
 -                  )*
 +                            {ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%",
 +                    stringify!($variant),
 +                    uses = $variant.total,
 +                    usespc = $variant.total as f64 * 100.0 / total.total as f64,
 +                    ty = $variant.ty_infer as f64 * 100.0  / total.total as f64,
 +                    lt = $variant.lt_infer as f64 * 100.0  / total.total as f64,
 +                    ct = $variant.ct_infer as f64 * 100.0  / total.total as f64,
 +                    all = $variant.all_infer as f64 * 100.0  / total.total as f64);
 +                )*
                  println!("                  total {uses:6}        \
 -                          {ty:4.1}% {region:5.1}% {both:4.1}%",
 -                         uses = total.total,
 -                         ty = total.ty_infer as f64 * 100.0  / total.total as f64,
 -                         region = total.region_infer as f64 * 100.0  / total.total as f64,
 -                         both = total.both_infer as f64 * 100.0  / total.total as f64)
 +                          {ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%",
 +                    uses = total.total,
 +                    ty = total.ty_infer as f64 * 100.0  / total.total as f64,
 +                    lt = total.lt_infer as f64 * 100.0  / total.total as f64,
 +                    ct = total.ct_infer as f64 * 100.0  / total.total as f64,
 +                    all = total.all_infer as f64 * 100.0  / total.total as f64)
              }
          }
  
@@@ -2473,7 -2453,7 +2473,7 @@@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, '
              self.mk_fn_sig(
                  params_iter,
                  s.output(),
 -                s.variadic,
 +                s.c_variadic,
                  hir::Unsafety::Normal,
                  abi::Abi::Rust,
              )
          let adt_def = self.adt_def(def_id);
          let substs = InternalSubsts::for_item(self, def_id, |param, substs| {
              match param.kind {
 -                GenericParamDefKind::Lifetime => bug!(),
 +                GenericParamDefKind::Lifetime |
 +                GenericParamDefKind::Const => {
 +                    bug!()
 +                }
                  GenericParamDefKind::Type { has_default, .. } => {
                      if param.index == 0 {
                          ty.into()
      }
  
      #[inline]
 -    pub fn mk_var(self, v: TyVid) -> Ty<'tcx> {
 +    pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> {
          self.mk_infer(TyVar(v))
      }
  
 +    #[inline]
 +    pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> &'tcx LazyConst<'tcx> {
 +        self.mk_lazy_const(LazyConst::Evaluated(ty::Const {
 +            val: ConstValue::Infer(InferConst::Var(v)),
 +            ty,
 +        }))
 +    }
 +
      #[inline]
      pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> {
          self.mk_infer(IntVar(v))
          self.mk_ty(Param(ParamTy { idx: index, name: name }))
      }
  
 +    #[inline]
 +    pub fn mk_const_param(
 +        self,
 +        index: u32,
 +        name: InternedString,
 +        ty: Ty<'tcx>
 +    ) -> &'tcx LazyConst<'tcx> {
 +        self.mk_lazy_const(LazyConst::Evaluated(ty::Const {
 +            val: ConstValue::Param(ParamConst { index, name }),
 +            ty,
 +        }))
 +    }
 +
      #[inline]
      pub fn mk_self_type(self) -> Ty<'tcx> {
          self.mk_ty_param(0, keywords::SelfUpper.name().as_interned_str())
              GenericParamDefKind::Lifetime => {
                  self.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())).into()
              }
 -            GenericParamDefKind::Type {..} => self.mk_ty_param(param.index, param.name).into(),
 +            GenericParamDefKind::Type { .. } => self.mk_ty_param(param.index, param.name).into(),
 +            GenericParamDefKind::Const => {
 +                self.mk_const_param(param.index, param.name, self.type_of(param.def_id)).into()
 +            }
          }
      }
  
      pub fn mk_fn_sig<I>(self,
                          inputs: I,
                          output: I::Item,
 -                        variadic: bool,
 +                        c_variadic: bool,
                          unsafety: hir::Unsafety,
                          abi: abi::Abi)
          -> <I::Item as InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>>::Output
      {
          inputs.chain(iter::once(output)).intern_with(|xs| ty::FnSig {
              inputs_and_output: self.intern_type_list(xs),
 -            variadic, unsafety, abi
 +            c_variadic, unsafety, abi
          })
      }
  
          self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit()
      }
  
 -    pub fn lint_node<S: Into<MultiSpan>>(self,
 -                                         lint: &'static Lint,
 -                                         id: NodeId,
 -                                         span: S,
 -                                         msg: &str) {
 -        self.struct_span_lint_node(lint, id, span.into(), msg).emit()
 -    }
 -
      pub fn lint_hir_note<S: Into<MultiSpan>>(self,
                                               lint: &'static Lint,
                                               hir_id: HirId,
          err.emit()
      }
  
 -    pub fn lint_level_at_node(self, lint: &'static Lint, mut id: NodeId)
 +    pub fn lint_level_at_node(self, lint: &'static Lint, mut id: hir::HirId)
          -> (lint::Level, lint::LintSource)
      {
          // Right now we insert a `with_ignore` node in the dep graph here to
          self.dep_graph.with_ignore(|| {
              let sets = self.lint_levels(LOCAL_CRATE);
              loop {
 -                let hir_id = self.hir().definitions().node_to_hir_id(id);
 -                if let Some(pair) = sets.level_and_source(lint, hir_id, self.sess) {
 +                if let Some(pair) = sets.level_and_source(lint, id, self.sess) {
                      return pair
                  }
 -                let next = self.hir().get_parent_node(id);
 +                let next = self.hir().get_parent_node_by_hir_id(id);
                  if next == id {
                      bug!("lint traversal reached the root of the crate");
                  }
                                                      msg: &str)
          -> DiagnosticBuilder<'tcx>
      {
 -        let node_id = self.hir().hir_to_node_id(hir_id);
 -        let (level, src) = self.lint_level_at_node(lint, node_id);
 +        let (level, src) = self.lint_level_at_node(lint, hir_id);
          lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
      }
  
 -    pub fn struct_span_lint_node<S: Into<MultiSpan>>(self,
 -                                                     lint: &'static Lint,
 -                                                     id: NodeId,
 -                                                     span: S,
 -                                                     msg: &str)
 -        -> DiagnosticBuilder<'tcx>
 -    {
 -        let (level, src) = self.lint_level_at_node(lint, id);
 -        lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
 -    }
 -
 -    pub fn struct_lint_node(self, lint: &'static Lint, id: NodeId, msg: &str)
 +    pub fn struct_lint_node(self, lint: &'static Lint, id: HirId, msg: &str)
          -> DiagnosticBuilder<'tcx>
      {
          let (level, src) = self.lint_level_at_node(lint, id);
@@@ -3019,12 -2993,6 +3019,12 @@@ impl<T, R, E> InternIteratorElement<T, 
      }
  }
  
 +// We are comparing types with different invariant lifetimes, so `ptr::eq`
 +// won't work for us.
 +fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
 +    t as *const () == u as *const ()
 +}
 +
  pub fn provide(providers: &mut ty::query::Providers<'_>) {
      providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id).cloned();
      providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).cloned();
index 6af45957acf0908984dedbe30f6efa6c05655423,ff5f3018acc08f1c0af116e28a23a1bc21db08b7..ad0a22cc7827c9f3e2163ebc2cdd8d63d5ca7586
@@@ -5,10 -5,9 +5,9 @@@ use crate::hair::cx::to_ref::ToRef
  use crate::hair::util::UserAnnotatedTyHelpers;
  use rustc_data_structures::indexed_vec::Idx;
  use rustc::hir::def::{Def, CtorKind};
 -use rustc::mir::interpret::{GlobalId, ErrorHandled};
 +use rustc::mir::interpret::{GlobalId, ErrorHandled, ConstValue};
  use rustc::ty::{self, AdtKind, Ty};
  use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
- use rustc::ty::cast::CastKind as TyCastKind;
  use rustc::ty::subst::{InternalSubsts, SubstsRef};
  use rustc::hir;
  use rustc::hir::def_id::LocalDefId;
@@@ -89,7 -88,7 +88,7 @@@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx
              ExprKind::NeverToAny { source: expr.to_ref() }
          }
          Adjust::MutToConstPointer => {
 -            ExprKind::Cast { source: expr.to_ref() }
 +            ExprKind::MutToConstPointer { source: expr.to_ref() }
          }
          Adjust::Deref(None) => {
              // Adjust the span from the block, to the last expression of the
@@@ -530,7 -529,8 +529,7 @@@ fn make_mirror_unadjusted<'a, 'gcx, 'tc
                      span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
                  }
              };
 -            let expr_node_id = cx.tcx.hir().hir_to_node_id(expr.hir_id);
 -            let upvars = cx.tcx.with_freevars(expr_node_id, |freevars| {
 +            let upvars = cx.tcx.with_freevars(expr.hir_id, |freevars| {
                  freevars.iter()
                      .zip(substs.upvar_tys(def_id, cx.tcx))
                      .map(|(fv, ty)| capture_freevar(cx, expr, fv, ty))
  
          // Now comes the rote stuff:
          hir::ExprKind::Repeat(ref v, ref count) => {
 -            let def_id = cx.tcx.hir().local_def_id(count.id);
 +            let def_id = cx.tcx.hir().local_def_id_from_hir_id(count.hir_id);
              let substs = InternalSubsts::identity_for_item(cx.tcx.global_tcx(), def_id);
              let instance = ty::Instance::resolve(
                  cx.tcx.global_tcx(),
              match dest.target_id {
                  Ok(target_id) => ExprKind::Break {
                      label: region::Scope {
 -                        id: cx.tcx.hir().node_to_hir_id(target_id).local_id,
 +                        id: target_id.local_id,
                          data: region::ScopeData::Node
                      },
                      value: value.to_ref(),
              match dest.target_id {
                  Ok(loop_id) => ExprKind::Continue {
                      label: region::Scope {
 -                        id: cx.tcx.hir().node_to_hir_id(loop_id).local_id,
 +                        id: loop_id.local_id,
                          data: region::ScopeData::Node
                      },
                  },
  
              // Check to see if this cast is a "coercion cast", where the cast is actually done
              // using a coercion (or is a no-op).
-             let cast = if let Some(&TyCastKind::CoercionCast) =
-                 cx.tables()
-                 .cast_kinds()
-                 .get(source.hir_id)
-             {
+             let cast = if cx.tables().is_coercion_cast(source.hir_id) {
                  // Convert the lexpr to a vexpr.
                  ExprKind::Use { source: source.to_ref() }
              } else {
                  };
  
                  let source = if let Some((did, offset, var_ty)) = var {
 -                    let mk_const = |literal| Expr {
 +                    let mk_lazy_const = |literal| Expr {
                          temp_lifetime,
                          ty: var_ty,
                          span: expr.span,
                              user_ty: None
                          },
                      }.to_ref();
 -                    let offset = mk_const(ty::LazyConst::Evaluated(ty::Const::from_bits(
 +                    let offset = mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bits(
                          cx.tcx,
                          offset as u128,
                          cx.param_env.and(var_ty),
                              // in case we are offsetting from a computed discriminant
                              // and not the beginning of discriminants (which is always `0`)
                              let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
 -                            let lhs = mk_const(ty::LazyConst::Unevaluated(did, substs));
 +                            let lhs = mk_lazy_const(ty::LazyConst::Unevaluated(did, substs));
                              let bin = ExprKind::Binary {
                                  op: BinOp::Add,
                                  lhs,
@@@ -924,26 -920,7 +919,26 @@@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx
                  ))),
                  user_ty,
              }
 -        },
 +        }
 +
 +        Def::ConstParam(def_id) => {
 +            let node_id = cx.tcx.hir().as_local_node_id(def_id).unwrap();
 +            let item_id = cx.tcx.hir().get_parent_node(node_id);
 +            let item_def_id = cx.tcx.hir().local_def_id(item_id);
 +            let generics = cx.tcx.generics_of(item_def_id);
 +            let index = generics.param_def_id_to_index[&cx.tcx.hir().local_def_id(node_id)];
 +            let name = cx.tcx.hir().name(node_id).as_interned_str();
 +            let val = ConstValue::Param(ty::ParamConst::new(index, name));
 +            ExprKind::Literal {
 +                literal: cx.tcx.mk_lazy_const(
 +                    ty::LazyConst::Evaluated(ty::Const {
 +                        val,
 +                        ty: cx.tables().node_type(expr.hir_id),
 +                    })
 +                ),
 +                user_ty: None,
 +            }
 +        }
  
          Def::Const(def_id) |
          Def::AssociatedConst(def_id) => {
@@@ -992,7 -969,7 +987,7 @@@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mu
      let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
  
      match def {
 -        Def::Local(id) => ExprKind::VarRef { id },
 +        Def::Local(id) => ExprKind::VarRef { id: cx.tcx.hir().node_to_hir_id(id) },
  
          Def::Upvar(var_id, index, closure_expr_id) => {
              debug!("convert_var(upvar({:?}, {:?}, {:?}))",
index af01e38cb54317f0eb89800d9e18b0dd2e68f033,b0dd72030cc51c547dd691f2eb52fe637333af64..9de022a4021a55c0733e7128b3c85cd758b2060f
@@@ -14,7 -14,7 +14,7 @@@
  // - It's not possible to take the address of a static item with unsafe interior. This is enforced
  // by borrowck::gather_loans
  
- use rustc::ty::cast::CastKind;
+ use rustc::ty::cast::CastTy;
  use rustc::hir::def::{Def, CtorKind};
  use rustc::hir::def_id::DefId;
  use rustc::middle::expr_use_visitor as euv;
@@@ -26,6 -26,7 +26,6 @@@ use rustc::ty::subst::{InternalSubsts, 
  use rustc::util::nodemap::{ItemLocalSet, HirIdSet};
  use rustc::hir;
  use rustc_data_structures::sync::Lrc;
 -use syntax::ast;
  use syntax_pos::{Span, DUMMY_SP};
  use log::debug;
  use Promotability::*;
@@@ -52,9 -53,9 +52,9 @@@ fn const_is_rvalue_promotable_to_static
  {
      assert!(def_id.is_local());
  
 -    let node_id = tcx.hir().as_local_node_id(def_id)
 +    let hir_id = tcx.hir().as_local_hir_id(def_id)
          .expect("rvalue_promotable_map invoked with non-local def-id");
 -    let body_id = tcx.hir().body_owned_by(node_id);
 +    let body_id = tcx.hir().body_owned_by(hir_id);
      tcx.rvalue_promotable_map(def_id).contains(&body_id.hir_id.local_id)
  }
  
@@@ -79,9 -80,9 +79,9 @@@ fn rvalue_promotable_map<'a, 'tcx>(tcx
      };
  
      // `def_id` should be a `Body` owner
 -    let node_id = tcx.hir().as_local_node_id(def_id)
 +    let hir_id = tcx.hir().as_local_hir_id(def_id)
          .expect("rvalue_promotable_map invoked with non-local def-id");
 -    let body_id = tcx.hir().body_owned_by(node_id);
 +    let body_id = tcx.hir().body_owned_by(hir_id);
      let _ = visitor.check_nested_body(body_id);
  
      Lrc::new(visitor.result)
@@@ -318,15 -319,12 +318,12 @@@ fn check_expr_kind<'a, 'tcx>
          hir::ExprKind::Cast(ref from, _) => {
              let expr_promotability = v.check_expr(from);
              debug!("Checking const cast(id={})", from.hir_id);
-             match v.tables.cast_kinds().get(from.hir_id) {
-                 None => {
-                     v.tcx.sess.delay_span_bug(e.span, "no kind for cast");
-                     NotPromotable
-                 },
-                 Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
-                     NotPromotable
-                 }
-                 _ => expr_promotability
+             let cast_in = CastTy::from_ty(v.tables.expr_ty(from));
+             let cast_out = CastTy::from_ty(v.tables.expr_ty(e));
+             match (cast_in, cast_out) {
+                 (Some(CastTy::FnPtr), Some(CastTy::Int(_))) |
+                 (Some(CastTy::Ptr(_)), Some(CastTy::Int(_))) => NotPromotable,
+                 (_, _) => expr_promotability
              }
          }
          hir::ExprKind::Path(ref qpath) => {
          hir::ExprKind::Closure(_capture_clause, ref _box_fn_decl,
                                 body_id, _span, _option_generator_movability) => {
              let nested_body_promotable = v.check_nested_body(body_id);
 -            let node_id = v.tcx.hir().hir_to_node_id(e.hir_id);
              // Paths in constant contexts cannot refer to local variables,
              // as there are none, and thus closures can't have upvars there.
 -            if v.tcx.with_freevars(node_id, |fv| !fv.is_empty()) {
 +            if v.tcx.with_freevars(e.hir_id, |fv| !fv.is_empty()) {
                  NotPromotable
              } else {
                  nested_body_promotable
@@@ -675,7 -674,7 +672,7 @@@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx
          }
      }
  
 -    fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) {}
 +    fn decl_without_init(&mut self, _id: hir::HirId, _span: Span) {}
      fn mutate(&mut self,
                _assignment_id: hir::HirId,
                _assignment_span: Span,
index 5981d9bb66bfca81017017746321923d38667a79,73eadf6f275dd387ceec41de6e19bcee64827422..d001545d1d9152e345a6a9e5e2c9de4c7fb89b09
@@@ -50,7 -50,7 +50,7 @@@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, '
          wbcx.visit_liberated_fn_sigs();
          wbcx.visit_fru_field_types();
          wbcx.visit_opaque_types(body.value.span);
-         wbcx.visit_cast_types();
+         wbcx.visit_coercion_casts();
          wbcx.visit_free_region_map();
          wbcx.visit_user_provided_tys();
          wbcx.visit_user_provided_sigs();
@@@ -287,7 -287,7 +287,7 @@@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> fo
  
      fn visit_local(&mut self, l: &'gcx hir::Local) {
          intravisit::walk_local(self, l);
 -        let var_ty = self.fcx.local_ty(l.span, l.id).decl_ty;
 +        let var_ty = self.fcx.local_ty(l.span, l.hir_id).decl_ty;
          let var_ty = self.resolve(&var_ty, &l.span);
          self.write_ty_to_tables(l.hir_id, var_ty);
      }
@@@ -355,19 -355,13 +355,13 @@@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 
          }
      }
  
-     fn visit_cast_types(&mut self) {
+     fn visit_coercion_casts(&mut self) {
          let fcx_tables = self.fcx.tables.borrow();
-         let fcx_cast_kinds = fcx_tables.cast_kinds();
+         let fcx_coercion_casts = fcx_tables.coercion_casts();
          debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
-         let mut self_cast_kinds = self.tables.cast_kinds_mut();
-         let common_local_id_root = fcx_tables.local_id_root.unwrap();
  
-         for (&local_id, &cast_kind) in fcx_cast_kinds.iter() {
-             let hir_id = hir::HirId {
-                 owner: common_local_id_root.index,
-                 local_id,
-             };
-             self_cast_kinds.insert(hir_id, cast_kind);
+         for local_id in fcx_coercion_casts {
+             self.tables.set_coercion_cast(*local_id);
          }
      }