about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBastian Kauschke <bastian_kauschke@hotmail.de>2020-07-06 23:49:53 +0200
committerBastian Kauschke <bastian_kauschke@hotmail.de>2020-07-15 12:58:32 +0200
commit48bbf49765a2f2dd30d18242145a5e3084b42f94 (patch)
treea970bcc72abb88ec91614b80c6fc5f34f4d1b11b
parentb615b98f33c73670731c7e681a45a8335049492e (diff)
downloadrust-48bbf49765a2f2dd30d18242145a5e3084b42f94.tar.gz
rust-48bbf49765a2f2dd30d18242145a5e3084b42f94.zip
const generics work!
-rw-r--r--src/librustc_metadata/rmeta/decoder/cstore_impl.rs2
-rw-r--r--src/librustc_middle/arena.rs10
-rw-r--r--src/librustc_middle/query/mod.rs49
-rw-r--r--src/librustc_middle/ty/mod.rs8
-rw-r--r--src/librustc_middle/ty/relate.rs8
-rw-r--r--src/librustc_mir/borrow_check/mod.rs60
-rw-r--r--src/librustc_mir/borrow_check/nll.rs10
-rw-r--r--src/librustc_mir/borrow_check/universal_regions.rs49
-rw-r--r--src/librustc_mir/const_eval/eval_queries.rs2
-rw-r--r--src/librustc_mir/interpret/eval_context.rs6
-rw-r--r--src/librustc_mir/transform/check_consts/qualifs.rs7
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs45
-rw-r--r--src/librustc_mir/transform/mod.rs120
-rw-r--r--src/librustc_mir/transform/promote_consts.rs17
-rw-r--r--src/librustc_mir_build/build/mod.rs20
-rw-r--r--src/librustc_mir_build/hair/cx/expr.rs8
-rw-r--r--src/librustc_mir_build/hair/cx/mod.rs21
17 files changed, 301 insertions, 141 deletions
diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
index c46229b77a5..be153758a2a 100644
--- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
+++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
@@ -112,7 +112,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
         })
     }
     optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
-    promoted_mir => { cdata.get_promoted_mir(tcx, def_id.index) }
+    promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
     mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
     fn_sig => { cdata.fn_sig(def_id.index, tcx) }
     inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs
index caf771803c0..b77aca4d634 100644
--- a/src/librustc_middle/arena.rs
+++ b/src/librustc_middle/arena.rs
@@ -31,10 +31,20 @@ macro_rules! arena_types {
                         rustc_middle::mir::Body<$tcx>
                     >
                 >;
+            [] promoted:
+                rustc_index::vec::IndexVec<
+                    rustc_middle::mir::Promoted,
+                    rustc_middle::mir::Body<$tcx>
+                >,
+                rustc_index::vec::IndexVec<
+                    rustc_middle::mir::Promoted,
+                    rustc_middle::mir::Body<'_x>
+                >;
             [decode] tables: rustc_middle::ty::TypeckTables<$tcx>, rustc_middle::ty::TypeckTables<'_x>;
             [decode] borrowck_result:
                 rustc_middle::mir::BorrowCheckResult<$tcx>,
                 rustc_middle::mir::BorrowCheckResult<'_x>;
+            [] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, rustc_middle::mir::UnsafetyCheckResult;
             [] const_allocs: rustc_middle::mir::interpret::Allocation, rustc_middle::mir::interpret::Allocation;
             // Required for the incremental on-disk cache
             [few, decode] mir_keys: rustc_hir::def_id::DefIdSet, rustc_hir::def_id::DefIdSet;
diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs
index bad2dc64859..f1deb6388af 100644
--- a/src/librustc_middle/query/mod.rs
+++ b/src/librustc_middle/query/mod.rs
@@ -208,19 +208,27 @@ rustc_queries! {
             desc { |tcx| "const checking `{}`", tcx.def_path_str(key) }
             cache_on_disk_if { key.is_local() }
         }
+        query mir_const_qualif_const_arg(
+            key: ty::WithOptParam<LocalDefId>
+        ) -> mir::ConstQualifs {
+            desc {
+                |tcx| "const checking the potential const argument `{}`",
+                tcx.def_path_str(key.did.to_def_id())
+            }
+        }
 
         /// Fetch the MIR for a given `DefId` right after it's built - this includes
         /// unreachable code.
-        query mir_built(key: LocalDefId) -> &'tcx Steal<mir::Body<'tcx>> {
-            desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.to_def_id()) }
+        query mir_built(key: ty::WithOptParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
+            desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
         }
 
         /// Fetch the MIR for a given `DefId` up till the point where it is
         /// ready for const qualification.
         ///
         /// See the README for the `mir` module for details.
-        query mir_const(key: DefId) -> &'tcx Steal<mir::Body<'tcx>> {
-            desc { |tcx| "processing MIR for `{}`", tcx.def_path_str(key) }
+        query mir_const(key: ty::WithOptParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
+            desc { |tcx| "processing MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
             no_hash
         }
 
@@ -231,13 +239,16 @@ rustc_queries! {
             desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) }
         }
 
-        query mir_validated(key: LocalDefId) ->
+        query mir_validated(key: ty::WithOptParam<LocalDefId>) ->
             (
                 &'tcx Steal<mir::Body<'tcx>>,
                 &'tcx Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>>
             ) {
             no_hash
-            desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
+            desc {
+                |tcx| "processing the potential const argument `{}`",
+                tcx.def_path_str(key.did.to_def_id())
+            }
         }
 
         /// MIR after our optimization passes have run. This is MIR that is ready
