From 14e6947fa4b9a144802869286a937c987d6a3c54 Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Tue, 10 Sep 2019 18:46:27 +0100
Subject: [PATCH 1/2] Correct the polymorphic extern fn error for const
 parameters

---
 src/librustc_typeck/check/mod.rs              | 33 +++++++++++++++----
 .../foreign-item-const-parameter.rs           | 10 ++++++
 .../foreign-item-const-parameter.stderr       | 27 +++++++++++++++
 3 files changed, 63 insertions(+), 7 deletions(-)
 create mode 100644 src/test/ui/const-generics/foreign-item-const-parameter.rs
 create mode 100644 src/test/ui/const-generics/foreign-item-const-parameter.stderr

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d8d01624f1d56..e76ef14f06c87 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1511,20 +1511,39 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item) {
             } else {
                 for item in &m.items {
                     let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id));
-                    if generics.params.len() - generics.own_counts().lifetimes != 0 {
+                    let own_counts = generics.own_counts();
+                    if generics.params.len() - own_counts.lifetimes != 0 {
+                        let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
+                            (_, 0) => ("type", "types", Some("u32")),
+                            // We don't specify an example value, because we can't generate
+                            // a valid value for any type.
+                            (0, _) => ("const", "consts", None),
+                            _ => ("type or const", "types or consts", None),
+                        };
                         let mut err = struct_span_err!(
                             tcx.sess,
                             item.span,
                             E0044,
-                            "foreign items may not have type parameters"
+                            "foreign items may not have {} parameters",
+                            kinds,
+                        );
+                        err.span_label(
+                            item.span,
+                            &format!("can't have {} parameters", kinds),
                         );
-                        err.span_label(item.span, "can't have type parameters");
                         // FIXME: once we start storing spans for type arguments, turn this into a
                         // suggestion.
-                        err.help(
-                            "use specialization instead of type parameters by replacing them \
-                             with concrete types like `u32`",
-                        );
+                        err.help(&format!(
+                            "use specialization instead of {} parameters by replacing \
+                            them with concrete {}{}",
+                            kinds,
+                            kinds_pl,
+                            if let Some(egs) = egs {
+                                format!(" like `{}`", egs)
+                            } else {
+                                "".to_string()
+                            },
+                        ));
                         err.emit();
                     }
 
