about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_infer/infer/outlives/mod.rs3
-rw-r--r--src/librustc_infer/traits/util.rs5
-rw-r--r--src/librustc_lint/builtin.rs1
-rw-r--r--src/librustc_middle/ty/mod.rs12
-rw-r--r--src/librustc_middle/ty/print/pretty.rs3
-rw-r--r--src/librustc_middle/ty/structural_impls.rs4
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs3
-rw-r--r--src/librustc_trait_selection/opaque_types.rs3
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs18
-rw-r--r--src/librustc_trait_selection/traits/fulfill.rs15
-rw-r--r--src/librustc_trait_selection/traits/object_safety.rs6
-rw-r--r--src/librustc_trait_selection/traits/select.rs14
-rw-r--r--src/librustc_trait_selection/traits/wf.rs26
-rw-r--r--src/librustc_traits/chalk/lowering.rs11
-rw-r--r--src/librustc_traits/implied_outlives_bounds.rs3
-rw-r--r--src/librustc_traits/normalize_erasing_regions.rs3
-rw-r--r--src/librustc_typeck/check/method/probe.rs3
-rw-r--r--src/librustc_typeck/check/mod.rs65
-rw-r--r--src/librustc_typeck/impl_wf_check/min_specialization.rs3
-rw-r--r--src/librustc_typeck/outlives/explicit.rs3
-rw-r--r--src/librustdoc/clean/mod.rs3
-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-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/wf-misc.rs16
-rw-r--r--src/test/ui/const-generics/wf-misc.stderr27
32 files changed, 296 insertions, 61 deletions
diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs
index fd3b38e9d67..ad8e44a6c1d 100644
--- a/src/librustc_infer/infer/outlives/mod.rs
+++ b/src/librustc_infer/infer/outlives/mod.rs
@@ -20,7 +20,8 @@ pub fn explicit_outlives_bounds<'tcx>(
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::TypeOutlives(..)
         | ty::PredicateKind::ConstEvaluatable(..)
-        | ty::PredicateKind::ConstEquate(..) => None,
+        | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::WellFormedConst(..) => None,
         ty::PredicateKind::RegionOutlives(ref data) => data
             .no_bound_vars()
             .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)),
diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs
index 8081cac0067..1aaa07d23cc 100644
--- a/src/librustc_infer/traits/util.rs
+++ b/src/librustc_infer/traits/util.rs
@@ -45,6 +45,8 @@ pub fn anonymize_predicate<'tcx>(
         }
 
         ty::PredicateKind::ConstEquate(c1, c2) => ty::PredicateKind::ConstEquate(c1, c2),
+
+        ty::PredicateKind::WellFormedConst(ct) => ty::PredicateKind::WellFormedConst(ct),
     };
 
     if new != *kind { new.to_predicate(tcx) } else { pred }
@@ -204,6 +206,9 @@ impl Elaborator<'tcx> {
                 // Currently, we do not elaborate const-equate
                 // predicates.
             }
+            ty::PredicateKind::WellFormedConst(..) => {
+                // Currently, we do not elaborate WF predicates.
+            }
             ty::PredicateKind::RegionOutlives(..) => {
                 // Nothing to elaborate from `'a: 'b`.
             }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index e17e8b7b964..bde761b01c3 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1218,6 +1218,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
                     Projection(..) |
                     // Ignore bounds that a user can't type
                     WellFormed(..) |
+                    WellFormedConst(..) |
                     ObjectSafe(..) |
                     ClosureKind(..) |
                     Subtype(..) |
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 4cd3be932de..554553dc6b4 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -1079,6 +1079,9 @@ pub enum PredicateKind<'tcx> {
 
     /// Constants must be equal. The first component is the const that is expected.
     ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
+
+    /// Constant must be well formed.
+    WellFormedConst(&'tcx Const<'tcx>),
 }
 
 /// The crate outlives map is computed during typeck and contains the
@@ -1195,6 +1198,9 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::ConstEquate(c1, c2) => {
                 PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs))
             }
+            PredicateKind::WellFormedConst(c) => {
+                PredicateKind::WellFormedConst(c.subst(tcx, substs))
+            }
         };
 
         if new != *kind { new.to_predicate(tcx) } else { self }
@@ -1386,7 +1392,8 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::ClosureKind(..)
             | PredicateKind::TypeOutlives(..)
             | PredicateKind::ConstEvaluatable(..)
-            | PredicateKind::ConstEquate(..) => None,
+            | PredicateKind::ConstEquate(..)
+            | PredicateKind::WellFormedConst(..) => None,
         }
     }
 