@@ -261,11 +272,18 @@ rustc_queries! {
             cache_on_disk_if { key.is_local() }
         }
 
-        query promoted_mir(key: DefId) -> IndexVec<mir::Promoted, mir::Body<'tcx>> {
+        query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
             desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
-            storage(ArenaCacheSelector<'tcx>)
             cache_on_disk_if { key.is_local() }
         }
+        query promoted_mir_of_const_arg(
+            key: ty::WithOptParam<LocalDefId>
+        ) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
+            desc {
+                |tcx| "optimizing promoted MIR for the potential const argument `{}`",
+                tcx.def_path_str(key.did.to_def_id()),
+            }
+        }
     }
 
     TypeChecking {
@@ -473,11 +491,13 @@ rustc_queries! {
     }
 
     TypeChecking {
-        /// The result of unsafety-checking this `DefId`.
-        query unsafety_check_result(key: LocalDefId) -> mir::UnsafetyCheckResult {
+        /// The result of unsafety-checking this `LocalDefId`.
+        query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
             desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
             cache_on_disk_if { true }
-            storage(ArenaCacheSelector<'tcx>)
+        }
+        query unsafety_check_result_const_arg(key: ty::WithOptParam<LocalDefId>) -> &'tcx mir::UnsafetyCheckResult {
+            desc { |tcx| "unsafety-checking the potential const arg `{}`", tcx.def_path_str(key.did.to_def_id()) }
         }
 
         /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error.
@@ -601,13 +621,18 @@ rustc_queries! {
         /// Borrow-checks the function body. If this is a closure, returns
         /// additional requirements that the closure's creator must verify.
         query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
-            storage(ArenaCacheSelector<'tcx>)
             desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
             cache_on_disk_if(tcx, opt_result) {
                 tcx.is_closure(key.to_def_id())
                     || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty())
             }
         }
+        query mir_borrowck_const_arg(key: ty::WithOptParam<LocalDefId>) -> &'tcx mir::BorrowCheckResult<'tcx> {
+            desc {
+                |tcx| "borrow-checking the potential const argument`{}`",
+                tcx.def_path_str(key.did.to_def_id())
+            }
+        }
     }
 
     TypeChecking {
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 2a366c9801e..9ebf1ed60e2 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -1600,6 +1600,10 @@ impl WithOptParam<DefId> {
         self.did.as_local().map(|did| WithOptParam { did, param_did: self.param_did })
     }
 
+    pub fn expect_local(self) -> WithOptParam<LocalDefId> {
+        self.as_local().unwrap()
+    }
+
     pub fn is_local(self) -> bool {
         self.did.is_local()
     }
@@ -1607,6 +1611,10 @@ impl WithOptParam<DefId> {
     pub fn ty_def_id(self) -> DefId {
         self.param_did.unwrap_or(self.did)
     }
+
+    pub fn init_me_bby(tcx: TyCtxt<'_>, did: DefId) -> WithOptParam<DefId> {
+        WithOptParam { did, param_did: did.as_local().and_then(|did| tcx.opt_const_param_of(did)) }
+    }
 }
 
 /// When type checking, we use the `ParamEnv` to track
diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs
index 7946a27b4d9..ae2820b460f 100644
--- a/src/librustc_middle/ty/relate.rs
+++ b/src/librustc_middle/ty/relate.rs
@@ -578,12 +578,12 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
 
         // FIXME(const_generics): this is wrong, as it is a projection
         (
-            ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
-            ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
-        ) if a_def_id == b_def_id && a_promoted == b_promoted => {
+            ty::ConstKind::Unevaluated(a_def, a_substs, a_promoted),
+            ty::ConstKind::Unevaluated(b_def, b_substs, b_promoted),
+        ) if a_def == b_def && a_promoted == b_promoted => {
             let substs =
                 relation.relate_with_variance(ty::Variance::Invariant, a_substs, b_substs)?;
-            Ok(ty::ConstKind::Unevaluated(a_def_id, substs, a_promoted))
+            Ok(ty::ConstKind::Unevaluated(a_def, substs, a_promoted))
         }
         _ => Err(TypeError::ConstMismatch(expected_found(relation, a, b))),
     };
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index e77dcb63f46..b4ddda5c03d 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -17,7 +17,7 @@ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind
 use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
 use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, RegionVid, TyCtxt};
 use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 
@@ -87,17 +87,32 @@ crate struct Upvar {
 const DEREF_PROJECTION: &[PlaceElem<'_>; 1] = &[ProjectionElem::Deref];
 
 pub fn provide(providers: &mut Providers) {
-    *providers = Providers { mir_borrowck, ..*providers };
+    *providers = Providers {
+        mir_borrowck: |tcx, did| mir_borrowck(tcx, ty::WithOptParam::dummy(did)),
+        mir_borrowck_const_arg: |tcx, def| {
+            if def.param_did.is_none() { tcx.mir_borrowck(def.did) } else { mir_borrowck(tcx, def) }
+        },
+        ..*providers
+    };
 }
 
-fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx BorrowCheckResult<'tcx> {
-    let (input_body, promoted) = tcx.mir_validated(def_id);
-    debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id.to_def_id()));
+fn mir_borrowck<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::WithOptParam<LocalDefId>,
+) -> &'tcx BorrowCheckResult<'tcx> {
+    if def.param_did.is_none() {
+        if let param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
+            return tcx.mir_borrowck_const_arg(ty::WithOptParam { param_did, ..def });
+        }
+    }
+
+    let (input_body, promoted) = tcx.mir_validated(def);
+    debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
 
     let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
         let input_body: &Body<'_> = &input_body.borrow();
         let promoted: &IndexVec<_, _> = &promoted.borrow();
