about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-06-03 08:43:11 +0000
committerbors <bors@rust-lang.org>2020-06-03 08:43:11 +0000
commitff4aff6ce0f216c8cb8d40f432efaacdaca8095b (patch)
tree1097d9453861691c8d3e743b439a15b69f0de4e5 /src
parent680a4b2fbdca0dc6c5ceec826a8dbeabe28f305d (diff)
parent631ac9c472322077304d9acc4de21220c54c56db (diff)
downloadrust-ff4aff6ce0f216c8cb8d40f432efaacdaca8095b.tar.gz
rust-ff4aff6ce0f216c8cb8d40f432efaacdaca8095b.zip
Auto merge of #70107 - lcnr:issue68977, r=eddyb
WF-check all ty::Const's, not just array lengths.

fixes #68977

This PR removes the special case for array length in `wf::compute` and
checks the well formedness of all consts.

Changes `PredicateKind::WellFormed` to take a `GenericArg` and updates `wf::obligations`.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_infer/infer/combine.rs2
-rw-r--r--src/librustc_middle/ty/mod.rs4
-rw-r--r--src/librustc_middle/ty/print/pretty.rs2
-rw-r--r--src/librustc_middle/ty/structural_impls.rs2
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs6
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs18
-rw-r--r--src/librustc_trait_selection/traits/fulfill.rs6
-rw-r--r--src/librustc_trait_selection/traits/select.rs4
-rw-r--r--src/librustc_trait_selection/traits/wf.rs188
-rw-r--r--src/librustc_traits/chalk/lowering.rs41
-rw-r--r--src/librustc_traits/implied_outlives_bounds.rs12
-rw-r--r--src/librustc_traits/type_op.rs4
-rw-r--r--src/librustc_typeck/check/callee.rs2
-rw-r--r--src/librustc_typeck/check/method/confirm.rs2
-rw-r--r--src/librustc_typeck/check/method/mod.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs55
-rw-r--r--src/librustc_typeck/check/wfcheck.rs18
-rw-r--r--src/librustc_typeck/impl_wf_check/min_specialization.rs4
-rw-r--r--src/test/ui/const-generics/cannot-infer-const-args.stderr4
-rw-r--r--src/test/ui/const-generics/issues/issue-61747.rs3
-rw-r--r--src/test/ui/const-generics/issues/issue-61747.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-61935.rs3
-rw-r--r--src/test/ui/const-generics/issues/issue-61935.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-62220.rs4
-rw-r--r--src/test/ui/const-generics/issues/issue-62220.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-66205.rs4
-rw-r--r--src/test/ui/const-generics/issues/issue-66205.stderr11
-rw-r--r--src/test/ui/const-generics/issues/issue-68977.rs40
-rw-r--r--src/test/ui/const-generics/issues/issue-68977.stderr19
-rw-r--r--src/test/ui/const-generics/lazy-normalization/issue-71922.rs4
-rw-r--r--src/test/ui/const-generics/lazy-normalization/issue-71922.stderr19
-rw-r--r--src/test/ui/const-generics/wf-misc.rs16
-rw-r--r--src/test/ui/const-generics/wf-misc.stderr27
33 files changed, 386 insertions, 174 deletions
diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs
index 70a2122a9ea..4ef4ed47cb1 100644
--- a/src/librustc_infer/infer/combine.rs
+++ b/src/librustc_infer/infer/combine.rs
@@ -307,7 +307,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
             self.obligations.push(Obligation::new(
                 self.trace.cause.clone(),
                 self.param_env,
-                ty::PredicateKind::WellFormed(b_ty).to_predicate(self.infcx.tcx),
+                ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx),
             ));
         }
 
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 4cd3be932de..a34cff06bc1 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -14,7 +14,7 @@ use crate::mir::Body;
 use crate::mir::GeneratorLayout;
 use crate::traits::{self, Reveal};
 use crate::ty;
-use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
+use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::util::{Discr, IntTypeExt};
 use rustc_ast::ast;
 use rustc_attr as attr;
@@ -1061,7 +1061,7 @@ pub enum PredicateKind<'tcx> {
     Projection(PolyProjectionPredicate<'tcx>),
 
     /// No syntax: `T` well-formed.
-    WellFormed(Ty<'tcx>),
+    WellFormed(GenericArg<'tcx>),
 
     /// Trait must be object-safe.
     ObjectSafe(DefId),
diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs
index 6a11e775c8c..90fb1981617 100644
--- a/src/librustc_middle/ty/print/pretty.rs
+++ b/src/librustc_middle/ty/print/pretty.rs
@@ -2031,7 +2031,7 @@ define_print_and_forward_display! {
             ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)),
             ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)),
             ty::PredicateKind::Projection(predicate) => p!(print(predicate)),