@@ -1401,7 +1408,8 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::ObjectSafe(..)
             | PredicateKind::ClosureKind(..)
             | PredicateKind::ConstEvaluatable(..)
-            | PredicateKind::ConstEquate(..) => None,
+            | PredicateKind::ConstEquate(..)
+            | PredicateKind::WellFormedConst(..) => None,
         }
     }
 }
diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs
index 6a11e775c8c..6eb11b0c942 100644
--- a/src/librustc_middle/ty/print/pretty.rs
+++ b/src/librustc_middle/ty/print/pretty.rs
@@ -2054,6 +2054,9 @@ define_print_and_forward_display! {
                    print(c2),
                    write("`"))
             }
+            ty::PredicateKind::WellFormedConst(c) => {
+                p!(print(c), write(" well-formed"))
+            }
         }
     }
 
diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs
index c6ecb08615f..19a2e89ca41 100644
--- a/src/librustc_middle/ty/structural_impls.rs
+++ b/src/librustc_middle/ty/structural_impls.rs
@@ -247,6 +247,7 @@ impl fmt::Debug for ty::PredicateKind<'tcx> {
                 write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
             }
             ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
+            ty::PredicateKind::WellFormedConst(c) => write!(f, "WellFormedConst({:?})", c),
         }
     }
 }
@@ -507,6 +508,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
             ty::PredicateKind::ConstEquate(c1, c2) => {
                 tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2))
             }
+            ty::PredicateKind::WellFormedConst(c) => {
+                tcx.lift(&c).map(ty::PredicateKind::WellFormedConst)
+            }
         }
     }
 }
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 5615aa84eec..22959c6a3df 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -29,7 +29,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -
                 | ty::PredicateKind::WellFormed(_)
                 | ty::PredicateKind::Projection(_)
                 | ty::PredicateKind::ConstEvaluatable(..)
-                | ty::PredicateKind::ConstEquate(..) => continue,
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::WellFormedConst(..) => continue,
                 ty::PredicateKind::ObjectSafe(_) => {
                     bug!("object safe predicate on function: {:#?}", predicate)
                 }
diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs
index f78a6207a3a..8bbcfb1ade5 100644
--- a/src/librustc_trait_selection/opaque_types.rs
+++ b/src/librustc_trait_selection/opaque_types.rs
@@ -1277,7 +1277,8 @@ crate fn required_region_bounds(
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::RegionOutlives(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
-                | ty::PredicateKind::ConstEquate(..) => None,
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::WellFormedConst(..) => None,
                 ty::PredicateKind::TypeOutlives(predicate) => {
                     // Search for a bound of the form `erased_self_ty
                     // : 'a`, but be wary of something like `for<'a>
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index f8b33b782c0..1134cafbae4 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -610,6 +610,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         }
                     }
 
+                    ty::PredicateKind::WellFormedConst(ct) => {
+                        // Const WF predicates cannot themselves make
+                        // errors. They can only block due to
+                        // ambiguity; otherwise, they always
+                        // degenerate into other obligations
+                        // (which may fail).
+                        span_bug!(span, "const WF predicate not satisfied for {:?}", ct);
+                    }
+
                     ty::PredicateKind::ConstEvaluatable(..) => {
                         // Errors for `ConstEvaluatable` predicates show up as
                         // `SelectionError::ConstEvalFailure`,
@@ -1540,6 +1549,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 self.need_type_info_err(body_id, span, ty, ErrorCode::E0282)
             }
 
+            ty::PredicateKind::WellFormedConst(ct) => {
+                // Same hacky approach as above to avoid deluging user
+                // with error messages.
+                if ct.references_error() || self.tcx.sess.has_errors() {
+                    return;
+                }
+                self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282)
+            }
+
             ty::PredicateKind::Subtype(ref data) => {
                 if data.references_error() || self.tcx.sess.has_errors() {
                     // no need to overload user in such cases
diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs
index c1d9b0a2d88..8ab81246e7d 100644
--- a/src/librustc_trait_selection/traits/fulfill.rs
+++ b/src/librustc_trait_selection/traits/fulfill.rs
@@ -476,6 +476,21 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
                 }
             }
 