-        do_mir_borrowck(&infcx, input_body, promoted, def_id)
+        do_mir_borrowck(&infcx, input_body, promoted, def)
     });
     debug!("mir_borrowck done");
 
@@ -108,13 +123,13 @@ fn do_mir_borrowck<'a, 'tcx>(
     infcx: &InferCtxt<'a, 'tcx>,
     input_body: &Body<'tcx>,
     input_promoted: &IndexVec<Promoted, Body<'tcx>>,
-    def_id: LocalDefId,
+    def: ty::WithOptParam<LocalDefId>,
 ) -> BorrowCheckResult<'tcx> {
-    debug!("do_mir_borrowck(def_id = {:?})", def_id);
+    debug!("do_mir_borrowck(def = {:?})", def);
 
     let tcx = infcx.tcx;
-    let param_env = tcx.param_env(def_id);
-    let id = tcx.hir().as_local_hir_id(def_id);
+    let param_env = tcx.param_env(def.did);
+    let id = tcx.hir().as_local_hir_id(def.did);
 
     let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
     for var_debug_info in &input_body.var_debug_info {
@@ -135,13 +150,13 @@ fn do_mir_borrowck<'a, 'tcx>(
     }
 
     // Gather the upvars of a closure, if any.
-    let tables = tcx.typeck_tables_of(def_id);
+    let tables = tcx.typeck_tables_of_const_arg(def);
     if let Some(ErrorReported) = tables.tainted_by_errors {
         infcx.set_tainted_by_errors();
     }
     let upvars: Vec<_> = tables
         .closure_captures
-        .get(&def_id.to_def_id())
+        .get(&def.did.to_def_id())
         .into_iter()
         .flat_map(|v| v.values())
         .map(|upvar_id| {
@@ -171,8 +186,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     // will have a lifetime tied to the inference context.
     let mut body = input_body.clone();
     let mut promoted = input_promoted.clone();
-    let free_regions =
-        nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted);
+    let free_regions = nll::replace_regions_in_mir(infcx, def, param_env, &mut body, &mut promoted);
     let body = &body; // no further changes
 
     let location_table = &LocationTable::new(&body);
@@ -190,7 +204,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     let mdpe = MoveDataParamEnv { move_data, param_env };
 
     let mut flow_inits = MaybeInitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint()
         .into_results_cursor(&body);
 
@@ -207,7 +221,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         nll_errors,
     } = nll::compute_regions(
         infcx,
-        def_id,
+        def.did,
         free_regions,
         body,
         &promoted,
@@ -223,7 +237,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     // write unit-tests, as well as helping with debugging.
     nll::dump_mir_results(
         infcx,
-        MirSource::item(def_id.to_def_id()),
+        MirSource { instance: InstanceDef::Item(def.to_global()), promoted: None },
         &body,
         &regioncx,
         &opt_closure_req,
@@ -234,7 +248,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     nll::dump_annotation(
         infcx,
         &body,
-        def_id.to_def_id(),
+        def.did.to_def_id(),
         &regioncx,
         &opt_closure_req,
         &opaque_type_values,
@@ -249,13 +263,13 @@ fn do_mir_borrowck<'a, 'tcx>(
     let regioncx = Rc::new(regioncx);
 
     let flow_borrows = Borrows::new(tcx, &body, regioncx.clone(), &borrow_set)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint();
     let flow_uninits = MaybeUninitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint();
     let flow_ever_inits = EverInitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint();
 
     let movable_generator = match tcx.hir().get(id) {
@@ -274,7 +288,7 @@ fn do_mir_borrowck<'a, 'tcx>(
             let mut promoted_mbcx = MirBorrowckCtxt {
                 infcx,
                 body: promoted_body,
-                mir_def_id: def_id,
+                mir_def_id: def.did,
                 move_data: &move_data,
                 location_table: &LocationTable::new(promoted_body),
                 movable_generator,
@@ -307,7 +321,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     let mut mbcx = MirBorrowckCtxt {
         infcx,
         body,
-        mir_def_id: def_id,
+        mir_def_id: def.did,
         move_data: &mdpe.move_data,
         location_table,
         movable_generator,
diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs
index ea68364be37..f1e7f4c26f4 100644
--- a/src/librustc_mir/borrow_check/nll.rs
+++ b/src/librustc_mir/borrow_check/nll.rs
@@ -9,7 +9,7 @@ use rustc_middle::mir::{
     BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
     Promoted,
 };
-use rustc_middle::ty::{self, RegionKind, RegionVid};
+use rustc_middle::ty::{self, InstanceDef, RegionKind, RegionVid};
 use rustc_span::symbol::sym;
 use std::env;
 use std::fmt::Debug;
@@ -59,20 +59,20 @@ crate struct NllOutput<'tcx> {
 /// `compute_regions`.
 pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
-    def_id: LocalDefId,
+    def: ty::WithOptParam<LocalDefId>,
     param_env: ty::ParamEnv<'tcx>,
     body: &mut Body<'tcx>,
     promoted: &mut IndexVec<Promoted, Body<'tcx>>,
 ) -> UniversalRegions<'tcx> {
-    debug!("replace_regions_in_mir(def_id={:?})", def_id);
+    debug!("replace_regions_in_mir(def={:?})", def);
 
     // Compute named region information. This also renumbers the inputs/outputs.
-    let universal_regions = UniversalRegions::new(infcx, def_id, param_env);
+    let universal_regions = UniversalRegions::new(infcx, def, param_env);
 
     // Replace all remaining regions with fresh inference variables.
     renumber::renumber_mir(infcx, body, promoted);
 
-    let source = MirSource::item(def_id.to_def_id());
+    let source = MirSource { instance: InstanceDef::Item(def.to_global()), promoted: None };
     mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(()));
 
     universal_regions
diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs
index 7b292ee71f9..1e2d94a1df4 100644
--- a/src/librustc_mir/borrow_check/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/universal_regions.rs
@@ -227,12 +227,12 @@ impl<'tcx> UniversalRegions<'tcx> {
     /// known between those regions.
     pub fn new(
         infcx: &InferCtxt<'_, 'tcx>,
-        mir_def_id: LocalDefId,
+        mir_def: ty::WithOptParam<LocalDefId>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Self {
         let tcx = infcx.tcx;
-        let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id);
-        UniversalRegionsBuilder { infcx, mir_def_id, mir_hir_id, param_env }.build()
+        let mir_hir_id = tcx.hir().as_local_hir_id(mir_def.did);
+        UniversalRegionsBuilder { infcx, mir_def, mir_hir_id, param_env }.build()
     }
 
     /// Given a reference to a closure type, extracts all the values
@@ -388,7 +388,7 @@ impl<'tcx> UniversalRegions<'tcx> {
 
 struct UniversalRegionsBuilder<'cx, 'tcx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
-    mir_def_id: LocalDefId,
+    mir_def: ty::WithOptParam<LocalDefId>,
     mir_hir_id: HirId,
     param_env: ty::ParamEnv<'tcx>,
 }
@@ -397,7 +397,7 @@ const FR: NLLRegionVariableOrigin = NLLRegionVariableOrigin::FreeRegion;
 
 impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
     fn build(self) -> UniversalRegions<'tcx> {
-        debug!("build(mir_def_id={:?})", self.mir_def_id);
+        debug!("build(mir_def={:?})", self.mir_def);
 
         let param_env = self.param_env;
         debug!("build: param_env={:?}", param_env);
@@ -417,7 +417,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let mut indices = self.compute_indices(fr_static, defining_ty);
         debug!("build: indices={:?}", indices);
 
-        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id.to_def_id());
+        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id());
 
         // If this is a closure or generator, then the late-bound regions from the enclosing
         // function are actually external regions to us. For example, here, 'a is not local
@@ -425,8 +425,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         // fn foo<'a>() {
         //     let c = || { let x: &'a u32 = ...; }
         // }
-        if self.mir_def_id.to_def_id() != closure_base_def_id {
-            self.infcx.replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices)
+        if self.mir_def.did.to_def_id() != closure_base_def_id {
+            self.infcx
+                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
         }
 
         let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
@@ -436,15 +437,15 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let first_local_index = self.infcx.num_region_vars();
         let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
             FR,
-            self.mir_def_id,
+            self.mir_def.did,
             &bound_inputs_and_output,
             &mut indices,
         );
         // Converse of above, if this is a function then the late-bound regions declared on its
         // signature are local to the fn.
-        if self.mir_def_id.to_def_id() == closure_base_def_id {
+        if self.mir_def.did.to_def_id() == closure_base_def_id {
             self.infcx
-                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices);
+                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
         }
 
         let (unnormalized_output_ty, mut unnormalized_input_tys) =
@@ -456,7 +457,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             if self.infcx.tcx.fn_sig(def_id).c_variadic() {
                 let va_list_did = self.infcx.tcx.require_lang_item(
                     lang_items::VaListTypeLangItem,
-                    Some(self.infcx.tcx.def_span(self.mir_def_id)),
+                    Some(self.infcx.tcx.def_span(self.mir_def.did)),
                 );
                 let region = self
                     .infcx
@@ -507,14 +508,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
     /// see `DefiningTy` for details.
     fn defining_ty(&self) -> DefiningTy<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
+        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
 
         match tcx.hir().body_owner_kind(self.mir_hir_id) {
             BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
-                let defining_ty = if self.mir_def_id.to_def_id() == closure_base_def_id {
+                let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id {
                     tcx.type_of(closure_base_def_id)
                 } else {
-                    let tables = tcx.typeck_tables_of(self.mir_def_id);
+                    let tables = tcx.typeck_tables_of(self.mir_def.did);
                     tables.node_type(self.mir_hir_id)
                 };
 
@@ -530,20 +531,20 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                     }
                     ty::FnDef(def_id, substs) => DefiningTy::FnDef(def_id, substs),
                     _ => span_bug!(
-                        tcx.def_span(self.mir_def_id),
+                        tcx.def_span(self.mir_def.did),
                         "expected defining type for `{:?}`: `{:?}`",
-                        self.mir_def_id,
+                        self.mir_def.did,
                         defining_ty
                     ),
                 }
             }
 
             BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
-                assert_eq!(self.mir_def_id.to_def_id(), closure_base_def_id);
+                assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
                 let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
                 let substs =
                     self.infcx.replace_free_regions_with_nll_infer_vars(FR, &identity_substs);
-                DefiningTy::Const(self.mir_def_id.to_def_id(), substs)
+                DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
             }
         }
     }
@@ -558,7 +559,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         defining_ty: DefiningTy<'tcx>,
     ) -> UniversalRegionIndices<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id.to_def_id());
