From 600607f45a400e5930126b5ef1dc05f5644e95c3 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Sun, 20 Oct 2019 17:16:58 +0100
Subject: [PATCH 1/7] Move `search_for_adt_without_structural_match` to
 `ty/mod`

---
 src/librustc/ty/mod.rs               | 117 ++++++++++++++++++++++++-
 src/librustc_mir/hair/pattern/mod.rs | 122 +--------------------------
 2 files changed, 116 insertions(+), 123 deletions(-)

diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index d377b7328e80b..77d8141c9688c 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -4,7 +4,7 @@ pub use self::Variance::*;
 pub use self::AssocItemContainer::*;
 pub use self::BorrowKind::*;
 pub use self::IntVarValue::*;
-pub use self::fold::TypeFoldable;
+pub use self::fold::{TypeFoldable, TypeVisitor};
 
 use crate::hir::{map as hir_map, GlobMap, TraitMap};
 use crate::hir::Node;
@@ -50,7 +50,7 @@ use syntax::symbol::{kw, sym, Symbol, InternedString};
 use syntax_pos::Span;
 
 use smallvec;
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 use rustc_index::vec::{Idx, IndexVec};
 
@@ -3393,6 +3393,119 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
     fn_like.asyncness()
 }
 
+/// This method traverses the structure of `ty`, trying to find an
+/// instance of an ADT (i.e. struct or enum) that was declared without
+/// the `#[structural_match]` attribute.
+///
+/// The "structure of a type" includes all components that would be
+/// considered when doing a pattern match on a constant of that
+/// type.
+///
+///  * This means this method descends into fields of structs/enums,
+///    and also descends into the inner type `T` of `&T` and `&mut T`
+///
+///  * The traversal doesn't dereference unsafe pointers (`*const T`,
+///    `*mut T`), and it does not visit the type arguments of an
+///    instantiated generic like `PhantomData<T>`.
+///
+/// The reason we do this search is Rust currently require all ADTs
+/// reachable from a constant's type to be annotated with
+/// `#[structural_match]`, an attribute which essentially says that
+/// the implementation of `PartialEq::eq` behaves *equivalently* to a
+/// comparison against the unfolded structure.
+///
+/// For more background on why Rust has this requirement, and issues
+/// that arose when the requirement was not enforced completely, see
+/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
+pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
+                                                 ty: Ty<'tcx>)
+                                                 -> Option<&'tcx AdtDef>
+{
+    let mut search = Search { tcx, found: None, seen: FxHashSet::default() };
+    ty.visit_with(&mut search);
+    return search.found;
+
+    struct Search<'tcx> {
+        tcx: TyCtxt<'tcx>,
+
+        // records the first ADT we find without `#[structural_match`
+        found: Option<&'tcx AdtDef>,
+
+        // tracks ADT's previously encountered during search, so that
+        // we will not recur on them again.
+        seen: FxHashSet<hir::def_id::DefId>,
+    }
+
+    impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
+        fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+            debug!("Search visiting ty: {:?}", ty);
+
+            let (adt_def, substs) = match ty.kind {
+                ty::Adt(adt_def, substs) => (adt_def, substs),
+                ty::RawPtr(..) => {
+                    // `#[structural_match]` ignores substructure of
+                    // `*const _`/`*mut _`, so skip super_visit_with
+                    //
+                    // (But still tell caller to continue search.)
+                    return false;
+                }
+                ty::FnDef(..) | ty::FnPtr(..) => {
+                    // types of formals and return in `fn(_) -> _` are also irrelevant
+                    //
+                    // (But still tell caller to continue search.)
+                    return false;
+                }
+                ty::Array(_, n) if n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0)
+                => {
+                    // rust-lang/rust#62336: ignore type of contents
+                    // for empty array.
+                    return false;
+                }
+                _ => {
+                    ty.super_visit_with(self);
+                    return false;
+                }
+            };
+
+            if !self.tcx.has_attr(adt_def.did, sym::structural_match) {
+                self.found = Some(&adt_def);
+                debug!("Search found adt_def: {:?}", adt_def);
+                return true // Halt visiting!
+            }
+
+            if !self.seen.insert(adt_def.did) {
+                debug!("Search already seen adt_def: {:?}", adt_def);
+                // let caller continue its search
+                return false;
+            }
+
+            // `#[structural_match]` does not care about the
+            // instantiation of the generics in an ADT (it
+            // instead looks directly at its fields outside
+            // this match), so we skip super_visit_with.
+            //
+            // (Must not recur on substs for `PhantomData<T>` cf
+            // rust-lang/rust#55028 and rust-lang/rust#55837; but also
+            // want to skip substs when only uses of generic are
+            // behind unsafe pointers `*const T`/`*mut T`.)
+
+            // even though we skip super_visit_with, we must recur on
+            // fields of ADT.
+            let tcx = self.tcx;
+            for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) {
+                if field_ty.visit_with(self) {
+                    // found an ADT without `#[structural_match]`; halt visiting!
+                    assert!(self.found.is_some());
+                    return true;
+                }
+            }
+
+            // Even though we do not want to recur on substs, we do
+            // want our caller to continue its own search.
+            false
+        }
+    }
+}
 
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
     context::provide(providers);
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 58480912929b3..d996881221857 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -25,7 +25,6 @@ use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 use rustc::hir::ptr::P;
 
 use rustc_index::vec::Idx;