-            ty::PredicateKind::WellFormed(ty) => p!(print(ty), write(" well-formed")),
+            ty::PredicateKind::WellFormed(arg) => p!(print(arg), write(" well-formed")),
             &ty::PredicateKind::ObjectSafe(trait_def_id) => {
                 p!(write("the trait `"),
                    print_def_path(trait_def_id, &[]),
diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs
index aa47c6b70a2..cee0afacb68 100644
--- a/src/librustc_middle/ty/structural_impls.rs
+++ b/src/librustc_middle/ty/structural_impls.rs
@@ -236,7 +236,7 @@ impl fmt::Debug for ty::PredicateKind<'tcx> {
             ty::PredicateKind::RegionOutlives(ref pair) => pair.fmt(f),
             ty::PredicateKind::TypeOutlives(ref pair) => pair.fmt(f),
             ty::PredicateKind::Projection(ref pair) => pair.fmt(f),
-            ty::PredicateKind::WellFormed(ty) => write!(f, "WellFormed({:?})", ty),
+            ty::PredicateKind::WellFormed(data) => write!(f, "WellFormed({:?})", data),
             ty::PredicateKind::ObjectSafe(trait_def_id) => {
                 write!(f, "ObjectSafe({:?})", trait_def_id)
             }
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index fdc3b291ba4..377a0b6f25c 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -1016,7 +1016,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     }
 
                     self.prove_predicate(
-                        ty::PredicateKind::WellFormed(inferred_ty).to_predicate(self.tcx()),
+                        ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()),
                         Locations::All(span),
                         ConstraintCategory::TypeAnnotation,
                     );
@@ -1268,7 +1268,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     obligations.obligations.push(traits::Obligation::new(
                         ObligationCause::dummy(),
                         param_env,
-                        ty::PredicateKind::WellFormed(revealed_ty).to_predicate(infcx.tcx),
+                        ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx),
                     ));
                     obligations.add(
                         infcx
@@ -1612,7 +1612,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.check_call_dest(body, term, &sig, destination, term_location);
 
                 self.prove_predicates(
-                    sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty)),
+                    sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())),
                     term_location.to_locations(),
                     ConstraintCategory::Boring,
                 );
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index f8b33b782c0..41811bf44b1 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -19,6 +19,7 @@ use rustc_hir::Node;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::fold::TypeFolder;
+use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{
     self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
     TypeFoldable, WithConstness,
@@ -1531,13 +1532,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 err
             }
 
-            ty::PredicateKind::WellFormed(ty) => {
+            ty::PredicateKind::WellFormed(arg) => {
                 // Same hacky approach as above to avoid deluging user
                 // with error messages.
-                if ty.references_error() || self.tcx.sess.has_errors() {
+                if arg.references_error() || self.tcx.sess.has_errors() {
                     return;
                 }
-                self.need_type_info_err(body_id, span, ty, ErrorCode::E0282)
+
+                match arg.unpack() {
+                    GenericArgKind::Lifetime(lt) => {
+                        span_bug!(span, "unexpected well formed predicate: {:?}", lt)
+                    }
+                    GenericArgKind::Type(ty) => {
+                        self.need_type_info_err(body_id, span, ty, ErrorCode::E0282)
+                    }
+                    GenericArgKind::Const(ct) => {
+                        self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282)
+                    }
+                }
             }
 
             ty::PredicateKind::Subtype(ref data) => {
diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs
index c1d9b0a2d88..51c62dbb88c 100644
--- a/src/librustc_trait_selection/traits/fulfill.rs
+++ b/src/librustc_trait_selection/traits/fulfill.rs
@@ -459,17 +459,17 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
                 }
             }
 