+        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
         let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
         let fr_substs = match defining_ty {
             DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
@@ -592,7 +593,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let tcx = self.infcx.tcx;
         match defining_ty {
             DefiningTy::Closure(def_id, substs) => {
-                assert_eq!(self.mir_def_id.to_def_id(), def_id);
+                assert_eq!(self.mir_def.did.to_def_id(), def_id);
                 let closure_sig = substs.as_closure().sig();
                 let inputs_and_output = closure_sig.inputs_and_output();
                 let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap();
@@ -616,7 +617,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             }
 
             DefiningTy::Generator(def_id, substs, movability) => {
-                assert_eq!(self.mir_def_id.to_def_id(), def_id);
+                assert_eq!(self.mir_def.did.to_def_id(), def_id);
                 let resume_ty = substs.as_generator().resume_ty();
                 let output = substs.as_generator().return_ty();
                 let generator_ty = tcx.mk_generator(def_id, substs, movability);
@@ -634,8 +635,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             DefiningTy::Const(def_id, _) => {
                 // For a constant body, there are no inputs, and one
                 // "output" (the type of the constant).
-                assert_eq!(self.mir_def_id.to_def_id(), def_id);
-                let ty = tcx.type_of(def_id);
+                assert_eq!(self.mir_def.did.to_def_id(), def_id);
+                let ty = tcx.type_of(self.mir_def.ty_def_id());
                 let ty = indices.fold_to_region_vids(tcx, &ty);
                 ty::Binder::dummy(tcx.intern_type_list(&[ty]))
             }
diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs
index a8f0de68f22..c3f992877ea 100644
--- a/src/librustc_mir/const_eval/eval_queries.rs
+++ b/src/librustc_mir/const_eval/eval_queries.rs
@@ -359,7 +359,7 @@ pub fn const_eval_raw_provider<'tcx>(
                     // deny-by-default lint
                     _ => {
                         if let Some(p) = cid.promoted {
-                            let span = tcx.promoted_mir(def.did)[p].span;
+                            let span = tcx.promoted_mir_of_const_arg(def)[p].span;
                             if let err_inval!(ReferencedConstant) = err.error {
                                 err.report_as_error(
                                     tcx.at(span),
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 5e1376677a0..bfef9c1b353 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -406,7 +406,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
         trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
         if let Some(promoted) = promoted {
-            return Ok(&self.tcx.promoted_mir(def.did)[promoted]);
+            return if let Some(def) = def.as_local() {
+                Ok(&self.tcx.promoted_mir_of_const_arg(def)[promoted])
+            } else {
+                Ok(&self.tcx.promoted_mir(def.did)[promoted])
+            };
         }
         match instance {
             ty::InstanceDef::Item(def) => {
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index 705eb5d7323..a03d3fbb68e 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -248,7 +248,12 @@ where
         assert!(promoted.is_none());
         // Don't peek inside trait associated constants.
         if cx.tcx.trait_of_item(def.did).is_none() {
-            let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def.did);
+            let qualifs = if let Some(def) = def.as_local() {
+                cx.tcx.at(constant.span).mir_const_qualif_const_arg(def)
+            } else {
+                cx.tcx.at(constant.span).mir_const_qualif(def.did)
+            };
+
             if !Q::in_qualifs(&qualifs) {
                 return false;
             }
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index f218dd397c0..6d270a9c684 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -489,7 +489,20 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { unsafety_check_result, unsafe_derive_on_repr_packed, ..*providers };
+    *providers = Providers {
+        unsafety_check_result: |tcx, def_id| {
+            unsafety_check_result(tcx, ty::WithOptParam::dummy(def_id))
+        },
+        unsafety_check_result_const_arg: |tcx, def| {
+            if def.param_did.is_none() {
+                tcx.unsafety_check_result(def.did)
+            } else {
+                unsafety_check_result(tcx, def)
+            }
+        },
+        unsafe_derive_on_repr_packed,
+        ..*providers
+    };
 }
 
 struct UnusedUnsafeVisitor<'a> {
@@ -535,32 +548,42 @@ fn check_unused_unsafe(
     intravisit::Visitor::visit_body(&mut visitor, body);
 }
 
-fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: LocalDefId) -> UnsafetyCheckResult {
-    debug!("unsafety_violations({:?})", def_id);
+fn unsafety_check_result<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::WithOptParam<LocalDefId>,
+) -> &'tcx UnsafetyCheckResult {
+    if def.param_did.is_none() {
+        if let param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
+            return tcx.unsafety_check_result_const_arg(ty::WithOptParam { param_did, ..def });
+        }
+    }
+
+    debug!("unsafety_violations({:?})", def);
 
     // N.B., this borrow is valid because all the consumers of
     // `mir_built` force this.
-    let body = &tcx.mir_built(def_id).borrow();
+    let body = &tcx.mir_built(def).borrow();
 
-    let param_env = tcx.param_env(def_id);
+    let param_env = tcx.param_env(def.did);
 
-    let id = tcx.hir().as_local_hir_id(def_id);
+    let id = tcx.hir().as_local_hir_id(def.did);
     let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) {
         hir::BodyOwnerKind::Closure => (false, false),
         hir::BodyOwnerKind::Fn => {
-            (tcx.is_const_fn_raw(def_id.to_def_id()), is_min_const_fn(tcx, def_id.to_def_id()))
+            (tcx.is_const_fn_raw(def.did.to_def_id()), is_min_const_fn(tcx, def.did.to_def_id()))
         }
         hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false),
     };
     let mut checker =
-        UnsafetyChecker::new(const_context, min_const_fn, body, def_id, tcx, param_env);
+        UnsafetyChecker::new(const_context, min_const_fn, body, def.did, tcx, param_env);
     checker.visit_body(&body);
 
-    check_unused_unsafe(tcx, def_id, &checker.used_unsafe, &mut checker.inherited_blocks);
-    UnsafetyCheckResult {
+    check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks);
+
+    tcx.arena.alloc(UnsafetyCheckResult {
         violations: checker.violations.into(),
         unsafe_blocks: checker.inherited_blocks.into(),
-    }
+    })
 }
 
 fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 25973462e4c..8259e1288bb 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -48,13 +48,31 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         mir_keys,
         mir_const,
-        mir_const_qualif,
+        mir_const_qualif: |tcx, did| {
+            mir_const_qualif(tcx, ty::WithOptParam::dummy(did.expect_local()))
+        },
+        mir_const_qualif_const_arg: |tcx, def| {
+            if def.param_did.is_none() {
+                tcx.mir_const_qualif(def.did.to_def_id())
+            } else {
+                mir_const_qualif(tcx, def)
+            }
+        },
         mir_validated,
         mir_drops_elaborated_and_const_checked,
         optimized_mir,
         optimized_mir_of_const_arg,
         is_mir_available,
-        promoted_mir,
+        promoted_mir: |tcx, def_id| {
+            promoted_mir(tcx, ty::WithOptParam::dummy(def_id.expect_local()))
+        },
+        promoted_mir_of_const_arg: |tcx, def| {
+            if def.param_did.is_none() {
+                tcx.promoted_mir(def.did.to_def_id())
+            } else {
+                promoted_mir(tcx, def)
+            }
+        },
         ..*providers
     };
     instrument_coverage::provide(providers);
@@ -120,6 +138,10 @@ impl<'tcx> MirSource<'tcx> {
         MirSource { instance: InstanceDef::Item(ty::WithOptParam::dummy(def_id)), promoted: None }
     }
 
+    pub fn with_opt_param(self) -> ty::WithOptParam<DefId> {
+        self.instance.with_opt_param()
+    }
+
     #[inline]
     pub fn def_id(&self) -> DefId {
         self.instance.def_id()
@@ -203,9 +225,14 @@ pub fn run_passes(
     }
 }
 
-fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
-    let def_id = def_id.expect_local();
-    let const_kind = tcx.hir().body_const_context(def_id);
+fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptParam<LocalDefId>) -> ConstQualifs {
+    if def.param_did.is_none() {
+        if let param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
+            return tcx.mir_const_qualif_const_arg(ty::WithOptParam { param_did, ..def });
+        }
+    }
+
+    let const_kind = tcx.hir().body_const_context(def.did);
 
     // No need to const-check a non-const `fn`.
     if const_kind.is_none() {
@@ -216,15 +243,20 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
     // cannot yet be stolen), because `mir_validated()`, which steals
     // from `mir_const(), forces this query to execute before
     // performing the steal.
-    let body = &tcx.mir_const(def_id.to_def_id()).borrow();
+    let body = &tcx.mir_const(def).borrow();
 
     if body.return_ty().references_error() {
         tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors");
         return Default::default();
     }
 
-    let ccx =
-        check_consts::ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) };
+    let ccx = check_consts::ConstCx {
+        body,
+        tcx,
+        def_id: def.did,
+        const_kind,
+        param_env: tcx.param_env(def.did),
+    };
 
     let mut validator = check_consts::validation::Validator::new(&ccx);
     validator.check_body();