-use rustc_data_structures::fx::FxHashSet;
 
 use std::cmp::Ordering;
 use std::fmt;
@@ -1000,7 +999,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         if self.include_lint_checks && !saw_error {
             // If we were able to successfully convert the const to some pat, double-check
             // that the type of the const obeys `#[structural_match]` constraint.
-            if let Some(adt_def) = search_for_adt_without_structural_match(self.tcx, cv.ty) {
+            if let Some(adt_def) = ty::search_for_adt_without_structural_match(self.tcx, cv.ty) {
 
                 let path = self.tcx.def_path_str(adt_def.did);
                 let msg = format!(
@@ -1169,125 +1168,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     }
 }
 
-/// This method traverses the structure of `ty`, trying to find an
-/// instance of an ADT (i.e. struct or enum) that was declared without
-/// the `#[structural_match]` attribute.
-///
-/// The "structure of a type" includes all components that would be
-/// considered when doing a pattern match on a constant of that
-/// type.
-///
-///  * This means this method descends into fields of structs/enums,
-///    and also descends into the inner type `T` of `&T` and `&mut T`
-///
-///  * The traversal doesn't dereference unsafe pointers (`*const T`,
-///    `*mut T`), and it does not visit the type arguments of an
-///    instantiated generic like `PhantomData<T>`.
-///
-/// The reason we do this search is Rust currently require all ADT's
-/// reachable from a constant's type to be annotated with
-/// `#[structural_match]`, an attribute which essentially says that
-/// the implementation of `PartialEq::eq` behaves *equivalently* to a
-/// comparison against the unfolded structure.
-///
-/// For more background on why Rust has this requirement, and issues
-/// that arose when the requirement was not enforced completely, see
-/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
-fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
-                                                 ty: Ty<'tcx>)
-                                                 -> Option<&'tcx AdtDef>
-{
-    // Import here (not mod level), because `TypeFoldable::fold_with`
-    // conflicts with `PatternFoldable::fold_with`
-    use crate::rustc::ty::fold::TypeVisitor;
-    use crate::rustc::ty::TypeFoldable;
-
-    let mut search = Search { tcx, found: None, seen: FxHashSet::default() };
-    ty.visit_with(&mut search);
-    return search.found;
-
-    struct Search<'tcx> {
-        tcx: TyCtxt<'tcx>,
-
-        // records the first ADT we find without `#[structural_match`
-        found: Option<&'tcx AdtDef>,
-
-        // tracks ADT's previously encountered during search, so that
-        // we will not recur on them again.
-        seen: FxHashSet<hir::def_id::DefId>,
-    }
-
-    impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
-        fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
-            debug!("Search visiting ty: {:?}", ty);
-
-            let (adt_def, substs) = match ty.kind {
-                ty::Adt(adt_def, substs) => (adt_def, substs),
-                ty::RawPtr(..) => {
-                    // `#[structural_match]` ignores substructure of
-                    // `*const _`/`*mut _`, so skip super_visit_with
-                    //
-                    // (But still tell caller to continue search.)
-                    return false;
-                }
-                ty::FnDef(..) | ty::FnPtr(..) => {
-                    // types of formals and return in `fn(_) -> _` are also irrelevant
-                    //
-                    // (But still tell caller to continue search.)
-                    return false;
-                }
-                ty::Array(_, n) if n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0)
-                => {
-                    // rust-lang/rust#62336: ignore type of contents
-                    // for empty array.
-                    return false;
-                }
-                _ => {
-                    ty.super_visit_with(self);
-                    return false;
-                }
-            };
-
-            if !self.tcx.has_attr(adt_def.did, sym::structural_match) {
-                self.found = Some(&adt_def);
-                debug!("Search found adt_def: {:?}", adt_def);
-                return true // Halt visiting!
-            }
-
-            if !self.seen.insert(adt_def.did) {
-                debug!("Search already seen adt_def: {:?}", adt_def);
-                // let caller continue its search
-                return false;
-            }
-
-            // `#[structural_match]` does not care about the
-            // instantiation of the generics in an ADT (it
-            // instead looks directly at its fields outside
-            // this match), so we skip super_visit_with.
-            //
-            // (Must not recur on substs for `PhantomData<T>` cf
-            // rust-lang/rust#55028 and rust-lang/rust#55837; but also
-            // want to skip substs when only uses of generic are
-            // behind unsafe pointers `*const T`/`*mut T`.)
-
-            // even though we skip super_visit_with, we must recur on
-            // fields of ADT.
-            let tcx = self.tcx;
-            for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) {
-                if field_ty.visit_with(self) {
-                    // found an ADT without `#[structural_match]`; halt visiting!
-                    assert!(self.found.is_some());
-                    return true;
-                }
-            }
-
-            // Even though we do not want to recur on substs, we do
-            // want our caller to continue its own search.
-            false
-        }
-    }
-}
-
 impl UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx

From bbd53deaeb79e78162524e18ca29211745e2d18e Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Sun, 20 Oct 2019 17:17:12 +0100
Subject: [PATCH 2/7] Forbid non-`structural_match` types in const generics

---
 src/librustc_typeck/collect.rs                | 11 +++++++++
 src/librustc_typeck/error_codes.rs            | 24 +++++++++++++++++++
 .../forbid-non-structural_match-types.rs      | 13 ++++++++++
 .../forbid-non-structural_match-types.stderr  | 17 +++++++++++++
 4 files changed, 65 insertions(+)
 create mode 100644 src/test/ui/const-generics/forbid-non-structural_match-types.rs
 create mode 100644 src/test/ui/const-generics/forbid-non-structural_match-types.stderr

diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 1749fd1075e05..d6162c0bc0e9f 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1532,6 +1532,17 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                         );
                     };
                 }
+                if ty::search_for_adt_without_structural_match(tcx, ty).is_some() {
+                    struct_span_err!(
+                        tcx.sess,
+                        hir_ty.span,
+                        E0739,
+                        "the types of const generic parameters must derive `PartialEq` and `Eq`",
+                    ).span_label(
+                        hir_ty.span,
+                        format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
+                    ).emit();
+                }
                 ty
             }
             x => {
diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs
index 3ecbf620cbc7b..5d1afcaef9140 100644
--- a/src/librustc_typeck/error_codes.rs
+++ b/src/librustc_typeck/error_codes.rs
@@ -4978,6 +4978,30 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
 [RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
 "##,
 
+E0739: r##"
+Only `structural_match` types (that is, types that derive `PartialEq` and `Eq`)
+may be used as the types of const generic parameters.
+
+```compile_fail,E0739
+#![feature(const_generics)]
+
+struct A;
+
+struct B<const X: A>; // error!
+```
+
+To fix this example, we derive `PartialEq` and `Eq`.
+
+```
+#![feature(const_generics)]
+
+#[derive(PartialEq, Eq)]
+struct A;
+
+struct B<const X: A>; // ok!
+```
+"##,
+
 ;
 //  E0035, merged into E0087/E0089
 //  E0036, merged into E0087/E0089
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.rs b/src/test/ui/const-generics/forbid-non-structural_match-types.rs
new file mode 100644
index 0000000000000..7bc4f3986eb75
--- /dev/null
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.rs
@@ -0,0 +1,13 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+#[derive(PartialEq, Eq)]
+struct A;
+
+struct B<const X: A>; // ok
+
+struct C;
+
+struct D<const X: C>; //~ ERROR the types of const generic parameters must derive
+
+fn main() {}
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.stderr b/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
new file mode 100644
index 0000000000000..9ab6c69521be0
--- /dev/null
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
@@ -0,0 +1,17 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/forbid-non-structural_match-types.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0739]: the types of const generic parameters must derive `PartialEq` and `Eq`
+  --> $DIR/forbid-non-structural_match-types.rs:11:19
+   |
+LL | struct D<const X: C>;
+   |                   ^ `C` doesn't derive both `PartialEq` and `Eq`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0739`.

From 133cd2cfaf244c130e2e0d681090ca117bcba94e Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Sun, 20 Oct 2019 18:17:42 +0100
Subject: [PATCH 3/7] Search for generic parameters when finding
 non-`structural_match` types

---
 src/librustc/ty/mod.rs                        | 32 ++++++++++++-------
 src/librustc_mir/hair/pattern/mod.rs          | 24 ++++++++------
 src/librustc_typeck/collect.rs                |  4 +--
 src/librustc_typeck/error_codes.rs            |  4 +--
 .../forbid-non-structural_match-types.stderr  |  4 +--
 5 files changed, 42 insertions(+), 26 deletions(-)

diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 77d8141c9688c..6c512a0238eed 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -3393,9 +3393,15 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
     fn_like.asyncness()
 }
 