-            &ty::PredicateKind::WellFormed(ty) => {
+            &ty::PredicateKind::WellFormed(arg) => {
                 match wf::obligations(
                     self.selcx.infcx(),
                     obligation.param_env,
                     obligation.cause.body_id,
-                    ty,
+                    arg,
                     obligation.cause.span,
                 ) {
                     None => {
                         pending_obligation.stalled_on =
-                            vec![TyOrConstInferVar::maybe_from_ty(ty).unwrap()];
+                            vec![TyOrConstInferVar::maybe_from_generic_arg(arg).unwrap()];
                         ProcessResult::Unchanged
                     }
                     Some(os) => ProcessResult::Changed(mk_pending(os)),
diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs
index 7aa5aa2dae8..517433b90ee 100644
--- a/src/librustc_trait_selection/traits/select.rs
+++ b/src/librustc_trait_selection/traits/select.rs
@@ -436,11 +436,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
             }
 
-            &ty::PredicateKind::WellFormed(ty) => match wf::obligations(
+            &ty::PredicateKind::WellFormed(arg) => match wf::obligations(
                 self.infcx,
                 obligation.param_env,
                 obligation.cause.body_id,
-                ty,
+                arg,
                 obligation.cause.span,
             ) {
                 Some(mut obligations) => {
diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs
index 39c7528a632..5024392a0f9 100644
--- a/src/librustc_trait_selection/traits/wf.rs
+++ b/src/librustc_trait_selection/traits/wf.rs
@@ -4,14 +4,14 @@ use crate::traits;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items;
-use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_span::Span;
 use std::rc::Rc;
 
-/// Returns the set of obligations needed to make `ty` well-formed.
-/// If `ty` contains unresolved inference variables, this may include
-/// further WF obligations. However, if `ty` IS an unresolved
+/// Returns the set of obligations needed to make `arg` well-formed.
+/// If `arg` contains unresolved inference variables, this may include
+/// further WF obligations. However, if `arg` IS an unresolved
 /// inference variable, returns `None`, because we are not able to
 /// make any progress at all. This is to prevent "livelock" where we
 /// say "$0 is WF if $0 is WF".
@@ -19,29 +19,51 @@ pub fn obligations<'a, 'tcx>(
     infcx: &InferCtxt<'a, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     body_id: hir::HirId,
-    ty: Ty<'tcx>,
+    arg: GenericArg<'tcx>,
     span: Span,
 ) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
     // Handle the "livelock" case (see comment above) by bailing out if necessary.
-    let ty = match ty.kind {
-        ty::Infer(ty::TyVar(_)) => {
-            let resolved_ty = infcx.shallow_resolve(ty);
-            if resolved_ty == ty {
-                // No progress, bail out to prevent "livelock".
-                return None;
+    let arg = match arg.unpack() {
+        GenericArgKind::Type(ty) => {
+            match ty.kind {
+                ty::Infer(ty::TyVar(_)) => {
+                    let resolved_ty = infcx.shallow_resolve(ty);
+                    if resolved_ty == ty {
+                        // No progress, bail out to prevent "livelock".
+                        return None;
+                    }
+
+                    resolved_ty
+                }
+                _ => ty,
             }
+            .into()
+        }
+        GenericArgKind::Const(ct) => {
+            match ct.val {
+                ty::ConstKind::Infer(infer) => {
+                    let resolved = infcx.shallow_resolve(infer);
+                    if resolved == infer {
+                        // No progress.
+                        return None;
+                    }
 
-            resolved_ty
+                    infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ty: ct.ty })
+                }
+                _ => ct,
+            }
+            .into()
         }
-        _ => ty,
+        // There is nothing we have to do for lifetimes.
+        GenericArgKind::Lifetime(..) => return Some(Vec::new()),
     };
 
     let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
-    wf.compute(ty);
-    debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
+    wf.compute(arg);
+    debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
 
     let result = wf.normalize();
-    debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result);
+    debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", arg, body_id, result);
     Some(result)
 }
 
@@ -78,33 +100,33 @@ pub fn predicate_obligations<'a, 'tcx>(
         }
         ty::PredicateKind::RegionOutlives(..) => {}
         ty::PredicateKind::TypeOutlives(t) => {
-            wf.compute(t.skip_binder().0);
+            wf.compute(t.skip_binder().0.into());
         }
         ty::PredicateKind::Projection(t) => {
             let t = t.skip_binder(); // (*)
             wf.compute_projection(t.projection_ty);
-            wf.compute(t.ty);
+            wf.compute(t.ty.into());
         }
-        &ty::PredicateKind::WellFormed(t) => {
-            wf.compute(t);
+        &ty::PredicateKind::WellFormed(arg) => {
+            wf.compute(arg);
         }
         ty::PredicateKind::ObjectSafe(_) => {}
         ty::PredicateKind::ClosureKind(..) => {}
         ty::PredicateKind::Subtype(data) => {
-            wf.compute(data.skip_binder().a); // (*)
-            wf.compute(data.skip_binder().b); // (*)
+            wf.compute(data.skip_binder().a.into()); // (*)
+            wf.compute(data.skip_binder().b.into()); // (*)
         }
         &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
             let obligations = wf.nominal_obligations(def_id, substs);
             wf.out.extend(obligations);
 
-            for ty in substs.types() {
-                wf.compute(ty);
+            for arg in substs.iter() {
+                wf.compute(arg);
             }
         }
-        ty::PredicateKind::ConstEquate(c1, c2) => {
-            wf.compute(c1.ty);
-            wf.compute(c2.ty);
+        &ty::PredicateKind::ConstEquate(c1, c2) => {
+            wf.compute(c1.into());
+            wf.compute(c2.into());
         }
     }
 
@@ -213,7 +235,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         self.infcx.tcx
     }
 
-    fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
+    fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
         traits::ObligationCause::new(self.span, self.body_id, code)
     }
 
@@ -273,15 +295,22 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         }
 
         let tcx = self.tcx();
-        self.out.extend(trait_ref.substs.types().filter(|ty| !ty.has_escaping_bound_vars()).map(
-            |ty| {
-                traits::Obligation::new(
-                    cause.clone(),
-                    param_env,
-                    ty::PredicateKind::WellFormed(ty).to_predicate(tcx),
-                )
-            },
-        ));
+        self.out.extend(
+            trait_ref
+                .substs
+                .iter()
+                .filter(|arg| {
+                    matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
+                })
+                .filter(|arg| !arg.has_escaping_bound_vars())
+                .map(|arg| {
+                    traits::Obligation::new(
+                        cause.clone(),
+                        param_env,
+                        ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
+                    )
+                }),
+        );
     }
 
     /// Pushes the obligations required for `trait_ref::Item` to be WF
@@ -300,22 +329,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         }
     }
 
-    /// Pushes the obligations required for an array length to be WF
-    /// into `self.out`.
-    fn compute_array_len(&mut self, constant: ty::Const<'tcx>) {
-        if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val {
-            assert!(promoted.is_none());
-
-            let obligations = self.nominal_obligations(def_id, substs);
-            self.out.extend(obligations);
-
-            let predicate =
-                ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx());
-            let cause = self.cause(traits::MiscObligation);
-            self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
-        }
-    }
-
     fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
         if !subty.has_escaping_bound_vars() {
             let cause = self.cause(cause);
@@ -332,8 +345,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
     }
 
     /// Pushes all the predicates needed to validate that `ty` is WF into `out`.