@@ -235,22 +267,35 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
 }
 
 /// Make MIR ready for const evaluation. This is run on all MIR, not just on consts!
-fn mir_const<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Steal<Body<'tcx>> {
-    let def_id = def_id.expect_local();
+fn mir_const<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::WithOptParam<LocalDefId>,
+) -> &'tcx Steal<Body<'tcx>> {
+    if def.param_did.is_none() {
+        if let param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
+            return tcx.mir_const(ty::WithOptParam { param_did, ..def });
+        }
+    }
 
     // Unsafety check uses the raw mir, so make sure it is run.
-    let _ = tcx.unsafety_check_result(def_id);
+    let _ = tcx.unsafety_check_result_const_arg(def);
 
-    let mut body = tcx.mir_built(def_id).steal();
+    let mut body = tcx.mir_built(def).steal();
 
-    util::dump_mir(tcx, None, "mir_map", &0, MirSource::item(def_id.to_def_id()), &body, |_, _| {
-        Ok(())
-    });
+    util::dump_mir(
+        tcx,
+        None,
+        "mir_map",
+        &0,
+        MirSource { instance: InstanceDef::Item(def.to_global()), promoted: None },
+        &body,
+        |_, _| Ok(()),
+    );
 
     run_passes(
         tcx,
         &mut body,
-        InstanceDef::Item(ty::WithOptParam::dummy(def_id.to_def_id())),
+        InstanceDef::Item(def.to_global()),
         None,
         MirPhase::Const,
         &[&[
@@ -266,13 +311,19 @@ fn mir_const<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Steal<Body<'tcx>>
 
 fn mir_validated(
     tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
+    def: ty::WithOptParam<LocalDefId>,
 ) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
+    if def.param_did.is_none() {
+        if let param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
+            return tcx.mir_validated(ty::WithOptParam { param_did, ..def });
+        }
+    }
+
     // Ensure that we compute the `mir_const_qualif` for constants at
     // this point, before we steal the mir-const result.
-    let _ = tcx.mir_const_qualif(def_id.to_def_id());
+    let _ = tcx.mir_const_qualif_const_arg(def);
 
-    let mut body = tcx.mir_const(def_id.to_def_id()).steal();
+    let mut body = tcx.mir_const(def).steal();
 
     let mut required_consts = Vec::new();
     let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
@@ -285,7 +336,7 @@ fn mir_validated(
     run_passes(
         tcx,
         &mut body,
-        InstanceDef::Item(ty::WithOptParam::dummy(def_id.to_def_id())),
+        InstanceDef::Item(def.to_global()),
         None,
         MirPhase::Validated,
         &[&[
@@ -316,9 +367,9 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
 
     // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
     // execute before we can steal.
-    tcx.ensure().mir_borrowck(def.did);
+    tcx.ensure().mir_borrowck_const_arg(def);
 
-    let (body, _) = tcx.mir_validated(def.did);
+    let (body, _) = tcx.mir_validated(def);
     let mut body = body.steal();
 
     run_post_borrowck_cleanup_passes(tcx, &mut body, def.did, None);
@@ -473,23 +524,30 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptParam<LocalDefId>) -> Bo
     body
 }
 
-fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> IndexVec<Promoted, Body<'_>> {
-    if tcx.is_constructor(def_id) {
-        return IndexVec::new();
+fn promoted_mir<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::WithOptParam<LocalDefId>,
+) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
+    if def.param_did.is_none() {
+        if let param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
+            return tcx.promoted_mir_of_const_arg(ty::WithOptParam { param_did, ..def });
+        }
     }
 
-    let def_id = def_id.expect_local();
+    if tcx.is_constructor(def.did.to_def_id()) {
+        return tcx.arena.alloc(IndexVec::new());
+    }
 
-    tcx.ensure().mir_borrowck(def_id);
-    let (_, promoted) = tcx.mir_validated(def_id);
+    tcx.ensure().mir_borrowck_const_arg(def);
+    let (_, promoted) = tcx.mir_validated(def);
     let mut promoted = promoted.steal();
 
     for (p, mut body) in promoted.iter_enumerated_mut() {
-        run_post_borrowck_cleanup_passes(tcx, &mut body, def_id, Some(p));
-        run_optimization_passes(tcx, &mut body, def_id, Some(p));
+        run_post_borrowck_cleanup_passes(tcx, &mut body, def.did, Some(p));
+        run_optimization_passes(tcx, &mut body, def.did, Some(p));
     }
 
     debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
 
-    promoted
+    tcx.arena.alloc(promoted)
 }
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index a96ba715835..292ff17f4c5 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -60,16 +60,15 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
             return;
         }
 
-        let def_id = src.def_id().expect_local();
+        let def = src.with_opt_param().expect_local();
 
         let mut rpo = traversal::reverse_postorder(body);
-        let ccx = ConstCx::new(tcx, def_id, body);
+        let ccx = ConstCx::new(tcx, def.did, body);
         let (temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
 
         let promotable_candidates = validate_candidates(&ccx, &temps, &all_candidates);
 
-        let promoted =
-            promote_candidates(def_id.to_def_id(), body, tcx, temps, promotable_candidates);
+        let promoted = promote_candidates(def.to_global(), body, tcx, temps, promotable_candidates);
         self.promoted_fragments.set(promoted);
     }
 }