+pub enum NonStructuralMatchTy<'tcx> {
+    Adt(&'tcx AdtDef),
+    Param,
+}
+
 /// This method traverses the structure of `ty`, trying to find an
 /// instance of an ADT (i.e. struct or enum) that was declared without
-/// the `#[structural_match]` attribute.
+/// the `#[structural_match]` attribute, or a generic type parameter
+/// (which cannot be determined to be `structural_match`).
 ///
 /// The "structure of a type" includes all components that would be
 /// considered when doing a pattern match on a constant of that
@@ -3417,10 +3423,10 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
 /// For more background on why Rust has this requirement, and issues
 /// that arose when the requirement was not enforced completely, see
 /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
-pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
-                                                 ty: Ty<'tcx>)
-                                                 -> Option<&'tcx AdtDef>
-{
+pub fn search_for_structural_match_violation<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Option<NonStructuralMatchTy<'tcx>> {
     let mut search = Search { tcx, found: None, seen: FxHashSet::default() };
     ty.visit_with(&mut search);
     return search.found;
@@ -3428,11 +3434,11 @@ pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
     struct Search<'tcx> {
         tcx: TyCtxt<'tcx>,
 
-        // records the first ADT we find without `#[structural_match`
-        found: Option<&'tcx AdtDef>,
+        // Records the first ADT or type parameter we find without `#[structural_match`.
+        found: Option<NonStructuralMatchTy<'tcx>>,
 
-        // tracks ADT's previously encountered during search, so that
-        // we will not recur on them again.
+        // Tracks ADTs previously encountered during search, so that
+        // we will not recurse on them again.
         seen: FxHashSet<hir::def_id::DefId>,
     }
 