-    fn compute(&mut self, ty: Ty<'tcx>) {
-        let mut walker = ty.walk();
+    fn compute(&mut self, arg: GenericArg<'tcx>) {
+        let mut walker = arg.walk();
         let param_env = self.param_env;
         while let Some(arg) = walker.next() {
             let ty = match arg.unpack() {
@@ -343,9 +356,53 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                 // obligations are handled by the parent (e.g. `ty::Ref`).
                 GenericArgKind::Lifetime(_) => continue,
 
-                // FIXME(eddyb) this is wrong and needs to be replaced
-                // (see https://github.com/rust-lang/rust/pull/70107).
-                GenericArgKind::Const(_) => continue,
+                GenericArgKind::Const(constant) => {
+                    match constant.val {
+                        ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
+                            assert!(promoted.is_none());
+
+                            let obligations = self.nominal_obligations(def_id, substs);
+                            self.out.extend(obligations);
+
+                            let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs)
+                                .to_predicate(self.tcx());
+                            let cause = self.cause(traits::MiscObligation);
+                            self.out.push(traits::Obligation::new(
+                                cause,
+                                self.param_env,
+                                predicate,
+                            ));
+                        }
+                        ty::ConstKind::Infer(infer) => {
+                            let resolved = self.infcx.shallow_resolve(infer);
+                            // the `InferConst` changed, meaning that we made progress.
+                            if resolved != infer {
+                                let cause = self.cause(traits::MiscObligation);
+
+                                let resolved_constant = self.infcx.tcx.mk_const(ty::Const {
+                                    val: ty::ConstKind::Infer(resolved),
+                                    ..*constant
+                                });
+                                self.out.push(traits::Obligation::new(
+                                    cause,
+                                    self.param_env,
+                                    ty::PredicateKind::WellFormed(resolved_constant.into())
+                                        .to_predicate(self.tcx()),
+                                ));
+                            }
+                        }
+                        ty::ConstKind::Error
+                        | ty::ConstKind::Param(_)
+                        | ty::ConstKind::Bound(..)
+                        | ty::ConstKind::Placeholder(..) => {
+                            // These variants are trivially WF, so nothing to do here.
+                        }
+                        ty::ConstKind::Value(..) => {
+                            // FIXME: Enforce that values are structurally-matchable.
+                        }
+                    }
+                    continue;
+                }
             };
 
             match ty.kind {
@@ -375,10 +432,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     self.require_sized(subty, traits::SliceOrArrayElem);
                 }
 
-                ty::Array(subty, len) => {
+                ty::Array(subty, _) => {
                     self.require_sized(subty, traits::SliceOrArrayElem);
-                    // FIXME(eddyb) handle `GenericArgKind::Const` above instead.
-                    self.compute_array_len(*len);
+                    // Note that we handle the len is implicitly checked while walking `arg`.
                 }
 
                 ty::Tuple(ref tys) => {
@@ -390,11 +446,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                 }
 
                 ty::RawPtr(_) => {
-                    // simple cases that are WF if their type args are WF
+                    // Simple cases that are WF if their type args are WF.
                 }
 
                 ty::Projection(data) => {
-                    walker.skip_current_subtree(); // subtree handled by compute_projection
+                    walker.skip_current_subtree(); // Subtree handled by compute_projection.
                     self.compute_projection(data);
                 }
 
@@ -467,7 +523,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     walker.skip_current_subtree(); // subtree handled below
                     for upvar_ty in substs.as_closure().upvar_tys() {
                         // FIXME(eddyb) add the type to `walker` instead of recursing.
-                        self.compute(upvar_ty);
+                        self.compute(upvar_ty.into());
                     }
                 }
 
@@ -535,12 +591,12 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                         self.out.push(traits::Obligation::new(
                             cause,
                             param_env,
-                            ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx()),
+                            ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
                         ));
                     } else {
                         // Yes, resolved, proceed with the result.
                         // FIXME(eddyb) add the type to `walker` instead of recursing.
-                        self.compute(ty);
+                        self.compute(ty.into());
                     }
                 }
             }
diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs
index a33ada2fb6e..9530b07e47c 100644
--- a/src/librustc_traits/chalk/lowering.rs
+++ b/src/librustc_traits/chalk/lowering.rs
@@ -36,7 +36,7 @@ use rustc_middle::traits::{
     ChalkRustInterner as RustInterner,
 };
 use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::subst::{GenericArg, SubstsRef};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{
     self, Binder, BoundRegion, Region, RegionKind, Ty, TyCtxt, TyKind, TypeFoldable, TypeVisitor,
 };