@@ -937,7 +936,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
 
     fn promote_candidate(
         mut self,
-        def_id: DefId,
+        def: ty::WithOptParam<DefId>,
         candidate: Candidate,
         next_promoted_id: usize,
     ) -> Option<Body<'tcx>> {
@@ -955,8 +954,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                     literal: tcx.mk_const(ty::Const {
                         ty,
                         val: ty::ConstKind::Unevaluated(
-                            ty::WithOptParam::dummy(def_id),
-                            InternalSubsts::for_item(tcx, def_id, |param, _| {
+                            def,
+                            InternalSubsts::for_item(tcx, def.did, |param, _| {
                                 if let ty::GenericParamDefKind::Lifetime = param.kind {
                                     tcx.lifetimes.re_erased.into()
                                 } else {
@@ -1100,7 +1099,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
 }
 
 pub fn promote_candidates<'tcx>(
-    def_id: DefId,
+    def: ty::WithOptParam<DefId>,
     body: &mut Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     mut temps: IndexVec<Local, TempState>,
@@ -1157,7 +1156,7 @@ pub fn promote_candidates<'tcx>(
         };
 
         //FIXME(oli-obk): having a `maybe_push()` method on `IndexVec` might be nice
-        if let Some(promoted) = promoter.promote_candidate(def_id, candidate, promotions.len()) {
+        if let Some(promoted) = promoter.promote_candidate(def, candidate, promotions.len()) {
             promotions.push(promoted);
         }
     }
diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs
index 07d0f6ab8dd..4aa3e87d415 100644
--- a/src/librustc_mir_build/build/mod.rs
+++ b/src/librustc_mir_build/build/mod.rs
@@ -21,13 +21,19 @@ use rustc_target::spec::PanicStrategy;
 
 use super::lints;
 
-crate fn mir_built<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ty::steal::Steal<Body<'tcx>> {
-    tcx.alloc_steal_mir(mir_build(tcx, def_id))
+crate fn mir_built<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptParam<LocalDefId>) -> &'tcx ty::steal::Steal<Body<'tcx>> {
+    if def.param_did.is_none() {
+        if let param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
+            return tcx.mir_built(ty::WithOptParam { param_did, ..def });
+        }
+    }
+
+    tcx.alloc_steal_mir(mir_build(tcx, def))
 }
 
 /// Construct the MIR for a given `DefId`.
-fn mir_build(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Body<'_> {
-    let id = tcx.hir().as_local_hir_id(def_id);
+fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptParam<LocalDefId>) -> Body<'_> {
+    let id = tcx.hir().as_local_hir_id(def.did);
 
     // Figure out what primary body this item has.
     let (body_id, return_ty_span) = match tcx.hir().get(id) {
@@ -57,11 +63,11 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Body<'_> {
         }) => (*body_id, ty.span),
         Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => (*body, tcx.hir().span(*hir_id)),
 
-        _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def_id),
+        _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def.did),
     };
 
     tcx.infer_ctxt().enter(|infcx| {
-        let cx = Cx::new(&infcx, id);
+        let cx = Cx::new(&infcx, def, id);
         let body = if let Some(ErrorReported) = cx.tables().tainted_by_errors {
             build::construct_error(cx, body_id)
         } else if cx.body_owner_kind.is_fn_or_closure() {
@@ -181,7 +187,7 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Body<'_> {
             build::construct_const(cx, body_id, return_ty, return_ty_span)
         };
 
-        lints::check(tcx, &body, def_id);
+        lints::check(tcx, &body, def.did);
 
         // The borrow checker will replace all the regions here with its own
         // inference variables. There's no point having non-erased regions here.
diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs
index 025ef1ece46..e5f9f7328b8 100644
--- a/src/librustc_mir_build/hair/cx/expr.rs
+++ b/src/librustc_mir_build/hair/cx/expr.rs
@@ -601,7 +601,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                             let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
                             let lhs = mk_const(cx.tcx().mk_const(ty::Const {
                                 val: ty::ConstKind::Unevaluated(
-                                    ty::WithOptParam::dummy(did),
+                                    ty::WithOptParam::init_me_bby(cx.tcx(), did),
                                     substs,
                                     None,
                                 ),
@@ -800,7 +800,11 @@ fn convert_path_expr<'a, 'tcx>(
             debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
             ExprKind::Literal {
                 literal: cx.tcx.mk_const(ty::Const {
-                    val: ty::ConstKind::Unevaluated(ty::WithOptParam::dummy(def_id), substs, None),
+                    val: ty::ConstKind::Unevaluated(
+                        ty::WithOptParam::init_me_bby(cx.tcx, def_id),
+                        substs,
+                        None,
+                    ),
                     ty: cx.tables().node_type(expr.hir_id),
                 }),
                 user_ty,
diff --git a/src/librustc_mir_build/hair/cx/mod.rs b/src/librustc_mir_build/hair/cx/mod.rs
index d8b3ac79e6b..5505559fc8e 100644
--- a/src/librustc_mir_build/hair/cx/mod.rs
+++ b/src/librustc_mir_build/hair/cx/mod.rs
@@ -1,4 +1,4 @@
-//! This module contains the fcuntaiontliy to convert from the wacky tcx data
+//! This module contains the functionality to convert from the wacky tcx data
 //! structures into the HAIR. The `builder` is generally ignorant of the tcx,
 //! etc., and instead goes through the `Cx` for most of its work.
 
@@ -8,7 +8,7 @@ use crate::hair::*;
 use rustc_ast::ast;
 use rustc_ast::attr;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::Node;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::InferCtxt;
@@ -50,10 +50,13 @@ crate struct Cx<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Cx<'a, 'tcx> {
-    crate fn new(infcx: &'a InferCtxt<'a, 'tcx>, src_id: hir::HirId) -> Cx<'a, 'tcx> {
+    crate fn new(
+        infcx: &'a InferCtxt<'a, 'tcx>,
+        def: ty::WithOptParam<LocalDefId>,
+        src_id: hir::HirId,
+    ) -> Cx<'a, 'tcx> {
         let tcx = infcx.tcx;
-        let src_def_id = tcx.hir().local_def_id(src_id);
-        let tables = tcx.typeck_tables_of(src_def_id);
+        let tables = tcx.typeck_tables_of_const_arg(def);
         let body_owner_kind = tcx.hir().body_owner_kind(src_id);
 
         let constness = match body_owner_kind {
@@ -78,12 +81,12 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
             tcx,
             infcx,
             root_lint_level: src_id,
-            param_env: tcx.param_env(src_def_id),
-            identity_substs: InternalSubsts::identity_for_item(tcx, src_def_id.to_def_id()),
-            region_scope_tree: tcx.region_scope_tree(src_def_id),
+            param_env: tcx.param_env(def.did),
+            identity_substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
+            region_scope_tree: tcx.region_scope_tree(def.did),
             tables,
             constness,
-            body_owner: src_def_id.to_def_id(),
+            body_owner: def.did.to_def_id(),
             body_owner_kind,
             check_overflow,
         }