@@ -3442,6 +3448,10 @@ pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
 
             let (adt_def, substs) = match ty.kind {
                 ty::Adt(adt_def, substs) => (adt_def, substs),
+                ty::Param(_) => {
+                    self.found = Some(NonStructuralMatchTy::Param);
+                    return true; // Stop visiting.
+                }
                 ty::RawPtr(..) => {
                     // `#[structural_match]` ignores substructure of
                     // `*const _`/`*mut _`, so skip super_visit_with
@@ -3468,9 +3478,9 @@ pub fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
             };
 
             if !self.tcx.has_attr(adt_def.did, sym::structural_match) {
-                self.found = Some(&adt_def);
+                self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
                 debug!("Search found adt_def: {:?}", adt_def);
-                return true // Halt visiting!
+                return true; // Stop visiting.
             }
 
             if !self.seen.insert(adt_def.did) {
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index d996881221857..98e286e61e942 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -999,15 +999,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         if self.include_lint_checks && !saw_error {
             // If we were able to successfully convert the const to some pat, double-check
             // that the type of the const obeys `#[structural_match]` constraint.
-            if let Some(adt_def) = ty::search_for_adt_without_structural_match(self.tcx, cv.ty) {
-
-                let path = self.tcx.def_path_str(adt_def.did);
-                let msg = format!(
-                    "to use a constant of type `{}` in a pattern, \
-                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                    path,
-                    path,
-                );
+            if let Some(non_sm_ty) = ty::search_for_structural_match_violation(self.tcx, cv.ty) {
+                let msg = match non_sm_ty {
+                    ty::NonStructuralMatchTy::Adt(adt_def) => {
+                        let path = self.tcx.def_path_str(adt_def.did);
+                        format!(
+                            "to use a constant of type `{}` in a pattern, \
+                             `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
+                            path,
+                            path,
+                        )
+                    }
+                    ty::NonStructuralMatchTy::Param => {
+                        bug!("use of constant whose type is a parameter inside a pattern");
+                    }
+                };
 
                 // before issuing lint, double-check there even *is* a
                 // semantic PartialEq for us to dispatch to.
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index d6162c0bc0e9f..08fb5ae1676e7 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1532,11 +1532,11 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                         );
                     };
                 }
-                if ty::search_for_adt_without_structural_match(tcx, ty).is_some() {
+                if ty::search_for_structural_match_violation(tcx, ty).is_some() {
                     struct_span_err!(
                         tcx.sess,
                         hir_ty.span,
-                        E0739,
+                        E0740,
                         "the types of const generic parameters must derive `PartialEq` and `Eq`",
                     ).span_label(
                         hir_ty.span,
diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs
index 5d1afcaef9140..2cf6951c37569 100644
--- a/src/librustc_typeck/error_codes.rs
+++ b/src/librustc_typeck/error_codes.rs
@@ -4978,11 +4978,11 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
 [RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
 "##,
 
-E0739: r##"
+E0740: r##"
 Only `structural_match` types (that is, types that derive `PartialEq` and `Eq`)
 may be used as the types of const generic parameters.
 
-```compile_fail,E0739
+```compile_fail,E0740
 #![feature(const_generics)]
 
 struct A;
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.stderr b/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
index 9ab6c69521be0..c870d9b1db486 100644
--- a/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
@@ -6,7 +6,7 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0739]: the types of const generic parameters must derive `PartialEq` and `Eq`
+error[E0740]: the types of const generic parameters must derive `PartialEq` and `Eq`
   --> $DIR/forbid-non-structural_match-types.rs:11:19
    |
 LL | struct D<const X: C>;
@@ -14,4 +14,4 @@ LL | struct D<const X: C>;
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0739`.
+For more information about this error, try `rustc --explain E0740`.

From f0e6cd9f89d3cdb11f417707690679fc334dfe0a Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Sun, 20 Oct 2019 18:18:24 +0100
Subject: [PATCH 4/7] Remove "type parameter depends on const parameter" error
 from resolution

---
 src/librustc_resolve/diagnostics.rs           | 10 --------
 src/librustc_resolve/error_codes.rs           |  7 +++---
 src/librustc_resolve/late.rs                  | 23 +------------------
 src/librustc_resolve/lib.rs                   | 15 ++----------
 ...aram-type-depends-on-type-param-ungated.rs |  2 +-
 ...-type-depends-on-type-param-ungated.stderr | 14 +++++------
 .../const-param-type-depends-on-type-param.rs |  3 +--
 ...st-param-type-depends-on-type-param.stderr | 19 ++++-----------
 8 files changed, 21 insertions(+), 72 deletions(-)

diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 5647d5b2794af..7634093fbefba 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -367,16 +367,6 @@ impl<'a> Resolver<'a> {
                     span, "`Self` in type parameter default".to_string());
                 err
             }
-            ResolutionError::ConstParamDependentOnTypeParam => {
-                let mut err = struct_span_err!(
-                    self.session,
-                    span,
-                    E0671,
-                    "const parameters cannot depend on type parameters"
-                );
-                err.span_label(span, format!("const parameter depends on type parameter"));
-                err
-            }
         }
     }
 
diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs
index b82cba8c83dc4..49f8e82a2d1b5 100644
--- a/src/librustc_resolve/error_codes.rs
+++ b/src/librustc_resolve/error_codes.rs
@@ -1880,13 +1880,14 @@ fn main() {
 "##,
 
 E0671: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
 Const parameters cannot depend on type parameters.
 The following is therefore invalid:
-```compile_fail,E0671
+```compile_fail,E0740
 #![feature(const_generics)]
 
-fn const_id<T, const N: T>() -> T { // error: const parameter
-                                    // depends on type parameter
+fn const_id<T, const N: T>() -> T { // error
     N
 }
 ```
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 73a282b1a0ec1..136ab1f0444fa 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -111,9 +111,6 @@ crate enum RibKind<'a> {
     /// from the default of a type parameter because they're not declared
     /// before said type parameter. Also see the `visit_generics` override.
     ForwardTyParamBanRibKind,
-
-    /// We forbid the use of type parameters as the types of const parameters.
-    TyParamAsConstParamTy,
 }
 
 impl RibKind<'_> {
@@ -128,8 +125,7 @@ impl RibKind<'_> {
             | MacroDefinition(_) => false,
             AssocItemRibKind
             | ItemRibKind(_)
-            | ForwardTyParamBanRibKind
-            | TyParamAsConstParamTy => true,
+            | ForwardTyParamBanRibKind => true,
         }
     }
 }
@@ -483,18 +479,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
             default_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
         }
 