@@ -77,7 +77,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
     ) -> chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>> {
         let clauses = self.environment.into_iter().filter_map(|clause| match clause {
             ChalkEnvironmentClause::Predicate(predicate) => {
-                match &predicate.kind() {
+                match predicate.kind() {
                     ty::PredicateKind::Trait(predicate, _) => {
                         let (predicate, binders, _named_regions) =
                             collect_bound_vars(interner, interner.tcx, predicate);
@@ -165,24 +165,31 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
                 chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
             }
             ty::PredicateKind::Projection(predicate) => predicate.lower_into(interner),
-            ty::PredicateKind::WellFormed(ty) => match ty.kind {
-                // These types are always WF.
-                ty::Str | ty::Placeholder(..) | ty::Error | ty::Never => {
-                    chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
-                }
+            ty::PredicateKind::WellFormed(arg) => match arg.unpack() {
+                GenericArgKind::Type(ty) => match ty.kind {
+                    // These types are always WF.
+                    ty::Str | ty::Placeholder(..) | ty::Error | ty::Never => {
+                        chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
+                    }
 
-                // FIXME(chalk): Well-formed only if ref lifetime outlives type
-                ty::Ref(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)),
+                    // FIXME(chalk): Well-formed only if ref lifetime outlives type
+                    ty::Ref(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)),
 
-                ty::Param(..) => panic!("No Params expected."),
+                    ty::Param(..) => panic!("No Params expected."),
 
-                // FIXME(chalk) -- ultimately I think this is what we
-                // want to do, and we just have rules for how to prove
-                // `WellFormed` for everything above, instead of
-                // inlining a bit the rules of the proof here.
-                _ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed(
-                    chalk_ir::WellFormed::Ty(ty.lower_into(interner)),
-                )),
+                    // FIXME(chalk) -- ultimately I think this is what we
+                    // want to do, and we just have rules for how to prove
+                    // `WellFormed` for everything above, instead of
+                    // inlining a bit the rules of the proof here.
+                    _ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed(
+                        chalk_ir::WellFormed::Ty(ty.lower_into(interner)),
+                    )),
+                },
+                // FIXME(chalk): handle well formed consts
+                GenericArgKind::Const(..) => {
+                    chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
+                }
+                GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt),
             },
 
             // FIXME(chalk): other predicates
diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs
index 5dee71a2338..651596d0379 100644
--- a/src/librustc_traits/implied_outlives_bounds.rs
+++ b/src/librustc_traits/implied_outlives_bounds.rs
@@ -47,14 +47,14 @@ fn compute_implied_outlives_bounds<'tcx>(
     // process it next. Currently (at least) these resulting
     // predicates are always guaranteed to be a subset of the original
     // type, so we need not fear non-termination.
-    let mut wf_types = vec![ty];
+    let mut wf_args = vec![ty.into()];
 
     let mut implied_bounds = vec![];
 
     let mut fulfill_cx = FulfillmentContext::new();
 
-    while let Some(ty) = wf_types.pop() {
-        // Compute the obligations for `ty` to be well-formed. If `ty` is
+    while let Some(arg) = wf_args.pop() {
+        // Compute the obligations for `arg` to be well-formed. If `arg` is
         // an unresolved inference variable, just substituted an empty set
         // -- because the return type here is going to be things we *add*
         // to the environment, it's always ok for this set to be smaller
@@ -62,7 +62,7 @@ fn compute_implied_outlives_bounds<'tcx>(
         // unresolved inference variables here anyway, but there might be
         // during typeck under some circumstances.)
         let obligations =
-            wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, ty, DUMMY_SP).unwrap_or(vec![]);
+            wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, arg, DUMMY_SP).unwrap_or(vec![]);
 
         // N.B., all of these predicates *ought* to be easily proven
         // true. In fact, their correctness is (mostly) implied by
@@ -103,8 +103,8 @@ fn compute_implied_outlives_bounds<'tcx>(
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..) => vec![],
 
-                ty::PredicateKind::WellFormed(subty) => {
-                    wf_types.push(subty);
+                &ty::PredicateKind::WellFormed(arg) => {
+                    wf_args.push(arg);
                     vec![]
                 }
 
diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs
index 22077b49c3b..374ef3fc9c7 100644
--- a/src/librustc_traits/type_op.rs
+++ b/src/librustc_traits/type_op.rs
@@ -140,7 +140,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
             self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
 
             self.prove_predicate(
-                ty::PredicateKind::WellFormed(impl_self_ty).to_predicate(self.tcx()),
+                ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
             );
         }
 
@@ -155,7 +155,7 @@ impl AscribeUserTypeCx<'me, 'tcx> {
         // them?  This would only be relevant if some input
         // type were ill-formed but did not appear in `ty`,
         // which...could happen with normalization...
-        self.prove_predicate(ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx()));
+        self.prove_predicate(ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()));
         Ok(())
     }
 }
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index f4e46a04931..aa316105f7f 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -94,7 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // we must check that return type of called functions is WF:
-        self.register_wf_obligation(output, call_expr.span, traits::MiscObligation);
+        self.register_wf_obligation(output.into(), call_expr.span, traits::MiscObligation);
 
         output
     }
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 48d27387476..007794ce1b7 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -413,7 +413,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // the function type must also be well-formed (this is not
         // implied by the substs being well-formed because of inherent
         // impls and late-bound regions - see issue #28609).
-        self.register_wf_obligation(fty, self.span, traits::MiscObligation);
+        self.register_wf_obligation(fty.into(), self.span, traits::MiscObligation);
     }
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index aae02ea0273..ac3fa15417e 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -401,7 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         obligations.push(traits::Obligation::new(
             cause,
             self.param_env,
-            ty::PredicateKind::WellFormed(method_ty).to_predicate(tcx),
+            ty::PredicateKind::WellFormed(method_ty.into()).to_predicate(tcx),
         ));
 
         let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig };
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a8fa65a135a..ba4bca8cd99 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -121,9 +121,8 @@ use rustc_middle::ty::adjustment::{
 };
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{
-    GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts,
-};
+use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
+use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts};
 use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
 use rustc_middle::ty::{
     self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef,
@@ -3333,7 +3332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
         let t = AstConv::ast_ty_to_ty(self, ast_t);
-        self.register_wf_obligation(t, ast_t.span, traits::MiscObligation);
+        self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation);
         t
     }
 