diff --git a/src/test/ui/const-generics/foreign-item-const-parameter.rs b/src/test/ui/const-generics/foreign-item-const-parameter.rs
new file mode 100644
index 0000000000000..4673c8606c393
--- /dev/null
+++ b/src/test/ui/const-generics/foreign-item-const-parameter.rs
@@ -0,0 +1,10 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+extern "C" {
+    fn foo<const X: usize>(); //~ ERROR foreign items may not have const parameters
+
+    fn bar<T, const X: usize>(_: T); //~ ERROR foreign items may not have type or const parameters
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/foreign-item-const-parameter.stderr b/src/test/ui/const-generics/foreign-item-const-parameter.stderr
new file mode 100644
index 0000000000000..0a74537dfef35
--- /dev/null
+++ b/src/test/ui/const-generics/foreign-item-const-parameter.stderr
@@ -0,0 +1,27 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/foreign-item-const-parameter.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0044]: foreign items may not have const parameters
+  --> $DIR/foreign-item-const-parameter.rs:5:5
+   |
+LL |     fn foo<const X: usize>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters
+   |
+   = help: use specialization instead of const parameters by replacing them with concrete consts
+
+error[E0044]: foreign items may not have type or const parameters
+  --> $DIR/foreign-item-const-parameter.rs:7:5
+   |
+LL |     fn bar<T, const X: usize>(_: T);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have type or const parameters
+   |
+   = help: use specialization instead of type or const parameters by replacing them with concrete types or consts
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0044`.

From ef62e050624fabc57f17dd6744ff29f79b39e8cd Mon Sep 17 00:00:00 2001
From: varkor <github@varkor.com>
Date: Tue, 10 Sep 2019 22:35:10 +0100
Subject: [PATCH 2/2] Make wording less confusing

---
 src/librustc_typeck/check/mod.rs              | 30 ++++++++-----------
 .../foreign-item-const-parameter.stderr       |  4 +--
 src/test/ui/error-codes/E0044.rs              |  2 +-
 src/test/ui/error-codes/E0044.stderr          |  2 +-
 src/test/ui/generic/generic-extern.stderr     |  2 +-
 5 files changed, 17 insertions(+), 23 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index e76ef14f06c87..02e7d97ccdf7b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1520,31 +1520,25 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item) {
                             (0, _) => ("const", "consts", None),
                             _ => ("type or const", "types or consts", None),
                         };
-                        let mut err = struct_span_err!(
+                        struct_span_err!(
                             tcx.sess,
                             item.span,
                             E0044,
                             "foreign items may not have {} parameters",
                             kinds,
-                        );
-                        err.span_label(
+                        ).span_label(
                             item.span,
                             &format!("can't have {} parameters", kinds),
-                        );
-                        // FIXME: once we start storing spans for type arguments, turn this into a
-                        // suggestion.
-                        err.help(&format!(
-                            "use specialization instead of {} parameters by replacing \
-                            them with concrete {}{}",
-                            kinds,
-                            kinds_pl,
-                            if let Some(egs) = egs {
-                                format!(" like `{}`", egs)
-                            } else {
-                                "".to_string()
-                            },
-                        ));
-                        err.emit();
+                        ).help(
+                            // FIXME: once we start storing spans for type arguments, turn this
+                            // into a suggestion.
+                            &format!(
+                                "replace the {} parameters with concrete {}{}",
+                                kinds,
+                                kinds_pl,
+                                egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(),
+                            ),
+                        ).emit();
                     }
 
                     if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node {
diff --git a/src/test/ui/const-generics/foreign-item-const-parameter.stderr b/src/test/ui/const-generics/foreign-item-const-parameter.stderr
index 0a74537dfef35..999feed2d3b20 100644
--- a/src/test/ui/const-generics/foreign-item-const-parameter.stderr
+++ b/src/test/ui/const-generics/foreign-item-const-parameter.stderr
@@ -12,7 +12,7 @@ error[E0044]: foreign items may not have const parameters
 LL |     fn foo<const X: usize>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters
    |
-   = help: use specialization instead of const parameters by replacing them with concrete consts
+   = help: replace the const parameters with concrete consts
 
 error[E0044]: foreign items may not have type or const parameters
   --> $DIR/foreign-item-const-parameter.rs:7:5
@@ -20,7 +20,7 @@ error[E0044]: foreign items may not have type or const parameters
 LL |     fn bar<T, const X: usize>(_: T);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have type or const parameters
    |
-   = help: use specialization instead of type or const parameters by replacing them with concrete types or consts
+   = help: replace the type or const parameters with concrete types or consts
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0044.rs b/src/test/ui/error-codes/E0044.rs
index a5265e7dc1708..9eee9c31d3c38 100644
--- a/src/test/ui/error-codes/E0044.rs
+++ b/src/test/ui/error-codes/E0044.rs
@@ -1,7 +1,7 @@
 extern {
     fn sqrt<T>(f: T) -> T;
     //~^ ERROR foreign items may not have type parameters [E0044]
-    //~| HELP use specialization instead of type parameters by replacing them with concrete types
+    //~| HELP replace the type parameters with concrete types
     //~| NOTE can't have type parameters
 }
 
diff --git a/src/test/ui/error-codes/E0044.stderr b/src/test/ui/error-codes/E0044.stderr
index 57c21116b2856..e889c167b98d2 100644
--- a/src/test/ui/error-codes/E0044.stderr
+++ b/src/test/ui/error-codes/E0044.stderr
@@ -4,7 +4,7 @@ error[E0044]: foreign items may not have type parameters
 LL |     fn sqrt<T>(f: T) -> T;
    |     ^^^^^^^^^^^^^^^^^^^^^^ can't have type parameters
    |
-   = help: use specialization instead of type parameters by replacing them with concrete types like `u32`
+   = help: replace the type parameters with concrete types like `u32`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generic/generic-extern.stderr b/src/test/ui/generic/generic-extern.stderr
index e7625abb1c831..c90215b612d4c 100644
--- a/src/test/ui/generic/generic-extern.stderr
+++ b/src/test/ui/generic/generic-extern.stderr
@@ -4,7 +4,7 @@ error[E0044]: foreign items may not have type parameters
 LL |     fn foo<T>();
    |     ^^^^^^^^^^^^ can't have type parameters
    |
-   = help: use specialization instead of type parameters by replacing them with concrete types like `u32`
+   = help: replace the type parameters with concrete types like `u32`
 
 error: aborting due to previous error