-        // We also ban access to type parameters for use as the types of const parameters.
-        let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy);
-        const_ty_param_ban_rib.bindings.extend(generics.params.iter()
-            .filter(|param| {
-                if let GenericParamKind::Type { .. } = param.kind {
-                    true
-                } else {
-                    false
-                }
-            })
-            .map(|param| (Ident::with_dummy_span(param.ident.name), Res::Err)));
-
         for param in &generics.params {
             match param.kind {
                 GenericParamKind::Lifetime { .. } => self.visit_generic_param(param),
@@ -513,15 +497,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
                     default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
                 }
                 GenericParamKind::Const { ref ty } => {
-                    self.ribs[TypeNS].push(const_ty_param_ban_rib);
-
                     for bound in &param.bounds {
                         self.visit_param_bound(bound);
                     }
-
                     self.visit_ty(ty);
-
-                    const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap();
                 }
             }
         }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 17d8f0f211a92..1cc21a54e3cff 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -215,8 +215,6 @@ enum ResolutionError<'a> {
     ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
     /// Error E0735: type parameters with a default cannot use `Self`
     SelfInTyParamDefault,
-    /// Error E0671: const parameter cannot depend on type parameter.
-    ConstParamDependentOnTypeParam,
 }
 
 // A minimal representation of a path segment. We use this in resolve because
@@ -2169,15 +2167,6 @@ impl<'a> Resolver<'a> {
             return Res::Err;
         }
 