@@ -3353,28 +3352,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
         let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
         let c = ty::Const::from_anon_const(self.tcx, const_def_id);
-
-        // HACK(eddyb) emulate what a `WellFormedConst` obligation would do.
-        // This code should be replaced with the proper WF handling ASAP.
-        if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
-            assert!(promoted.is_none());
-
-            // HACK(eddyb) let's hope these are always empty.
-            // let obligations = self.nominal_obligations(def_id, substs);
-            // self.out.extend(obligations);
-
-            let cause = traits::ObligationCause::new(
-                self.tcx.def_span(const_def_id.to_def_id()),
-                self.body_id,
-                traits::MiscObligation,
-            );
-            self.register_predicate(traits::Obligation::new(
-                cause,
-                self.param_env,
-                ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx),
-            ));
-        }
-
+        self.register_wf_obligation(
+            c.into(),
+            self.tcx.hir().span(ast_c.hir_id),
+            ObligationCauseCode::MiscObligation,
+        );
         c
     }
 
@@ -3407,11 +3389,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    /// Registers an obligation for checking later, during regionck, that the type `ty` must
-    /// outlive the region `r`.
+    /// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
     pub fn register_wf_obligation(
         &self,
-        ty: Ty<'tcx>,
+        arg: subst::GenericArg<'tcx>,
         span: Span,
         code: traits::ObligationCauseCode<'tcx>,
     ) {
@@ -3420,16 +3401,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.register_predicate(traits::Obligation::new(
             cause,
             self.param_env,
-            ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx),
+            ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx),
         ));
     }
 
