about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-05-08 13:11:43 +0000
committerbors <bors@rust-lang.org>2020-05-08 13:11:43 +0000
commit7b805396bf46dce972692a6846ce2ad8481c5f85 (patch)
treeda21217d9b268425e249c329ad841a5e8ac0b48f
parenta51e004e1bf7f9bba151dd9104a217c1ace6a0a2 (diff)
parent678954000a2ebd22e5e4a2541bbf893c32441a1c (diff)
downloadrust-7b805396bf46dce972692a6846ce2ad8481c5f85.tar.gz
rust-7b805396bf46dce972692a6846ce2ad8481c5f85.zip
Auto merge of #72010 - Dylan-DPC:rollup-prdj0pk, r=Dylan-DPC
Rollup of 6 pull requests

Successful merges:

 - #71989 (Use a single enum for the kind of a const context)
 - #71993 (Remove old `util/liveness.rs` module)
 - #71999 (Add myself to mailmap.)
 - #72001 (Adjust cfg(version) to lang team decision)
 - #72007 (Fix some tests failing in `--pass check` mode)
 - #72008 (Add const-generics test)

Failed merges:

r? @ghost
-rw-r--r--.mailmap1
-rw-r--r--src/librustc_attr/build.rs3
-rw-r--r--src/librustc_attr/builtin.rs7
-rw-r--r--src/librustc_hir/hir.rs47
-rw-r--r--src/librustc_middle/hir/map/mod.rs20
-rw-r--r--src/librustc_mir/borrow_check/def_use.rs78
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/find_use.rs4
-rw-r--r--src/librustc_mir/borrow_check/mod.rs1
-rw-r--r--src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs5
-rw-r--r--src/librustc_mir/borrow_check/type_check/liveness/polonius.rs4
-rw-r--r--src/librustc_mir/dataflow/impls/liveness.rs7
-rw-r--r--src/librustc_mir/transform/check_consts/mod.rs68
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs7
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs25
-rw-r--r--src/librustc_mir/transform/mod.rs2
-rw-r--r--src/librustc_mir/transform/promote_consts.rs11
-rw-r--r--src/librustc_mir/util/liveness.rs326
-rw-r--r--src/librustc_mir/util/mod.rs1
-rw-r--r--src/librustc_passes/check_const.rs55
-rw-r--r--src/test/ui/const-generics/trait-const-args.rs29
-rw-r--r--src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr2
-rw-r--r--src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr2
-rw-r--r--src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr2
-rw-r--r--src/test/ui/lint/lint-exceeding-bitshifts.rs4
24 files changed, 235 insertions, 476 deletions
diff --git a/.mailmap b/.mailmap
index aed3a4ca5b0..680aa04078f 100644
--- a/.mailmap
+++ b/.mailmap
@@ -49,6 +49,7 @@ Carol (Nichols || Goulding) <carol.nichols@gmail.com> <193874+carols10cents@user
 Carol (Nichols || Goulding) <carol.nichols@gmail.com> <carol.nichols@gmail.com>
 Carol (Nichols || Goulding) <carol.nichols@gmail.com> <cnichols@thinkthroughmath.com>
 Carol Willing <carolcode@willingconsulting.com>
+Charles Lew <crlf0710@gmail.com> CrLF0710 <crlf0710@gmail.com>
 Chris C Cerami <chrisccerami@users.noreply.github.com> Chris C Cerami <chrisccerami@gmail.com>
 Chris Pressey <cpressey@gmail.com>
 Chris Thorn <chris@thorn.co> Chris Thorn <thorn@thoughtbot.com>
diff --git a/src/librustc_attr/build.rs b/src/librustc_attr/build.rs
index d230ba91039..863f2b7337b 100644
--- a/src/librustc_attr/build.rs
+++ b/src/librustc_attr/build.rs
@@ -1,4 +1,5 @@
 fn main() {
     println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_VERSION");
+    println!("cargo:rerun-if-env-changed=CFG_RELEASE");
+    println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
 }
diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs
index ce38e3f5f4e..a592bbc2bf9 100644
--- a/src/librustc_attr/builtin.rs
+++ b/src/librustc_attr/builtin.rs
@@ -652,9 +652,12 @@ pub fn eval_condition(
                     return false;
                 }
             };
-            let version = Version::parse(env!("CFG_VERSION")).unwrap();
+            let channel = env!("CFG_RELEASE_CHANNEL");
+            let nightly = channel == "nightly" || channel == "dev";
+            let rustc_version = Version::parse(env!("CFG_RELEASE")).unwrap();
 
-            version >= min_version
+            // See https://github.com/rust-lang/rust/issues/64796#issuecomment-625474439 for details
+            if nightly { rustc_version > min_version } else { rustc_version >= min_version }
         }
         ast::MetaItemKind::List(ref mis) => {
             for mi in mis.iter() {
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index e6d673b30f7..75a5c198ec7 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -1291,6 +1291,53 @@ impl BodyOwnerKind {
     }
 }
 
+/// The kind of an item that requires const-checking.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ConstContext {
+    /// A `const fn`.
+    ConstFn,
+
+    /// A `static` or `static mut`.
+    Static(Mutability),
+
+    /// A `const`, associated `const`, or other const context.
+    ///
+    /// Other contexts include:
+    /// - Array length expressions
+    /// - Enum discriminants
+    /// - Const generics
+    ///
+    /// For the most part, other contexts are treated just like a regular `const`, so they are
+    /// lumped into the same category.
+    Const,
+}
+
+impl ConstContext {
+    /// A description of this const context that can appear between backticks in an error message.
+    ///
+    /// E.g. `const` or `static mut`.
+    pub fn keyword_name(self) -> &'static str {
+        match self {
+            Self::Const => "const",
+            Self::Static(Mutability::Not) => "static",
+            Self::Static(Mutability::Mut) => "static mut",
+            Self::ConstFn => "const fn",
+        }
+    }
+}
+
+/// A colloquial, trivially pluralizable description of this const context for use in error
+/// messages.
+impl fmt::Display for ConstContext {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            Self::Const => write!(f, "constant"),
+            Self::Static(_) => write!(f, "static"),
+            Self::ConstFn => write!(f, "constant function"),
+        }
+    }
+}
+
 /// A literal.
 pub type Lit = Spanned<LitKind>;
 
diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs
index 1c71fc57bea..235d1d80192 100644
--- a/src/librustc_middle/hir/map/mod.rs
+++ b/src/librustc_middle/hir/map/mod.rs
@@ -408,6 +408,9 @@ impl<'hir> Map<'hir> {
         })
     }
 
+    /// Returns the `BodyOwnerKind` of this `LocalDefId`.
+    ///
+    /// Panics if `LocalDefId` does not have an associated body.
     pub fn body_owner_kind(&self, id: HirId) -> BodyOwnerKind {
         match self.get(id) {
             Node::Item(&Item { kind: ItemKind::Const(..), .. })
@@ -424,6 +427,23 @@ impl<'hir> Map<'hir> {
         }
     }
 
+    /// Returns the `ConstContext` of the body associated with this `LocalDefId`.
+    ///
+    /// Panics if `LocalDefId` does not have an associated body.
+    pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> {
+        let hir_id = self.local_def_id_to_hir_id(did);
+        let ccx = match self.body_owner_kind(hir_id) {
+            BodyOwnerKind::Const => ConstContext::Const,
+            BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
+
+            BodyOwnerKind::Fn if self.tcx.is_constructor(did.to_def_id()) => return None,
+            BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(did.to_def_id()) => ConstContext::ConstFn,
+            BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
+        };
+
+        Some(ccx)
+    }
+
     pub fn ty_param_owner(&self, id: HirId) -> HirId {
         match self.get(id) {
             Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => id,
diff --git a/src/librustc_mir/borrow_check/def_use.rs b/src/librustc_mir/borrow_check/def_use.rs
new file mode 100644
index 00000000000..689ec249a2f
--- /dev/null
+++ b/src/librustc_mir/borrow_check/def_use.rs
@@ -0,0 +1,78 @@
+use rustc_middle::mir::visit::{
+    MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext,
+};
+
+#[derive(Eq, PartialEq, Clone)]
+pub enum DefUse {
+    Def,
+    Use,
+    Drop,
+}
+
+pub fn categorize(context: PlaceContext) -> Option<DefUse> {
+    match context {
+        ///////////////////////////////////////////////////////////////////////////
+        // DEFS
+
+        PlaceContext::MutatingUse(MutatingUseContext::Store) |
+
+        // This is potentially both a def and a use...
+        PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
+
+        // We let Call define the result in both the success and
+        // unwind cases. This is not really correct, however it
+        // does not seem to be observable due to the way that we
+        // generate MIR. To do things properly, we would apply
+        // the def in call only to the input from the success
+        // path and not the unwind path. -nmatsakis
+        PlaceContext::MutatingUse(MutatingUseContext::Call) |
+        PlaceContext::MutatingUse(MutatingUseContext::Yield) |
+
+        // Storage live and storage dead aren't proper defines, but we can ignore
+        // values that come before them.
+        PlaceContext::NonUse(NonUseContext::StorageLive) |
+        PlaceContext::NonUse(NonUseContext::StorageDead) => Some(DefUse::Def),
+
+        ///////////////////////////////////////////////////////////////////////////
+        // REGULAR USES
+        //
+        // These are uses that occur *outside* of a drop. For the
+        // purposes of NLL, these are special in that **all** the
+        // lifetimes appearing in the variable must be live for each regular use.
+
+        PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) |
+        PlaceContext::MutatingUse(MutatingUseContext::Projection) |
+
+        // Borrows only consider their local used at the point of the borrow.
+        // This won't affect the results since we use this analysis for generators
+        // and we only care about the result at suspension points. Borrows cannot
+        // cross suspension points so this behavior is unproblematic.
+        PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
+        PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
+        PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
+        PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
+
+        PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
+        PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
+        PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
+        PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
+        PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
+        PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
+        PlaceContext::MutatingUse(MutatingUseContext::Retag) =>
+            Some(DefUse::Use),
+
+        ///////////////////////////////////////////////////////////////////////////
+        // DROP USES
+        //
+        // These are uses that occur in a DROP (a MIR drop, not a
+        // call to `std::mem::drop()`). For the purposes of NLL,
+        // uses in drop are special because `#[may_dangle]`
+        // attributes can affect whether lifetimes must be live.
+
+        PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
+            Some(DefUse::Drop),
+
+        // Debug info is neither def nor use.
+        PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
+    }
+}
diff --git a/src/librustc_mir/borrow_check/diagnostics/find_use.rs b/src/librustc_mir/borrow_check/diagnostics/find_use.rs
index 6c6bde8ae2c..8d8cdfb5293 100644
--- a/src/librustc_mir/borrow_check/diagnostics/find_use.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/find_use.rs
@@ -2,10 +2,10 @@ use std::collections::VecDeque;
 use std::rc::Rc;
 
 use crate::borrow_check::{
+    def_use::{self, DefUse},
     nll::ToRegionVid,
     region_infer::{Cause, RegionInferenceContext},
 };
-use crate::util::liveness::{self, DefUse};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location};
@@ -117,7 +117,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> {
         });
 
         if found_it {
-            self.def_use_result = match liveness::categorize(context) {
+            self.def_use_result = match def_use::categorize(context) {
                 Some(DefUse::Def) => Some(DefUseResult::Def),
                 Some(DefUse::Use) => Some(DefUseResult::UseLive { local }),
                 Some(DefUse::Drop) => Some(DefUseResult::UseDrop { local }),
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 465aa5847af..457f0f8444b 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -51,6 +51,7 @@ use self::path_utils::*;
 mod borrow_set;
 mod constraint_generation;
 mod constraints;
+mod def_use;
 mod diagnostics;
 mod facts;
 mod invalidation;
diff --git a/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs
index 0fdf96710c6..995e3a60a0c 100644
--- a/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs
+++ b/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs
@@ -3,8 +3,7 @@ use rustc_index::vec::IndexVec;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location};
 
-use crate::util::liveness::{categorize, DefUse};
-
+use crate::borrow_check::def_use::{self, DefUse};
 use crate::borrow_check::region_infer::values::{PointIndex, RegionValueElements};
 
 /// A map that cross references each local with the locations where it
@@ -160,7 +159,7 @@ impl LocalUseMapBuild<'_> {
 impl Visitor<'tcx> for LocalUseMapBuild<'_> {
     fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
         if self.locals_with_use_data[local] {
-            match categorize(context) {
+            match def_use::categorize(context) {
                 Some(DefUse::Def) => self.insert_def(local, location),
                 Some(DefUse::Use) => self.insert_use(local, location),
                 Some(DefUse::Drop) => self.insert_drop(local, location),
diff --git a/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs b/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs
index 2e033896ce1..d285098c52a 100644
--- a/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs
+++ b/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs
@@ -1,7 +1,7 @@
+use crate::borrow_check::def_use::{self, DefUse};
 use crate::borrow_check::location::{LocationIndex, LocationTable};
 use crate::dataflow::indexes::MovePathIndex;
 use crate::dataflow::move_paths::{LookupResult, MoveData};
-use crate::util::liveness::{categorize, DefUse};
 use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location, Place};
 use rustc_middle::ty::subst::GenericArg;
@@ -56,7 +56,7 @@ impl UseFactsExtractor<'_> {
 
 impl Visitor<'tcx> for UseFactsExtractor<'_> {
     fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
-        match categorize(context) {
+        match def_use::categorize(context) {
             Some(DefUse::Def) => self.insert_def(local, location),
             Some(DefUse::Use) => self.insert_use(local, location),
             Some(DefUse::Drop) => self.insert_drop_use(local, location),
diff --git a/src/librustc_mir/dataflow/impls/liveness.rs b/src/librustc_mir/dataflow/impls/liveness.rs
index 5e9bec89ac0..d24faacd377 100644
--- a/src/librustc_mir/dataflow/impls/liveness.rs
+++ b/src/librustc_mir/dataflow/impls/liveness.rs
@@ -6,6 +6,13 @@ use crate::dataflow::{AnalysisDomain, Backward, BottomValue, GenKill, GenKillAna
 
 /// A [live-variable dataflow analysis][liveness].
 ///
+/// This analysis considers references as being used only at the point of the
+/// borrow. In other words, this analysis does not track uses because of references that already
+/// exist. See [this `mir-datalow` test][flow-test] for an example. You almost never want to use
+/// this analysis without also looking at the results of [`MaybeBorrowedLocals`].
+///
+/// [`MaybeBorrowedLocals`]: ../struct.MaybeBorrowedLocals.html
+/// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs
 /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
 pub struct MaybeLiveLocals;
 
diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs
index 46a46aa5ae9..7c439f80ef6 100644
--- a/src/librustc_mir/transform/check_consts/mod.rs
+++ b/src/librustc_mir/transform/check_consts/mod.rs
@@ -9,8 +9,6 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, TyCtxt};
 
-use std::fmt;
-
 pub use self::qualifs::Qualif;
 
 mod ops;
@@ -25,7 +23,7 @@ pub struct ConstCx<'mir, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
     pub def_id: DefId,
     pub param_env: ty::ParamEnv<'tcx>,
-    pub const_kind: Option<ConstKind>,
+    pub const_kind: Option<hir::ConstContext>,
 }
 
 impl ConstCx<'mir, 'tcx> {
@@ -40,78 +38,18 @@ impl ConstCx<'mir, 'tcx> {
         body: &'mir mir::Body<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Self {
-        let const_kind = ConstKind::for_item(tcx, def_id);
-
+        let const_kind = tcx.hir().body_const_context(def_id);
         ConstCx { body, tcx, def_id: def_id.to_def_id(), param_env, const_kind }
     }
 
     /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.).
     ///
     /// Panics if this `Item` is not const.
-    pub fn const_kind(&self) -> ConstKind {
+    pub fn const_kind(&self) -> hir::ConstContext {
         self.const_kind.expect("`const_kind` must not be called on a non-const fn")
     }
 }
 
-/// The kinds of items which require compile-time evaluation.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum ConstKind {
-    /// A `static` item.
-    Static,
-    /// A `static mut` item.
-    StaticMut,
-    /// A `const fn` item.
-    ConstFn,
-    /// A `const` item or an anonymous constant (e.g. in array lengths).
-    Const,
-}
-
-impl ConstKind {
-    /// Returns the validation mode for the item with the given `DefId`, or `None` if this item
-    /// does not require validation (e.g. a non-const `fn`).
-    pub fn for_item(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<Self> {
-        use hir::BodyOwnerKind as HirKind;
-
-        let hir_id = tcx.hir().as_local_hir_id(def_id);
-
-        let mode = match tcx.hir().body_owner_kind(hir_id) {
-            HirKind::Closure => return None,
-
-            // Note: this is deliberately checking for `is_const_fn_raw`, as the `is_const_fn`
-            // checks take into account the `rustc_const_unstable` attribute combined with enabled
-            // feature gates. Otherwise, const qualification would _not check_ whether this
-            // function body follows the `const fn` rules, as an unstable `const fn` would
-            // be considered "not const". More details are available in issue #67053.
-            HirKind::Fn if tcx.is_const_fn_raw(def_id) => ConstKind::ConstFn,
-            HirKind::Fn => return None,
-
-            HirKind::Const => ConstKind::Const,
-
-            HirKind::Static(hir::Mutability::Not) => ConstKind::Static,
-            HirKind::Static(hir::Mutability::Mut) => ConstKind::StaticMut,
-        };
-
-        Some(mode)
-    }
-
-    pub fn is_static(self) -> bool {
-        match self {
-            ConstKind::Static | ConstKind::StaticMut => true,
-            ConstKind::ConstFn | ConstKind::Const => false,
-        }
-    }
-}
-
-impl fmt::Display for ConstKind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            ConstKind::Const => write!(f, "constant"),
-            ConstKind::Static | ConstKind::StaticMut => write!(f, "static"),
-            ConstKind::ConstFn => write!(f, "constant function"),
-        }
-    }
-}
-
 /// Returns `true` if this `DefId` points to one of the official `panic` lang items.
 pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
     Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn()
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index bb6e3681cc3..28743ee8e36 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -1,13 +1,14 @@
 //! Concrete error types for all operations which may be invalid in a certain const context.
 
 use rustc_errors::struct_span_err;
+use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_session::config::nightly_options;
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
 
-use super::{ConstCx, ConstKind};
+use super::ConstCx;
 
 /// An operation that is not *always* allowed in a const context.
 pub trait NonConstOp: std::fmt::Debug {
@@ -326,7 +327,7 @@ impl NonConstOp for RawPtrToIntCast {
 pub struct StaticAccess;
 impl NonConstOp for StaticAccess {
     fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
-        ccx.const_kind().is_static()
+        matches!(ccx.const_kind(), hir::ConstContext::Static(_))
     }
 
     fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) {
@@ -374,7 +375,7 @@ pub struct UnionAccess;
 impl NonConstOp for UnionAccess {
     fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool {
         // Union accesses are stable in all contexts except `const fn`.
-        ccx.const_kind() != ConstKind::ConstFn
+        ccx.const_kind() != hir::ConstContext::ConstFn
             || ccx.tcx.features().enabled(Self::feature_gate().unwrap())
     }
 
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 1d03606f253..896ce981f92 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -1,7 +1,7 @@
 //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
 
 use rustc_errors::struct_span_err;
-use rustc_hir::lang_items;
+use rustc_hir::{self as hir, lang_items};
 use rustc_hir::{def_id::DefId, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
@@ -18,7 +18,7 @@ use std::ops::Deref;
 use super::ops::{self, NonConstOp};
 use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
 use super::resolver::FlowSensitiveAnalysis;
-use super::{is_lang_panic_fn, ConstCx, ConstKind, Qualif};
+use super::{is_lang_panic_fn, ConstCx, Qualif};
 use crate::const_eval::{is_const_fn, is_unstable_const_fn};
 use crate::dataflow::impls::MaybeMutBorrowedLocals;
 use crate::dataflow::{self, Analysis};
@@ -145,17 +145,13 @@ impl Qualifs<'mir, 'tcx> {
             // We don't care whether a `const fn` returns a value that is not structurally
             // matchable. Functions calls are opaque and always use type-based qualification, so
             // this value should never be used.
-            ConstKind::ConstFn => true,
+            hir::ConstContext::ConstFn => true,
 
             // If we know that all values of the return type are structurally matchable, there's no
             // need to run dataflow.
-            ConstKind::Const | ConstKind::Static | ConstKind::StaticMut
-                if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
-            {
-                false
-            }
+            _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false,
 
-            ConstKind::Const | ConstKind::Static | ConstKind::StaticMut => {
+            hir::ConstContext::Const | hir::ConstContext::Static(_) => {
                 let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
                     .into_engine(ccx.tcx, &ccx.body, ccx.def_id)
                     .iterate_to_fixpoint()
@@ -198,7 +194,7 @@ impl Validator<'mir, 'tcx> {
     pub fn check_body(&mut self) {
         let ConstCx { tcx, body, def_id, const_kind, .. } = *self.ccx;
 
-        let use_min_const_fn_checks = (const_kind == Some(ConstKind::ConstFn)
+        let use_min_const_fn_checks = (const_kind == Some(hir::ConstContext::ConstFn)
             && crate::const_eval::is_min_const_fn(tcx, def_id))
             && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
 
@@ -222,8 +218,9 @@ impl Validator<'mir, 'tcx> {
         self.visit_body(&body);
 
         // Ensure that the end result is `Sync` in a non-thread local `static`.
-        let should_check_for_sync =
-            const_kind == Some(ConstKind::Static) && !tcx.is_thread_local_static(def_id);
+        let should_check_for_sync = const_kind
+            == Some(hir::ConstContext::Static(hir::Mutability::Not))
+            && !tcx.is_thread_local_static(def_id);
 
         if should_check_for_sync {
             let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
@@ -351,7 +348,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 let ty = place.ty(self.body, self.tcx).ty;
                 let is_allowed = match ty.kind {
                     // Inside a `static mut`, `&mut [...]` is allowed.
-                    ty::Array(..) | ty::Slice(_) if self.const_kind() == ConstKind::StaticMut => {
+                    ty::Array(..) | ty::Slice(_)
+                        if self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut) =>
+                    {
                         true
                     }
 
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 1d982d18eeb..02356a43699 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -182,7 +182,7 @@ pub fn run_passes(
 }
 
 fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
-    let const_kind = check_consts::ConstKind::for_item(tcx, def_id.expect_local());
+    let const_kind = tcx.hir().body_const_context(def_id.expect_local());
 
     // No need to const-check a non-const `fn`.
     if const_kind.is_none() {
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index ad98920eb63..467e4188814 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -13,6 +13,7 @@
 //! move analysis runs after promotion on broken MIR.
 
 use rustc_ast::ast::LitKind;
+use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::traversal::ReversePostorder;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
@@ -30,7 +31,7 @@ use std::cell::Cell;
 use std::{cmp, iter, mem};
 
 use crate::const_eval::{is_const_fn, is_unstable_const_fn};
-use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx, ConstKind};
+use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx};
 use crate::transform::{MirPass, MirSource};
 
 /// A `MirPass` for promotion.
@@ -352,7 +353,9 @@ impl<'tcx> Validator<'_, 'tcx> {
                             // In theory, any zero-sized value could be borrowed
                             // mutably without consequences. However, only &mut []
                             // is allowed right now, and only in functions.
-                            if self.const_kind == Some(ConstKind::StaticMut) {
+                            if self.const_kind
+                                == Some(hir::ConstContext::Static(hir::Mutability::Mut))
+                            {
                                 // Inside a `static mut`, &mut [...] is also allowed.
                                 match ty.kind {
                                     ty::Array(..) | ty::Slice(_) => {}
@@ -517,7 +520,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                 if let Some(def_id) = c.check_static_ptr(self.tcx) {
                     // Only allow statics (not consts) to refer to other statics.
                     // FIXME(eddyb) does this matter at all for promotion?
-                    let is_static = self.const_kind.map_or(false, |k| k.is_static());
+                    let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_)));
                     if !is_static {
                         return Err(Unpromotable);
                     }
@@ -607,7 +610,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                     // In theory, any zero-sized value could be borrowed
                     // mutably without consequences. However, only &mut []
                     // is allowed right now, and only in functions.
-                    if self.const_kind == Some(ConstKind::StaticMut) {
+                    if self.const_kind == Some(hir::ConstContext::Static(hir::Mutability::Mut)) {
                         // Inside a `static mut`, &mut [...] is also allowed.
                         match ty.kind {
                             ty::Array(..) | ty::Slice(_) => {}
diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs
deleted file mode 100644
index c261219cc73..00000000000
--- a/src/librustc_mir/util/liveness.rs
+++ /dev/null
@@ -1,326 +0,0 @@
-//! Liveness analysis which computes liveness of MIR local variables at the boundary of basic
-//! blocks.
-//!
-//! This analysis considers references as being used only at the point of the
-//! borrow. This means that this does not track uses because of references that
-//! already exist:
-//!
-//! ```rust
-//! fn foo() {
-//!     x = 0;
-//!     // `x` is live here ...
-//!     GLOBAL = &x: *const u32;
-//!     // ... but not here, even while it can be accessed through `GLOBAL`.
-//!     foo();
-//!     x = 1;
-//!     // `x` is live again here, because it is assigned to `OTHER_GLOBAL`.
-//!     OTHER_GLOBAL = &x: *const u32;
-//!     // ...
-//! }
-//! ```
-//!
-//! This means that users of this analysis still have to check whether
-//! pre-existing references can be used to access the value (e.g., at movable
-//! generator yield points, all pre-existing references are invalidated, so this
-//! doesn't matter).
-
-use crate::transform::MirSource;
-use crate::util::pretty::{dump_enabled, write_basic_block, write_mir_intro};
-use rustc_data_structures::work_queue::WorkQueue;
-use rustc_index::bit_set::BitSet;
-use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::mir::visit::{
-    MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, Visitor,
-};
-use rustc_middle::mir::Local;
-use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt};
-use std::fs;
-use std::io::{self, BufWriter, Write};
-use std::path::{Path, PathBuf};
-
-pub type LiveVarSet = BitSet<Local>;
-
-/// This gives the result of the liveness analysis at the boundary of
-/// basic blocks.
-///
-/// The `V` type defines the set of variables that we computed
-/// liveness for. This is often `Local`, in which case we computed
-/// liveness for all variables -- but it can also be some other type,
-/// which indicates a subset of the variables within the graph.
-pub struct LivenessResult {
-    /// Live variables on exit to each basic block. This is equal to
-    /// the union of the `ins` for each successor.
-    pub outs: IndexVec<BasicBlock, LiveVarSet>,
-}
-
-/// Computes which local variables are live within the given function
-/// `mir`, including drops.
-pub fn liveness_of_locals(body: &Body<'_>) -> LivenessResult {
-    let num_live_vars = body.local_decls.len();
-
-    let def_use: IndexVec<_, DefsUses> =
-        body.basic_blocks().iter().map(|b| block(b, num_live_vars)).collect();
-
-    let mut outs: IndexVec<_, LiveVarSet> =
-        body.basic_blocks().indices().map(|_| LiveVarSet::new_empty(num_live_vars)).collect();
-
-    let mut bits = LiveVarSet::new_empty(num_live_vars);
-
-    // The dirty queue contains the set of basic blocks whose entry sets have changed since they
-    // were last processed. At the start of the analysis, we initialize the queue in post-order to
-    // make it more likely that the entry set for a given basic block will have the effects of all
-    // its successors in the CFG applied before it is processed.
-    //
-    // FIXME(ecstaticmorse): Reverse post-order on the reverse CFG may generate a better iteration
-    // order when cycles are present, but the overhead of computing the reverse CFG may outweigh
-    // any benefits. Benchmark this and find out.
-    let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks().len());
-    for (bb, _) in traversal::postorder(&body) {
-        dirty_queue.insert(bb);
-    }
-
-    // Add blocks which are not reachable from START_BLOCK to the work queue. These blocks will
-    // be processed after the ones added above.
-    for bb in body.basic_blocks().indices() {
-        dirty_queue.insert(bb);
-    }
-
-    let predecessors = body.predecessors();
-
-    while let Some(bb) = dirty_queue.pop() {
-        // bits = use ∪ (bits - def)
-        bits.overwrite(&outs[bb]);
-        def_use[bb].apply(&mut bits);
-
-        // `bits` now contains the live variables on entry. Therefore,
-        // add `bits` to the `out` set for each predecessor; if those
-        // bits were not already present, then enqueue the predecessor
-        // as dirty.
-        //
-        // (note that `union` returns true if the `self` set changed)
-        for &pred_bb in &predecessors[bb] {
-            if outs[pred_bb].union(&bits) {
-                dirty_queue.insert(pred_bb);
-            }
-        }
-    }
-
-    LivenessResult { outs }
-}
-
-#[derive(Eq, PartialEq, Clone)]
-pub enum DefUse {
-    Def,
-    Use,
-    Drop,
-}
-
-pub fn categorize(context: PlaceContext) -> Option<DefUse> {
-    match context {
-        ///////////////////////////////////////////////////////////////////////////
-        // DEFS
-
-        PlaceContext::MutatingUse(MutatingUseContext::Store) |
-
-        // This is potentially both a def and a use...
-        PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
-
-        // We let Call define the result in both the success and
-        // unwind cases. This is not really correct, however it
-        // does not seem to be observable due to the way that we
-        // generate MIR. To do things properly, we would apply
-        // the def in call only to the input from the success
-        // path and not the unwind path. -nmatsakis
-        PlaceContext::MutatingUse(MutatingUseContext::Call) |
-        PlaceContext::MutatingUse(MutatingUseContext::Yield) |
-
-        // Storage live and storage dead aren't proper defines, but we can ignore
-        // values that come before them.
-        PlaceContext::NonUse(NonUseContext::StorageLive) |
-        PlaceContext::NonUse(NonUseContext::StorageDead) => Some(DefUse::Def),
-
-        ///////////////////////////////////////////////////////////////////////////
-        // REGULAR USES
-        //
-        // These are uses that occur *outside* of a drop. For the
-        // purposes of NLL, these are special in that **all** the
-        // lifetimes appearing in the variable must be live for each regular use.
-
-        PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) |
-        PlaceContext::MutatingUse(MutatingUseContext::Projection) |
-
-        // Borrows only consider their local used at the point of the borrow.
-        // This won't affect the results since we use this analysis for generators
-        // and we only care about the result at suspension points. Borrows cannot
-        // cross suspension points so this behavior is unproblematic.
-        PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
-        PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
-        PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
-        PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
-
-        PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
-        PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
-        PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
-        PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
-        PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
-        PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
-        PlaceContext::MutatingUse(MutatingUseContext::Retag) =>
-            Some(DefUse::Use),
-
-        ///////////////////////////////////////////////////////////////////////////
-        // DROP USES
-        //
-        // These are uses that occur in a DROP (a MIR drop, not a
-        // call to `std::mem::drop()`). For the purposes of NLL,
-        // uses in drop are special because `#[may_dangle]`
-        // attributes can affect whether lifetimes must be live.
-
-        PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
-            Some(DefUse::Drop),
-
-        // Debug info is neither def nor use.
-        PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
-    }
-}
-
-struct DefsUsesVisitor {
-    defs_uses: DefsUses,
-}
-
-#[derive(Eq, PartialEq, Clone)]
-struct DefsUses {
-    defs: LiveVarSet,
-    uses: LiveVarSet,
-}
-
-impl DefsUses {
-    fn apply(&self, bits: &mut LiveVarSet) -> bool {
-        bits.subtract(&self.defs) | bits.union(&self.uses)
-    }
-
-    fn add_def(&mut self, index: Local) {
-        // If it was used already in the block, remove that use
-        // now that we found a definition.
-        //
-        // Example:
-        //
-        //     // Defs = {X}, Uses = {}
-        //     X = 5
-        //     // Defs = {}, Uses = {X}
-        //     use(X)
-        self.uses.remove(index);
-        self.defs.insert(index);
-    }
-
-    fn add_use(&mut self, index: Local) {
-        // Inverse of above.
-        //
-        // Example:
-        //
-        //     // Defs = {}, Uses = {X}
-        //     use(X)
-        //     // Defs = {X}, Uses = {}
-        //     X = 5
-        //     // Defs = {}, Uses = {X}
-        //     use(X)
-        self.defs.remove(index);
-        self.uses.insert(index);
-    }
-}
-
-impl<'tcx> Visitor<'tcx> for DefsUsesVisitor {
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
-        match categorize(context) {
-            Some(DefUse::Def) => self.defs_uses.add_def(local),
-            Some(DefUse::Use | DefUse::Drop) => self.defs_uses.add_use(local),
-            _ => (),
-        }
-    }
-}
-
-fn block(b: &BasicBlockData<'_>, locals: usize) -> DefsUses {
-    let mut visitor = DefsUsesVisitor {
-        defs_uses: DefsUses {
-            defs: LiveVarSet::new_empty(locals),
-            uses: LiveVarSet::new_empty(locals),
-        },
-    };
-
-    let dummy_location = Location { block: BasicBlock::new(0), statement_index: 0 };
-
-    // Visit the various parts of the basic block in reverse. If we go
-    // forward, the logic in `add_def` and `add_use` would be wrong.
-    visitor.visit_terminator(b.terminator(), dummy_location);
-    for statement in b.statements.iter().rev() {
-        visitor.visit_statement(statement, dummy_location);
-    }
-
-    visitor.defs_uses
-}
-
-pub fn dump_mir<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    pass_name: &str,
-    source: MirSource<'tcx>,
-    body: &Body<'tcx>,
-    result: &LivenessResult,
-) {
-    if !dump_enabled(tcx, pass_name, source.def_id()) {
-        return;
-    }
-    let node_path = ty::print::with_forced_impl_filename_line(|| {
-        // see notes on #41697 below
-        tcx.def_path_str(source.def_id())
-    });
-    dump_matched_mir_node(tcx, pass_name, &node_path, source, body, result);
-}
-
-fn dump_matched_mir_node<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    pass_name: &str,
-    node_path: &str,
-    source: MirSource<'tcx>,
-    body: &Body<'tcx>,
-    result: &LivenessResult,
-) {
-    let mut file_path = PathBuf::new();
-    file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir));
-    let item_id = tcx.hir().as_local_hir_id(source.def_id().expect_local());
-    let file_name = format!("rustc.node{}{}-liveness.mir", item_id, pass_name);
-    file_path.push(&file_name);
-    let _ = fs::File::create(&file_path).and_then(|file| {
-        let mut file = BufWriter::new(file);
-        writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?;
-        writeln!(file, "// source = {:?}", source)?;
-        writeln!(file, "// pass_name = {}", pass_name)?;
-        writeln!(file)?;
-        write_mir_fn(tcx, source, body, &mut file, result)?;
-        Ok(())
-    });
-}
-
-pub fn write_mir_fn<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    src: MirSource<'tcx>,
-    body: &Body<'tcx>,
-    w: &mut dyn Write,
-    result: &LivenessResult,
-) -> io::Result<()> {
-    write_mir_intro(tcx, src, body, w)?;
-    for block in body.basic_blocks().indices() {
-        let print = |w: &mut dyn Write, prefix, result: &IndexVec<BasicBlock, LiveVarSet>| {
-            let live: Vec<String> =
-                result[block].iter().map(|local| format!("{:?}", local)).collect();
-            writeln!(w, "{} {{{}}}", prefix, live.join(", "))
-        };
-        write_basic_block(tcx, block, body, &mut |_, _| Ok(()), w)?;
-        print(w, "   ", &result.outs)?;
-        if block.index() + 1 != body.basic_blocks().len() {
-            writeln!(w)?;
-        }
-    }
-
-    writeln!(w, "}}")?;
-    Ok(())
-}
diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs
index 3e501193e8d..8bbe207c077 100644
--- a/src/librustc_mir/util/mod.rs
+++ b/src/librustc_mir/util/mod.rs
@@ -8,7 +8,6 @@ pub mod storage;
 mod alignment;
 pub mod collect_writes;
 mod graphviz;
-pub mod liveness;
 pub(crate) mod pretty;
 
 pub use self::aggregate::expand_aggregate;
diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs
index c42f2fc264a..94f9c619a3a 100644
--- a/src/librustc_passes/check_const.rs
+++ b/src/librustc_passes/check_const.rs
@@ -7,7 +7,6 @@
 //! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips
 //! through, but errors for structured control flow in a `const` should be emitted here.
 
-use rustc_ast::ast::Mutability;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -19,8 +18,6 @@ use rustc_session::config::nightly_options;
 use rustc_session::parse::feature_err;
 use rustc_span::{sym, Span, Symbol};
 
-use std::fmt;
-
 /// An expression that is not *always* legal in a const context.
 #[derive(Clone, Copy)]
 enum NonConstExpr {
@@ -65,46 +62,6 @@ impl NonConstExpr {
     }
 }
 
-#[derive(Copy, Clone)]
-enum ConstKind {
-    Static,
-    StaticMut,
-    ConstFn,
-    Const,
-    AnonConst,
-}
-
-impl ConstKind {
-    fn for_body(body: &hir::Body<'_>, tcx: TyCtxt<'_>) -> Option<Self> {
-        let owner = tcx.hir().body_owner(body.id());
-        let const_kind = match tcx.hir().body_owner_kind(owner) {
-            hir::BodyOwnerKind::Const => Self::Const,
-            hir::BodyOwnerKind::Static(Mutability::Mut) => Self::StaticMut,
-            hir::BodyOwnerKind::Static(Mutability::Not) => Self::Static,
-
-            hir::BodyOwnerKind::Fn if tcx.is_const_fn_raw(tcx.hir().local_def_id(owner)) => {
-                Self::ConstFn
-            }
-            hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => return None,
-        };
-
-        Some(const_kind)
-    }
-}
-
-impl fmt::Display for ConstKind {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let s = match self {
-            Self::Static => "static",
-            Self::StaticMut => "static mut",
-            Self::Const | Self::AnonConst => "const",
-            Self::ConstFn => "const fn",
-        };
-
-        write!(f, "{}", s)
-    }
-}
-
 fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: DefId) {
     let mut vis = CheckConstVisitor::new(tcx);
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
@@ -117,7 +74,7 @@ pub(crate) fn provide(providers: &mut Providers<'_>) {
 #[derive(Copy, Clone)]
 struct CheckConstVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    const_kind: Option<ConstKind>,
+    const_kind: Option<hir::ConstContext>,
 }
 
 impl<'tcx> CheckConstVisitor<'tcx> {
@@ -147,7 +104,8 @@ impl<'tcx> CheckConstVisitor<'tcx> {
         let const_kind = self
             .const_kind
             .expect("`const_check_violated` may only be called inside a const context");
-        let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind);
+
+        let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
 
         let required_gates = required_gates.unwrap_or(&[]);
         let missing_gates: Vec<_> =
@@ -191,7 +149,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
     }
 
     /// Saves the parent `const_kind` before calling `f` and restores it afterwards.
-    fn recurse_into(&mut self, kind: Option<ConstKind>, f: impl FnOnce(&mut Self)) {
+    fn recurse_into(&mut self, kind: Option<hir::ConstContext>, f: impl FnOnce(&mut Self)) {
         let parent_kind = self.const_kind;
         self.const_kind = kind;
         f(self);
@@ -207,12 +165,13 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
     }
 
     fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
-        let kind = Some(ConstKind::AnonConst);
+        let kind = Some(hir::ConstContext::Const);
         self.recurse_into(kind, |this| intravisit::walk_anon_const(this, anon));
     }
 
     fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
-        let kind = ConstKind::for_body(body, self.tcx);
+        let owner = self.tcx.hir().body_owner_def_id(body.id());
+        let kind = self.tcx.hir().body_const_context(owner);
         self.recurse_into(kind, |this| intravisit::walk_body(this, body));
     }
 
diff --git a/src/test/ui/const-generics/trait-const-args.rs b/src/test/ui/const-generics/trait-const-args.rs
new file mode 100644
index 00000000000..b60d7e89651
--- /dev/null
+++ b/src/test/ui/const-generics/trait-const-args.rs
@@ -0,0 +1,29 @@
+// check-pass
+#![allow(incomplete_features)]
+#![feature(const_generics)]
+
+struct Const<const N: usize>;
+trait Foo<const N: usize> {}
+
+impl<const N: usize> Foo<N> for Const<N> {}
+
+fn foo_impl(_: impl Foo<3>) {}
+
+fn foo_explicit<T: Foo<3>>(_: T) {}
+
+fn foo_where<T>(_: T)
+where
+    T: Foo<3>,
+{
+}
+
+fn main() {
+    foo_impl(Const);
+    foo_impl(Const::<3>);
+
+    foo_explicit(Const);
+    foo_explicit(Const::<3>);
+
+    foo_where(Const);
+    foo_where(Const::<3>);
+}
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr
index 0c328a2594a..8dbfeff7972 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr
@@ -5,7 +5,7 @@ LL |     const N: i32 = T::N << 42;
    |                    ^^^^^^^^^^ attempt to shift left with overflow
    |
 note: the lint level is defined here
-  --> $DIR/lint-exceeding-bitshifts.rs:8:9
+  --> $DIR/lint-exceeding-bitshifts.rs:9:9
    |
 LL | #![warn(arithmetic_overflow, const_err)]
    |         ^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr
index 0c328a2594a..8dbfeff7972 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr
@@ -5,7 +5,7 @@ LL |     const N: i32 = T::N << 42;
    |                    ^^^^^^^^^^ attempt to shift left with overflow
    |
 note: the lint level is defined here
-  --> $DIR/lint-exceeding-bitshifts.rs:8:9
+  --> $DIR/lint-exceeding-bitshifts.rs:9:9
    |
 LL | #![warn(arithmetic_overflow, const_err)]
    |         ^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr
index 0c328a2594a..8dbfeff7972 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr
@@ -5,7 +5,7 @@ LL |     const N: i32 = T::N << 42;
    |                    ^^^^^^^^^^ attempt to shift left with overflow
    |
 note: the lint level is defined here
-  --> $DIR/lint-exceeding-bitshifts.rs:8:9
+  --> $DIR/lint-exceeding-bitshifts.rs:9:9
    |
 LL | #![warn(arithmetic_overflow, const_err)]
    |         ^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.rs b/src/test/ui/lint/lint-exceeding-bitshifts.rs
index 565bef49c9f..4d56d103a83 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts.rs
+++ b/src/test/ui/lint/lint-exceeding-bitshifts.rs
@@ -3,11 +3,11 @@
 //[opt]compile-flags: -O
 //[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O
 // build-pass
+// ignore-pass (test emits codegen-time warnings and verifies that they are not errors)
 
 #![crate_type="lib"]
 #![warn(arithmetic_overflow, const_err)]
-#![allow(unused_variables)]
-#![allow(dead_code)]
+
 
 pub trait Foo {
     const N: i32;