-        // An invalid use of a type parameter as the type of a const parameter.
-        if let TyParamAsConstParamTy = all_ribs[rib_index].kind {
-            if record_used {
-                self.report_error(span, ResolutionError::ConstParamDependentOnTypeParam);
-            }
-            assert_eq!(res, Res::Err);
-            return Res::Err;
-        }
-
         match res {
             Res::Local(_) => {
                 use ResolutionError::*;
@@ -2186,7 +2175,7 @@ impl<'a> Resolver<'a> {
                 for rib in ribs {
                     match rib.kind {
                         NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) |
-                        ForwardTyParamBanRibKind | TyParamAsConstParamTy => {
+                        ForwardTyParamBanRibKind => {
                             // Nothing to do. Continue.
                         }
                         ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => {
@@ -2220,7 +2209,7 @@ impl<'a> Resolver<'a> {
                     let has_generic_params = match rib.kind {
                         NormalRibKind | AssocItemRibKind |
                         ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
-                        ConstantItemRibKind | TyParamAsConstParamTy => {
+                        ConstantItemRibKind => {
                             // Nothing to do. Continue.
                             continue;
                         }
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs
index af5e8f49754e8..78bd549ba791a 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs
@@ -1,6 +1,6 @@
 use std::marker::PhantomData;
 
 struct B<T, const N: T>(PhantomData<[T; N]>); //~ ERROR const generics are unstable
-//~^ ERROR const parameters cannot depend on type parameters
+//~^ ERROR the types of const generic parameters must derive `PartialEq` and `Eq`
 
 fn main() {}
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
index c659074a091c8..ba6f53e56840e 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
@@ -1,9 +1,3 @@
-error[E0671]: const parameters cannot depend on type parameters
-  --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
-   |
-LL | struct B<T, const N: T>(PhantomData<[T; N]>);
-   |                      ^ const parameter depends on type parameter
-
 error[E0658]: const generics are unstable
   --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19
    |
@@ -13,7 +7,13 @@ LL | struct B<T, const N: T>(PhantomData<[T; N]>);
    = note: for more information, see https://github.com/rust-lang/rust/issues/44580
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
+error[E0740]: the types of const generic parameters must derive `PartialEq` and `Eq`
+  --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
+   |
+LL | struct B<T, const N: T>(PhantomData<[T; N]>);
+   |                      ^ `T` doesn't derive both `PartialEq` and `Eq`
+
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0658, E0671.
+Some errors have detailed explanations: E0658, E0740.
 For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs
index 28e0d6c2bb7e7..b76209571b05c 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs
@@ -7,7 +7,6 @@
 // details.
 
 pub struct Dependent<T, const X: T>([(); X]);
-//~^ ERROR const parameters cannot depend on type parameters
-//~^^ ERROR parameter `T` is never used
+//~^ ERROR the types of const generic parameters must derive `PartialEq` and `Eq`
 
 fn main() {}
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr
index db14f9c9bf695..c86a09bef0b8d 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr
@@ -1,9 +1,3 @@
-error[E0671]: const parameters cannot depend on type parameters
-  --> $DIR/const-param-type-depends-on-type-param.rs:9:34
-   |
-LL | pub struct Dependent<T, const X: T>([(); X]);
-   |                                  ^ const parameter depends on type parameter
-
 warning: the feature `const_generics` is incomplete and may cause the compiler to crash
   --> $DIR/const-param-type-depends-on-type-param.rs:1:12
    |
@@ -12,15 +6,12 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0392]: parameter `T` is never used
-  --> $DIR/const-param-type-depends-on-type-param.rs:9:22
+error[E0740]: the types of const generic parameters must derive `PartialEq` and `Eq`
+  --> $DIR/const-param-type-depends-on-type-param.rs:9:34
    |
 LL | pub struct Dependent<T, const X: T>([(); X]);
-   |                      ^ unused parameter
-   |
-   = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData`
+   |                                  ^ `T` doesn't derive both `PartialEq` and `Eq`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0392, E0671.
-For more information about an error, try `rustc --explain E0392`.
+For more information about this error, try `rustc --explain E0740`.

From 9f788f3a2b7626318d0bdedca38986fc283f481f Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Mon, 21 Oct 2019 16:54:33 +0100
Subject: [PATCH 5/7] Fix rustdoc const generics test

---
 src/test/rustdoc/const-generics/const-impl.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/test/rustdoc/const-generics/const-impl.rs b/src/test/rustdoc/const-generics/const-impl.rs
index 85ee6d3376b27..2d506787b3b80 100644
--- a/src/test/rustdoc/const-generics/const-impl.rs
+++ b/src/test/rustdoc/const-generics/const-impl.rs
@@ -4,6 +4,7 @@
 
 #![crate_name = "foo"]
 
+#[derive(PartialEq, Eq)]
 pub enum Order {
     Sorted,
     Unsorted,

From 7f13a4a80a67ecc4fd0521e867eeb91b657f2fa0 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Tue, 22 Oct 2019 12:00:54 +0100
Subject: [PATCH 6/7] Remove FIXME

---
 src/librustc/ty/relate.rs | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 41f34703622e7..1da65f4b51d36 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -557,10 +557,9 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
         x.val
     };
 
-    // Currently, the values that can be unified are those that
-    // implement both `PartialEq` and `Eq`, corresponding to
-    // `structural_match` types.
-    // FIXME(const_generics): check for `structural_match` synthetic attribute.
+    // Currently, the values that can be unified are primitive types,
+    // and those that derive both `PartialEq` and `Eq`, corresponding
+    // to `structural_match` types.
     let new_const_val = match (eagerly_eval(a), eagerly_eval(b)) {
         (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => {
             // The caller should handle these cases!

From 2dda8ad98a8d5089335b2d09307f1bfd085499f9 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Tue, 22 Oct 2019 12:28:23 +0100
Subject: [PATCH 7/7] Use E0741 for structural match error

---
 src/librustc_resolve/error_codes.rs                           | 2 +-
 src/librustc_typeck/collect.rs                                | 2 +-
 src/librustc_typeck/error_codes.rs                            | 4 ++--
 .../const-param-type-depends-on-type-param-ungated.stderr     | 4 ++--
 .../const-param-type-depends-on-type-param.stderr             | 4 ++--
 .../const-generics/forbid-non-structural_match-types.stderr   | 4 ++--
 6 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs
index 49f8e82a2d1b5..df22085c38c74 100644
--- a/src/librustc_resolve/error_codes.rs
+++ b/src/librustc_resolve/error_codes.rs
@@ -1884,7 +1884,7 @@ E0671: r##"
 
 Const parameters cannot depend on type parameters.
 The following is therefore invalid:
-```compile_fail,E0740
+```compile_fail,E0741
 #![feature(const_generics)]
 
 fn const_id<T, const N: T>() -> T { // error
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 08fb5ae1676e7..f40667652cac0 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1536,7 +1536,7 @@ pub fn checked_type_of(tcx: TyCtxt<'_>, def_id: DefId, fail: bool) -> Option<Ty<
                     struct_span_err!(
                         tcx.sess,
                         hir_ty.span,
-                        E0740,
+                        E0741,
                         "the types of const generic parameters must derive `PartialEq` and `Eq`",
                     ).span_label(
                         hir_ty.span,
diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs
index 2cf6951c37569..8a9a89c38260c 100644
--- a/src/librustc_typeck/error_codes.rs
+++ b/src/librustc_typeck/error_codes.rs
@@ -4978,11 +4978,11 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
 [RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
 "##,
 
-E0740: r##"
+E0741: r##"
 Only `structural_match` types (that is, types that derive `PartialEq` and `Eq`)
 may be used as the types of const generic parameters.
 
-```compile_fail,E0740
+```compile_fail,E0741
 #![feature(const_generics)]
 
 struct A;
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
index ba6f53e56840e..a2872ab982da4 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr
@@ -7,7 +7,7 @@ LL | struct B<T, const N: T>(PhantomData<[T; N]>);
    = note: for more information, see https://github.com/rust-lang/rust/issues/44580
    = help: add `#![feature(const_generics)]` to the crate attributes to enable
 
-error[E0740]: the types of const generic parameters must derive `PartialEq` and `Eq`
+error[E0741]: the types of const generic parameters must derive `PartialEq` and `Eq`
   --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
    |
 LL | struct B<T, const N: T>(PhantomData<[T; N]>);
@@ -15,5 +15,5 @@ LL | struct B<T, const N: T>(PhantomData<[T; N]>);
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0658, E0740.
+Some errors have detailed explanations: E0658, E0741.
 For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr
index c86a09bef0b8d..c9d6db7e2c220 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr
+++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr
@@ -6,7 +6,7 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0740]: the types of const generic parameters must derive `PartialEq` and `Eq`
+error[E0741]: the types of const generic parameters must derive `PartialEq` and `Eq`
   --> $DIR/const-param-type-depends-on-type-param.rs:9:34
    |
 LL | pub struct Dependent<T, const X: T>([(); X]);
@@ -14,4 +14,4 @@ LL | pub struct Dependent<T, const X: T>([(); X]);
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0740`.
+For more information about this error, try `rustc --explain E0741`.
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.stderr b/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
index c870d9b1db486..0fd9e0599e80e 100644
--- a/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.stderr
@@ -6,7 +6,7 @@ LL | #![feature(const_generics)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0740]: the types of const generic parameters must derive `PartialEq` and `Eq`
+error[E0741]: the types of const generic parameters must derive `PartialEq` and `Eq`
   --> $DIR/forbid-non-structural_match-types.rs:11:19
    |
 LL | struct D<const X: C>;
@@ -14,4 +14,4 @@ LL | struct D<const X: C>;
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0740`.
+For more information about this error, try `rustc --explain E0741`.