+            ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations(
+                self.selcx.infcx(),
+                obligation.param_env,
+                obligation.cause.body_id,
+                constant,
+                obligation.cause.span,
+            ) {
+                Some(predicates) => ProcessResult::Changed(mk_pending(predicates)),
+                None => {
+                    pending_obligation.stalled_on =
+                        vec![TyOrConstInferVar::maybe_from_const(constant).unwrap()];
+                    ProcessResult::Unchanged
+                }
+            },
+
             &ty::PredicateKind::Subtype(subtype) => {
                 match self.selcx.infcx().subtype_predicate(
                     &obligation.cause,
diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs
index 5befc797a51..ee7aa6b165d 100644
--- a/src/librustc_trait_selection/traits/object_safety.rs
+++ b/src/librustc_trait_selection/traits/object_safety.rs
@@ -283,7 +283,8 @@ fn predicates_reference_self(
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
-                | ty::PredicateKind::ConstEquate(..) => None,
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::WellFormedConst(..) => None,
             }
         })
         .collect()
@@ -318,7 +319,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::TypeOutlives(..)
             | ty::PredicateKind::ConstEvaluatable(..)
-            | ty::PredicateKind::ConstEquate(..) => false,
+            | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::WellFormedConst(..) => false,
         }
     })
 }
diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs
index 7aa5aa2dae8..9dd0592c45f 100644
--- a/src/librustc_trait_selection/traits/select.rs
+++ b/src/librustc_trait_selection/traits/select.rs
@@ -450,6 +450,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 None => Ok(EvaluatedToAmbig),
             },
 
+            ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations(
+                self.infcx,
+                obligation.param_env,
+                obligation.cause.body_id,
+                constant,
+                obligation.cause.span,
+            ) {
+                Some(mut obligations) => {
+                    self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
+                    self.evaluate_predicates_recursively(previous_stack, obligations.into_iter())
+                }
+                None => Ok(EvaluatedToAmbig),
+            },
+
             ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::RegionOutlives(..) => {
                 // We do not consider region relationships when evaluating trait matches.
                 Ok(EvaluatedToOkModuloRegions)
diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs
index 60a88815214..458a6f5b88f 100644
--- a/src/librustc_trait_selection/traits/wf.rs
+++ b/src/librustc_trait_selection/traits/wf.rs
@@ -128,15 +128,15 @@ pub fn predicate_obligations<'a, 'tcx>(
             let obligations = wf.nominal_obligations(def_id, substs);
             wf.out.extend(obligations);
 
-            for subst in substs.iter().copied() {
+            for subst in substs.iter() {
                 wf.compute(subst);
             }
         }
-        ty::PredicateKind::ConstEquate(c1, c2) => {
-            wf.compute(c1.ty.into());
-            wf.compute(c2.ty.into());
+        &ty::PredicateKind::ConstEquate(c1, c2) => {
+            wf.compute(c1.into());
+            wf.compute(c2.into());
         }
-        ty::Predicate::WellFormedConst(constant) => {
+        &ty::PredicateKind::WellFormedConst(constant) => {
             wf.compute(constant.into());
         }
     }
@@ -368,7 +368,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                             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 predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs)
+                                .to_predicate(self.tcx());
                             let cause = self.cause(traits::MiscObligation);
                             self.out.push(traits::Obligation::new(
                                 cause,
@@ -389,11 +390,20 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                                 self.out.push(traits::Obligation::new(
                                     cause,
                                     self.param_env,
-                                    ty::PredicateKind::WellFormedConst(resolved_constant).to_predicate(self.tcx()),
+                                    ty::PredicateKind::WellFormedConst(resolved_constant)
+                                        .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 structually-matchable.
+                        }
                     }
                     continue;
                 }
diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs
index a33ada2fb6e..b624598322a 100644
--- a/src/librustc_traits/chalk/lowering.rs
+++ b/src/librustc_traits/chalk/lowering.rs
@@ -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);
@@ -126,7 +126,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                     | ty::PredicateKind::ClosureKind(..)
                     | ty::PredicateKind::Subtype(..)
                     | ty::PredicateKind::ConstEvaluatable(..)
-                    | ty::PredicateKind::ConstEquate(..) => {
+                    | ty::PredicateKind::ConstEquate(..)
+                    | ty::PredicateKind::WellFormedConst(..) => {
                         bug!("unexpected predicate {}", predicate)
                     }
                 }
@@ -193,7 +194,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::ConstEvaluatable(..)
-            | ty::PredicateKind::ConstEquate(..) => {
+            | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::WellFormedConst(..) => {
                 chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
             }
         }
@@ -460,7 +462,8 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::ConstEvaluatable(..)
-            | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", &self),
+            | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::WellFormedConst(..) => bug!("unexpected predicate {}", &self),
         }
     }
 }
diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs
index 5dee71a2338..073dfe4d592 100644
--- a/src/librustc_traits/implied_outlives_bounds.rs
+++ b/src/librustc_traits/implied_outlives_bounds.rs
@@ -101,7 +101,8 @@ fn compute_implied_outlives_bounds<'tcx>(
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
-                | ty::PredicateKind::ConstEquate(..) => vec![],
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::WellFormedConst(..) => vec![],
 
                 ty::PredicateKind::WellFormed(subty) => {
                     wf_types.push(subty);
diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs
index fcb75142269..6a8d81085c5 100644
--- a/src/librustc_traits/normalize_erasing_regions.rs
+++ b/src/librustc_traits/normalize_erasing_regions.rs
@@ -49,6 +49,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool {
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::Subtype(..)
         | ty::PredicateKind::ConstEvaluatable(..)
-        | ty::PredicateKind::ConstEquate(..) => true,
+        | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::WellFormedConst(..) => true,
     }
 }
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 91562d576ea..c17b3d78125 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -814,7 +814,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::TypeOutlives(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
-                | ty::PredicateKind::ConstEquate(..) => None,
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::WellFormedConst(..) => None,
             });
 
         self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a8fa65a135a..374ba1c7314 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3353,28 +3353,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_const_obligation(
+            c,
+            self.tcx.hir().span(ast_c.hir_id),
+            ObligationCauseCode::MiscObligation,
+        );
         c
     }
 
@@ -3424,11 +3407,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ));
     }
 
-    /// Registers obligations that all types appearing in `substs` are well-formed.
+    /// Registers an obligation for checking later, during regionck, that the type `ty` must
+    /// outlive the region `r`.
+    pub fn register_wf_const_obligation(
+        &self,
+        ct: &'tcx ty::Const<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+    ) {
+        // WF obligations never themselves fail, so no real need to give a detailed cause:
+        let cause = traits::ObligationCause::new(span, self.body_id, code);
+        self.register_predicate(traits::Obligation::new(
+            cause,
+            self.param_env,
+            ty::PredicateKind::WellFormedConst(ct).to_predicate(self.tcx),
+        ));
+    }
+
+    /// 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 subst in substs {
+            match subst.unpack() {
+                GenericArgKind::Lifetime(..) => {
+                    // Nothing to do for lifetimes.
+                }
+                GenericArgKind::Type(ty) => {
+                    if !ty.references_error() {
+                        self.register_wf_obligation(ty, expr.span, traits::MiscObligation);
+                    }
+                }
+                GenericArgKind::Const(ct) => {
+                    if !ct.references_error() {
+                        self.register_wf_const_obligation(ct, expr.span, traits::MiscObligation);
+                    }
+                }
             }
         }
     }
@@ -3860,6 +3872,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ty::PredicateKind::RegionOutlives(..) => None,
                 ty::PredicateKind::TypeOutlives(..) => None,
                 ty::PredicateKind::WellFormed(..) => None,
+                ty::PredicateKind::WellFormedConst(..) => None,
                 ty::PredicateKind::ObjectSafe(..) => None,
                 ty::PredicateKind::ConstEvaluatable(..) => None,
                 ty::PredicateKind::ConstEquate(..) => None,
diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs
index bf9a4d1cb6c..b2e8716b038 100644
--- a/src/librustc_typeck/impl_wf_check/min_specialization.rs
+++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs
@@ -405,6 +405,7 @@ fn trait_predicate_kind<'tcx>(
         | ty::PredicateKind::ObjectSafe(_)
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::ConstEvaluatable(..)
-        | ty::PredicateKind::ConstEquate(..) => None,
+        | ty::PredicateKind::ConstEquate(..)
+        | ty::PredicateKind::WellFormedConst(..) => None,
     }
 }
diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs
index 5740cc224cc..cf8be687f60 100644
--- a/src/librustc_typeck/outlives/explicit.rs
+++ b/src/librustc_typeck/outlives/explicit.rs
@@ -59,7 +59,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
                     | ty::PredicateKind::ClosureKind(..)
                     | ty::PredicateKind::Subtype(..)
                     | ty::PredicateKind::ConstEvaluatable(..)
-                    | ty::PredicateKind::ConstEquate(..) => (),
+                    | ty::PredicateKind::ConstEquate(..)
+                    | ty::PredicateKind::WellFormedConst(..) => (),
                 }
             }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 371df7444b0..5c2d6c6453d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -491,7 +491,8 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
             | ty::PredicateKind::ObjectSafe(..)
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::ConstEvaluatable(..)
-            | ty::PredicateKind::ConstEquate(..) => panic!("not user writable"),
+            | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::WellFormedConst(..) => panic!("not user writable"),
         }
     }
 }
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-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/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
+