-    /// Registers obligations that all types appearing in `substs` are well-formed.
+    /// Registers obligations that all `substs` are well-formed.
     pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) {
-        for ty in substs.types() {
-            if !ty.references_error() {
-                self.register_wf_obligation(ty, expr.span, traits::MiscObligation);
-            }
+        for arg in substs.iter().filter(|arg| {
+            matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
+        }) {
+            self.register_wf_obligation(arg, expr.span, traits::MiscObligation);
         }
     }
 
@@ -3901,8 +3882,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // All the input types from the fn signature must outlive the call
         // so as to validate implied bounds.
-        for (fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) {
-            self.register_wf_obligation(fn_input_ty, arg_expr.span, traits::MiscObligation);
+        for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) {
+            self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
         }
 
         let expected_arg_count = fn_inputs.len();
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index e154184f182..7d9bf975c69 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -292,7 +292,7 @@ fn check_associated_item(
             ty::AssocKind::Const => {
                 let ty = fcx.tcx.type_of(item.def_id);
                 let ty = fcx.normalize_associated_types_in(span, &ty);
-                fcx.register_wf_obligation(ty, span, code.clone());
+                fcx.register_wf_obligation(ty.into(), span, code.clone());
             }
             ty::AssocKind::Fn => {
                 let sig = fcx.tcx.fn_sig(item.def_id);
@@ -313,7 +313,7 @@ fn check_associated_item(
                 if item.defaultness.has_value() {
                     let ty = fcx.tcx.type_of(item.def_id);
                     let ty = fcx.normalize_associated_types_in(span, &ty);
-                    fcx.register_wf_obligation(ty, span, code.clone());
+                    fcx.register_wf_obligation(ty.into(), span, code.clone());
                 }
             }
             ty::AssocKind::OpaqueTy => {
@@ -406,7 +406,7 @@ fn check_type_defn<'tcx, F>(
             // All field types must be well-formed.
             for field in &variant.fields {
                 fcx.register_wf_obligation(
-                    field.ty,
+                    field.ty.into(),
                     field.span,
                     ObligationCauseCode::MiscObligation,
                 )
@@ -601,7 +601,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo
             }
         }
 
-        fcx.register_wf_obligation(item_ty, ty_span, ObligationCauseCode::MiscObligation);
+        fcx.register_wf_obligation(item_ty.into(), ty_span, ObligationCauseCode::MiscObligation);
         if forbid_unsized {
             fcx.register_bound(
                 item_ty,
@@ -650,7 +650,7 @@ fn check_impl<'tcx>(
                 let self_ty = fcx.tcx.type_of(item_def_id);
                 let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty);
                 fcx.register_wf_obligation(
-                    self_ty,
+                    self_ty.into(),
                     ast_self_ty.span,
                     ObligationCauseCode::MiscObligation,
                 );
@@ -698,7 +698,7 @@ fn check_where_clauses<'tcx, 'fcx>(
                 // be sure if it will error or not as user might always specify the other.
                 if !ty.needs_subst() {
                     fcx.register_wf_obligation(
-                        ty,
+                        ty.into(),
                         fcx.tcx.def_span(param.def_id),
                         ObligationCauseCode::MiscObligation,
                     );
@@ -841,13 +841,13 @@ fn check_fn_or_method<'fcx, 'tcx>(
     let sig = fcx.normalize_associated_types_in(span, &sig);
     let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig);
 
-    for (input_ty, span) in sig.inputs().iter().zip(hir_sig.decl.inputs.iter().map(|t| t.span)) {
-        fcx.register_wf_obligation(&input_ty, span, ObligationCauseCode::MiscObligation);
+    for (&input_ty, span) in sig.inputs().iter().zip(hir_sig.decl.inputs.iter().map(|t| t.span)) {
+        fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation);
     }
     implied_bounds.extend(sig.inputs());
 
     fcx.register_wf_obligation(
-        sig.output(),
+        sig.output().into(),
         hir_sig.decl.output.span(),
         ObligationCauseCode::ReturnType,
     );
diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs
index bf9a4d1cb6c..e4bffedd620 100644
--- a/src/librustc_typeck/impl_wf_check/min_specialization.rs
+++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs
@@ -332,12 +332,12 @@ fn check_predicates<'tcx>(
         });
 
     // Include the well-formed predicates of the type parameters of the impl.
-    for ty in tcx.impl_trait_ref(impl1_def_id).unwrap().substs.types() {
+    for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
         if let Some(obligations) = wf::obligations(
             infcx,
             tcx.param_env(impl1_def_id),
             tcx.hir().as_local_hir_id(impl1_def_id),
-            ty,
+            arg,
             span,
         ) {
             impl2_predicates
diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr
index 6696b025855..b29d27e5247 100644
--- a/src/test/ui/const-generics/cannot-infer-const-args.stderr
+++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr
@@ -11,7 +11,9 @@ error[E0282]: type annotations needed
   --> $DIR/cannot-infer-const-args.rs:9:5
    |
 LL |     foo();
-   |     ^^^ cannot infer type for fn item `fn() -> usize {foo::<{_: usize}>}`
+   |     ^^^
+   |
+   = note: unable to infer the value of a const parameter
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs
index 9e0572d3568..cc671163e85 100644
--- a/src/test/ui/const-generics/issues/issue-61747.rs
+++ b/src/test/ui/const-generics/issues/issue-61747.rs
@@ -1,5 +1,3 @@
-// check-pass
-
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
@@ -7,6 +5,7 @@ struct Const<const N: usize>;
 
 impl<const C: usize> Const<{C}> {
     fn successor() -> Const<{C + 1}> {
+        //~^ ERROR constant expression depends on a generic parameter
         Const
     }
 }
diff --git a/src/test/ui/const-generics/issues/issue-61747.stderr b/src/test/ui/const-generics/issues/issue-61747.stderr
index 2e405370dc0..2685d9fdf16 100644
--- a/src/test/ui/const-generics/issues/issue-61747.stderr
+++ b/src/test/ui/const-generics/issues/issue-61747.stderr
@@ -1,5 +1,5 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-61747.rs:3:12
+  --> $DIR/issue-61747.rs:1:12
    |
 LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
@@ -7,5 +7,13 @@ LL | #![feature(const_generics)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-warning: 1 warning emitted
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-61747.rs:7:23
+   |
+LL |     fn successor() -> Const<{C + 1}> {
+   |                       ^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs
index 5c987e63a9e..0d42ff1895c 100644
--- a/src/test/ui/const-generics/issues/issue-61935.rs
+++ b/src/test/ui/const-generics/issues/issue-61935.rs
@@ -1,5 +1,3 @@
-// check-pass
-
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete
 
@@ -8,6 +6,7 @@ trait Foo {}
 impl<const N: usize> Foo for [(); N]
     where
         Self:FooImpl<{N==0}>
+//~^ERROR constant expression depends on a generic parameter
 {}
 
 trait FooImpl<const IS_ZERO: bool>{}
diff --git a/src/test/ui/const-generics/issues/issue-61935.stderr b/src/test/ui/const-generics/issues/issue-61935.stderr
index cf0c0e24a76..a785af5f008 100644
--- a/src/test/ui/const-generics/issues/issue-61935.stderr
+++ b/src/test/ui/const-generics/issues/issue-61935.stderr
@@ -1,5 +1,5 @@
 warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-61935.rs:3:12
+  --> $DIR/issue-61935.rs:1:12
    |
 LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
@@ -7,5 +7,13 @@ LL | #![feature(const_generics)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
 
-warning: 1 warning emitted
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-61935.rs:8:14
+   |
+LL |         Self:FooImpl<{N==0}>
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs
index c95b3063201..5c4a0d31a89 100644
--- a/src/test/ui/const-generics/issues/issue-62220.rs
+++ b/src/test/ui/const-generics/issues/issue-62220.rs
@@ -1,7 +1,6 @@
-// build-pass
 #![allow(incomplete_features)]
-
 #![feature(const_generics)]
+
 pub struct Vector<T, const N: usize>([T; N]);
 
 pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
@@ -9,6 +8,7 @@ pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
 impl<T, const N: usize> Vector<T, { N }> {
     /// Drop the last component and return the vector with one fewer dimension.
     pub fn trunc(self) -> (TruncatedVector<T, { N }>, T) {
+        //~^ ERROR constant expression depends on a generic parameter
         unimplemented!()
     }
 }
diff --git a/src/test/ui/const-generics/issues/issue-62220.stderr b/src/test/ui/const-generics/issues/issue-62220.stderr
new file mode 100644
index 00000000000..d91d2bb326f
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-62220.stderr
@@ -0,0 +1,10 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-62220.rs:10:27
+   |
+LL |     pub fn trunc(self) -> (TruncatedVector<T, { N }>, T) {
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs
index 76bde1815be..7cedf51ca04 100644
--- a/src/test/ui/const-generics/issues/issue-66205.rs
+++ b/src/test/ui/const-generics/issues/issue-66205.rs
@@ -1,6 +1,6 @@
-#![allow(incomplete_features, dead_code, unconditional_recursion)]
+#![allow(dead_code, unconditional_recursion)]
 #![feature(const_generics)]
-#![feature(lazy_normalization_consts)]
+//~^ WARN the feature `const_generics` is incomplete
 
 fn fact<const N: usize>() {
     fact::<{ N - 1 }>();
diff --git a/src/test/ui/const-generics/issues/issue-66205.stderr b/src/test/ui/const-generics/issues/issue-66205.stderr
index 416b675b56d..1e9c0f2f3d9 100644
--- a/src/test/ui/const-generics/issues/issue-66205.stderr
+++ b/src/test/ui/const-generics/issues/issue-66205.stderr
@@ -1,3 +1,12 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-66205.rs:2:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
 error: constant expression depends on a generic parameter
   --> $DIR/issue-66205.rs:6:12
    |
@@ -6,5 +15,5 @@ LL |     fact::<{ N - 1 }>();
    |
    = note: this may fail depending on what value the parameter takes
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/issues/issue-68977.rs b/src/test/ui/const-generics/issues/issue-68977.rs
new file mode 100644
index 00000000000..346ea3c2042
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-68977.rs
@@ -0,0 +1,40 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+
+struct PhantomU8<const X: u8>;
+
+trait FxpStorage {
+    type SInt; // Add arithmetic traits as needed.
+}
+
+macro_rules! fxp_storage_impls {
+    ($($($n:literal)|+ => $sint:ty),* $(,)?) => {
+        $($(impl FxpStorage for PhantomU8<$n> {
+            type SInt = $sint;
+        })*)*
+    }
+}
+
+fxp_storage_impls! {
+    1 => i8,
+    2 => i16,
+    3 | 4 => i32,
+    5 | 6 | 7 | 8 => i64,
+    9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 => i128,
+}
+
+type FxpStorageHelper<const INT_BITS: u8, const FRAC_BITS: u8> =
+    PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
+
+struct Fxp<const INT_BITS: u8, const FRAC_BITS: u8>
+where
+    FxpStorageHelper<INT_BITS, FRAC_BITS>: FxpStorage,
+    //~^ ERROR constant expression depends on a generic parameter
+{
+    storage: <FxpStorageHelper<INT_BITS, FRAC_BITS> as FxpStorage>::SInt,
+}
+
+fn main() {
+    Fxp::<1, 15> { storage: 0i16 };
+    Fxp::<2, 15> { storage: 0i32 };
+}
diff --git a/src/test/ui/const-generics/issues/issue-68977.stderr b/src/test/ui/const-generics/issues/issue-68977.stderr
new file mode 100644
index 00000000000..e1190d9026d
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-68977.stderr
@@ -0,0 +1,19 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-68977.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-68977.rs:31:44
+   |
+LL |     FxpStorageHelper<INT_BITS, FRAC_BITS>: FxpStorage,
+   |                                            ^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/const-generics/lazy-normalization/issue-71922.rs b/src/test/ui/const-generics/lazy-normalization/issue-71922.rs
index 36513f94a9e..0d392ddcaed 100644
--- a/src/test/ui/const-generics/lazy-normalization/issue-71922.rs
+++ b/src/test/ui/const-generics/lazy-normalization/issue-71922.rs
@@ -1,9 +1,9 @@
-// run-pass
 #![feature(const_generics)]
-#![allow(incomplete_features)]
+//~^ WARN the feature `const_generics` is incomplete
 trait Foo {}
 
 impl<const N: usize> Foo for [(); N] where Self: FooImpl<{ N == 0 }> {}
+//~^ ERROR constant expression depends on a generic parameter
 
 trait FooImpl<const IS_ZERO: bool> {}
 
diff --git a/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr b/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr
new file mode 100644
index 00000000000..00917571e71
--- /dev/null
+++ b/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr
@@ -0,0 +1,19 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-71922.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-71922.rs:5:50
+   |
+LL | impl<const N: usize> Foo for [(); N] where Self: FooImpl<{ N == 0 }> {}
+   |                                                  ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/const-generics/wf-misc.rs b/src/test/ui/const-generics/wf-misc.rs
new file mode 100644
index 00000000000..4ff1b9e2da5
--- /dev/null
+++ b/src/test/ui/const-generics/wf-misc.rs
@@ -0,0 +1,16 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+
+pub fn arr_len<const N: usize>() {
+    let _: [u8; N + 1];
+    //~^ ERROR constant expression depends on a generic parameter
+}
+
+struct Const<const N: usize>;
+
+pub fn func_call<const N: usize>() {
+    let _: Const::<{N + 1}>;
+    //~^ ERROR constant expression depends on a generic parameter
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/wf-misc.stderr b/src/test/ui/const-generics/wf-misc.stderr
new file mode 100644
index 00000000000..03f2bf3f526
--- /dev/null
+++ b/src/test/ui/const-generics/wf-misc.stderr
@@ -0,0 +1,27 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/wf-misc.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: constant expression depends on a generic parameter
+  --> $DIR/wf-misc.rs:5:12
+   |
+LL |     let _: [u8; N + 1];
+   |            ^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/wf-misc.rs:12:12
+   |
+LL |     let _: Const::<{N + 1}>;
+   |            ^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors; 1 warning emitted
+