about summary refs log tree commit diff
path: root/tests/ui/polymorphization
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/polymorphization')
-rw-r--r--tests/ui/polymorphization/closure_in_upvar/fn.rs29
-rw-r--r--tests/ui/polymorphization/closure_in_upvar/fnmut.rs34
-rw-r--r--tests/ui/polymorphization/closure_in_upvar/fnonce.rs34
-rw-r--r--tests/ui/polymorphization/closure_in_upvar/other.rs38
-rw-r--r--tests/ui/polymorphization/const_parameters/closures.rs67
-rw-r--r--tests/ui/polymorphization/const_parameters/closures.stderr44
-rw-r--r--tests/ui/polymorphization/const_parameters/functions.rs37
-rw-r--r--tests/ui/polymorphization/const_parameters/functions.stderr17
-rw-r--r--tests/ui/polymorphization/drop_shims/simple.rs22
-rw-r--r--tests/ui/polymorphization/drop_shims/transitive.rs27
-rw-r--r--tests/ui/polymorphization/generators.rs92
-rw-r--r--tests/ui/polymorphization/generators.stderr39
-rw-r--r--tests/ui/polymorphization/issue-74614.rs18
-rw-r--r--tests/ui/polymorphization/issue-74636.rs16
-rw-r--r--tests/ui/polymorphization/lifetimes.rs25
-rw-r--r--tests/ui/polymorphization/lifetimes.stderr17
-rw-r--r--tests/ui/polymorphization/normalized_sig_types.rs26
-rw-r--r--tests/ui/polymorphization/predicates.rs95
-rw-r--r--tests/ui/polymorphization/predicates.stderr51
-rw-r--r--tests/ui/polymorphization/promoted-function-1.rs12
-rw-r--r--tests/ui/polymorphization/promoted-function-1.stderr8
-rw-r--r--tests/ui/polymorphization/promoted-function-2.rs16
-rw-r--r--tests/ui/polymorphization/promoted-function-2.stderr17
-rw-r--r--tests/ui/polymorphization/promoted-function-3.rs14
-rw-r--r--tests/ui/polymorphization/promoted-function.rs15
-rw-r--r--tests/ui/polymorphization/symbol-ambiguity.rs22
-rw-r--r--tests/ui/polymorphization/too-many-generic-params.rs85
-rw-r--r--tests/ui/polymorphization/type_parameters/closures.rs161
-rw-r--r--tests/ui/polymorphization/type_parameters/closures.stderr80
-rw-r--r--tests/ui/polymorphization/type_parameters/functions.rs96
-rw-r--r--tests/ui/polymorphization/type_parameters/functions.stderr35
-rw-r--r--tests/ui/polymorphization/unsized_cast.rs30
-rw-r--r--tests/ui/polymorphization/unsized_cast.stderr38
33 files changed, 1357 insertions, 0 deletions
diff --git a/tests/ui/polymorphization/closure_in_upvar/fn.rs b/tests/ui/polymorphization/closure_in_upvar/fn.rs
new file mode 100644
index 00000000000..e1030858814
--- /dev/null
+++ b/tests/ui/polymorphization/closure_in_upvar/fn.rs
@@ -0,0 +1,29 @@
+// build-pass
+// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
+
+fn foo(f: impl Fn()) {
+    let x = |_: ()| ();
+
+    // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
+    // `x` that will differ for each instantiation despite polymorphisation of the varying
+    // argument.
+    let y = || x(());
+
+    // Consider `f` used in `foo`.
+    f();
+    // Use `y` so that it is visited in monomorphisation collection.
+    y();
+}
+
+fn entry_a() {
+    foo(|| ());
+}
+
+fn entry_b() {
+    foo(|| ());
+}
+
+fn main() {
+    entry_a();
+    entry_b();
+}
diff --git a/tests/ui/polymorphization/closure_in_upvar/fnmut.rs b/tests/ui/polymorphization/closure_in_upvar/fnmut.rs
new file mode 100644
index 00000000000..62164ff9485
--- /dev/null
+++ b/tests/ui/polymorphization/closure_in_upvar/fnmut.rs
@@ -0,0 +1,34 @@
+// build-pass
+// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
+
+fn foo(f: impl Fn()) {
+    // Mutate an upvar from `x` so that it implements `FnMut`.
+    let mut outer = 3;
+    let mut x = |_: ()| {
+        outer = 4;
+        ()
+    };
+
+    // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
+    // `x` that will differ for each instantiation despite polymorphisation of the varying
+    // argument.
+    let mut y = || x(());
+
+    // Consider `f` used in `foo`.
+    f();
+    // Use `y` so that it is visited in monomorphisation collection.
+    y();
+}
+
+fn entry_a() {
+    foo(|| ());
+}
+
+fn entry_b() {
+    foo(|| ());
+}
+
+fn main() {
+    entry_a();
+    entry_b();
+}
diff --git a/tests/ui/polymorphization/closure_in_upvar/fnonce.rs b/tests/ui/polymorphization/closure_in_upvar/fnonce.rs
new file mode 100644
index 00000000000..7a364882fb8
--- /dev/null
+++ b/tests/ui/polymorphization/closure_in_upvar/fnonce.rs
@@ -0,0 +1,34 @@
+// build-pass
+// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
+
+fn foo(f: impl Fn()) {
+    // Move a non-copy type into `x` so that it implements `FnOnce`.
+    let outer = Vec::<u32>::new();
+    let x = move |_: ()| {
+        let inner = outer;
+        ()
+    };
+
+    // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
+    // `x` that will differ for each instantiation despite polymorphisation of the varying
+    // argument.
+    let y = || x(());
+
+    // Consider `f` used in `foo`.
+    f();
+    // Use `y` so that it is visited in monomorphisation collection.
+    y();
+}
+
+fn entry_a() {
+    foo(|| ());
+}
+
+fn entry_b() {
+    foo(|| ());
+}
+
+fn main() {
+    entry_a();
+    entry_b();
+}
diff --git a/tests/ui/polymorphization/closure_in_upvar/other.rs b/tests/ui/polymorphization/closure_in_upvar/other.rs
new file mode 100644
index 00000000000..27d59ec8899
--- /dev/null
+++ b/tests/ui/polymorphization/closure_in_upvar/other.rs
@@ -0,0 +1,38 @@
+// build-pass
+// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
+
+fn y_uses_f(f: impl Fn()) {
+    let x = |_: ()| ();
+
+    let y = || {
+        f();
+        x(());
+    };
+
+    f();
+    y();
+}
+
+fn x_uses_f(f: impl Fn()) {
+    let x = |_: ()| { f(); };
+
+    let y = || x(());
+
+    f();
+    y();
+}
+
+fn entry_a() {
+    x_uses_f(|| ());
+    y_uses_f(|| ());
+}
+
+fn entry_b() {
+    x_uses_f(|| ());
+    y_uses_f(|| ());
+}
+
+fn main() {
+    entry_a();
+    entry_b();
+}
diff --git a/tests/ui/polymorphization/const_parameters/closures.rs b/tests/ui/polymorphization/const_parameters/closures.rs
new file mode 100644
index 00000000000..2f41beeb969
--- /dev/null
+++ b/tests/ui/polymorphization/const_parameters/closures.rs
@@ -0,0 +1,67 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(generic_const_exprs, rustc_attrs)]
+//~^ WARN the feature `generic_const_exprs` is incomplete
+
+// This test checks that the polymorphization analysis correctly detects unused const
+// parameters in closures.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {
+    let _ = || {};
+}
+
+// Function has an unused generic parameter in parent and closure.
+#[rustc_polymorphize_error]
+pub fn unused<const T: usize>() -> usize {
+    //~^ ERROR item has unused generic parameters
+    let add_one = |x: usize| x + 1;
+    //~^ ERROR item has unused generic parameters
+    add_one(3)
+}
+
+// Function has an unused generic parameter in closure, but not in parent.
+#[rustc_polymorphize_error]
+pub fn used_parent<const T: usize>() -> usize {
+    let x: usize = T;
+    let add_one = |x: usize| x + 1;
+    //~^ ERROR item has unused generic parameters
+    x + add_one(3)
+}
+
+// Function uses generic parameter in value of a binding in closure.
+#[rustc_polymorphize_error]
+pub fn used_binding<const T: usize>() -> usize {
+    let x = || {
+        let y: usize = T;
+        y
+    };
+
+    x()
+}
+
+// Closure uses a value as an upvar, which used the generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused_upvar<const T: usize>() -> usize {
+    let x: usize = T;
+    let y = || x;
+    //~^ ERROR item has unused generic parameters
+    y()
+}
+
+// Closure uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<const T: usize>() -> usize {
+    let x = || unused::<T>();
+    x()
+}
+
+fn main() {
+    no_parameters();
+    let _ = unused::<1>();
+    let _ = used_parent::<1>();
+    let _ = used_binding::<1>();
+    let _ = unused_upvar::<1>();
+    let _ = used_substs::<1>();
+}
diff --git a/tests/ui/polymorphization/const_parameters/closures.stderr b/tests/ui/polymorphization/const_parameters/closures.stderr
new file mode 100644
index 00000000000..4e927f7732f
--- /dev/null
+++ b/tests/ui/polymorphization/const_parameters/closures.stderr
@@ -0,0 +1,44 @@
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/closures.rs:3:12
+   |
+LL | #![feature(generic_const_exprs, rustc_attrs)]
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:19:19
+   |
+LL | pub fn unused<const T: usize>() -> usize {
+   |               -------------- generic parameter `T` is unused
+LL |
+LL |     let add_one = |x: usize| x + 1;
+   |                   ^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:17:8
+   |
+LL | pub fn unused<const T: usize>() -> usize {
+   |        ^^^^^^ -------------- generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:28:19
+   |
+LL | pub fn used_parent<const T: usize>() -> usize {
+   |                    -------------- generic parameter `T` is unused
+LL |     let x: usize = T;
+LL |     let add_one = |x: usize| x + 1;
+   |                   ^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:48:13
+   |
+LL | pub fn unused_upvar<const T: usize>() -> usize {
+   |                     -------------- generic parameter `T` is unused
+LL |     let x: usize = T;
+LL |     let y = || x;
+   |             ^^
+
+error: aborting due to 4 previous errors; 1 warning emitted
+
diff --git a/tests/ui/polymorphization/const_parameters/functions.rs b/tests/ui/polymorphization/const_parameters/functions.rs
new file mode 100644
index 00000000000..cbc1b63fbc4
--- /dev/null
+++ b/tests/ui/polymorphization/const_parameters/functions.rs
@@ -0,0 +1,37 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(generic_const_exprs, rustc_attrs)]
+//~^ WARN the feature `generic_const_exprs` is incomplete
+
+// This test checks that the polymorphization analysis correctly detects unused const
+// parameters in functions.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {}
+
+// Function has an unused generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused<const T: usize>() {
+    //~^ ERROR item has unused generic parameters
+}
+
+// Function uses generic parameter in value of a binding.
+#[rustc_polymorphize_error]
+pub fn used_binding<const T: usize>() -> usize {
+    let x: usize = T;
+    x
+}
+
+// Function uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<const T: usize>() {
+    unused::<T>()
+}
+
+fn main() {
+    no_parameters();
+    unused::<1>();
+    used_binding::<1>();
+    used_substs::<1>();
+}
diff --git a/tests/ui/polymorphization/const_parameters/functions.stderr b/tests/ui/polymorphization/const_parameters/functions.stderr
new file mode 100644
index 00000000000..9d0922ac7ca
--- /dev/null
+++ b/tests/ui/polymorphization/const_parameters/functions.stderr
@@ -0,0 +1,17 @@
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/functions.rs:3:12
+   |
+LL | #![feature(generic_const_exprs, rustc_attrs)]
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: item has unused generic parameters
+  --> $DIR/functions.rs:15:8
+   |
+LL | pub fn unused<const T: usize>() {
+   |        ^^^^^^ -------------- generic parameter `T` is unused
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/ui/polymorphization/drop_shims/simple.rs b/tests/ui/polymorphization/drop_shims/simple.rs
new file mode 100644
index 00000000000..2695dc6d4f1
--- /dev/null
+++ b/tests/ui/polymorphization/drop_shims/simple.rs
@@ -0,0 +1,22 @@
+// check-pass
+// compile-flags:-Zpolymorphize=on
+
+pub struct OnDrop<F: Fn()>(pub F);
+
+impl<F: Fn()> Drop for OnDrop<F> {
+    fn drop(&mut self) { }
+}
+
+fn foo<R, S: FnOnce()>(
+    _: R,
+    _: S,
+) {
+    let bar = || {
+        let _ = OnDrop(|| ());
+    };
+    let _ = bar();
+}
+
+fn main() {
+    foo(3u32, || {});
+}
diff --git a/tests/ui/polymorphization/drop_shims/transitive.rs b/tests/ui/polymorphization/drop_shims/transitive.rs
new file mode 100644
index 00000000000..c2289117109
--- /dev/null
+++ b/tests/ui/polymorphization/drop_shims/transitive.rs
@@ -0,0 +1,27 @@
+// check-pass
+// compile-flags:-Zpolymorphize=on
+
+pub struct OnDrop<F: Fn()>(pub F);
+
+impl<F: Fn()> Drop for OnDrop<F> {
+    fn drop(&mut self) { }
+}
+
+fn bar<F: FnOnce()>(f: F) {
+    let _ = OnDrop(|| ());
+    f()
+}
+
+fn foo<R, S: FnOnce()>(
+    _: R,
+    _: S,
+) {
+    let bar = || {
+        bar(|| {})
+    };
+    let _ = bar();
+}
+
+fn main() {
+    foo(3u32, || {});
+}
diff --git a/tests/ui/polymorphization/generators.rs b/tests/ui/polymorphization/generators.rs
new file mode 100644
index 00000000000..779bac0ace2
--- /dev/null
+++ b/tests/ui/polymorphization/generators.rs
@@ -0,0 +1,92 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on -Zinline-mir=off
+#![feature(generic_const_exprs, generators, generator_trait, rustc_attrs)]
+//~^ WARN the feature `generic_const_exprs` is incomplete
+
+use std::marker::Unpin;
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+enum YieldOrReturn<Y, R> {
+    Yield(Y),
+    Return(R),
+}
+
+fn finish<T, Y, R>(mut t: T) -> Vec<YieldOrReturn<Y, R>>
+where
+    T: Generator<(), Yield = Y, Return = R> + Unpin,
+{
+    let mut results = Vec::new();
+    loop {
+        match Pin::new(&mut t).resume(()) {
+            GeneratorState::Yielded(yielded) => results.push(YieldOrReturn::Yield(yielded)),
+            GeneratorState::Complete(returned) => {
+                results.push(YieldOrReturn::Return(returned));
+                return results;
+            }
+        }
+    }
+}
+
+// This test checks that the polymorphization analysis functions on generators.
+
+#[rustc_polymorphize_error]
+pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+    || {
+        //~^ ERROR item has unused generic parameters
+        yield 1;
+        2
+    }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_type_in_yield<Y: Default>() -> impl Generator<(), Yield = Y, Return = u32> + Unpin {
+    || {
+        yield Y::default();
+        2
+    }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_type_in_return<R: Default>() -> impl Generator<(), Yield = u32, Return = R> + Unpin {
+    || {
+        yield 3;
+        R::default()
+    }
+}
+
+#[rustc_polymorphize_error]
+pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+    || {
+        //~^ ERROR item has unused generic parameters
+        yield 1;
+        2
+    }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_const_in_yield<const Y: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin
+{
+    || {
+        yield Y;
+        2
+    }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_const_in_return<const R: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin
+{
+    || {
+        yield 4;
+        R
+    }
+}
+
+fn main() {
+    finish(unused_type::<u32>());
+    finish(used_type_in_yield::<u32>());
+    finish(used_type_in_return::<u32>());
+    finish(unused_const::<1u32>());
+    finish(used_const_in_yield::<1u32>());
+    finish(used_const_in_return::<1u32>());
+}
diff --git a/tests/ui/polymorphization/generators.stderr b/tests/ui/polymorphization/generators.stderr
new file mode 100644
index 00000000000..84888f6fb2f
--- /dev/null
+++ b/tests/ui/polymorphization/generators.stderr
@@ -0,0 +1,39 @@
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/generators.rs:3:12
+   |
+LL | #![feature(generic_const_exprs, generators, generator_trait, rustc_attrs)]
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: item has unused generic parameters
+  --> $DIR/generators.rs:35:5
+   |
+LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+   |                    - generic parameter `T` is unused
+LL |     || {
+   |     ^^
+
+note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:35:5: 35:7], u32, u32>`
+  --> $DIR/generators.rs:86:5
+   |
+LL |     finish(unused_type::<u32>());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/generators.rs:60:5
+   |
+LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+   |                     ------------ generic parameter `T` is unused
+LL |     || {
+   |     ^^
+
+note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:60:5: 60:7], u32, u32>`
+  --> $DIR/generators.rs:89:5
+   |
+LL |     finish(unused_const::<1u32>());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
diff --git a/tests/ui/polymorphization/issue-74614.rs b/tests/ui/polymorphization/issue-74614.rs
new file mode 100644
index 00000000000..8b0c00b1355
--- /dev/null
+++ b/tests/ui/polymorphization/issue-74614.rs
@@ -0,0 +1,18 @@
+// compile-flags:-Zpolymorphize=on
+// build-pass
+
+fn test<T>() {
+    std::mem::size_of::<T>();
+}
+
+pub fn foo<T>(_: T) -> &'static fn() {
+    &(test::<T> as fn())
+}
+
+fn outer<T>() {
+    foo(|| ());
+}
+
+fn main() {
+    outer::<u8>();
+}
diff --git a/tests/ui/polymorphization/issue-74636.rs b/tests/ui/polymorphization/issue-74636.rs
new file mode 100644
index 00000000000..4c532f451e3
--- /dev/null
+++ b/tests/ui/polymorphization/issue-74636.rs
@@ -0,0 +1,16 @@
+// compile-flags:-Zpolymorphize=on
+// build-pass
+
+use std::any::TypeId;
+
+pub fn foo<T: 'static>(_: T) -> TypeId {
+    TypeId::of::<T>()
+}
+
+fn outer<T: 'static>() {
+    foo(|| ());
+}
+
+fn main() {
+    outer::<u8>();
+}
diff --git a/tests/ui/polymorphization/lifetimes.rs b/tests/ui/polymorphization/lifetimes.rs
new file mode 100644
index 00000000000..f26df45230a
--- /dev/null
+++ b/tests/ui/polymorphization/lifetimes.rs
@@ -0,0 +1,25 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(rustc_attrs)]
+
+// This test checks that the polymorphization analysis doesn't break when the
+// function/closure doesn't just have generic parameters.
+
+// Function has an unused generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused<'a, T>(_: &'a u32) {
+    //~^ ERROR item has unused generic parameters
+}
+
+#[rustc_polymorphize_error]
+pub fn used<'a, T: Default>(_: &'a u32) -> u32 {
+    let _: T = Default::default();
+    let add_one = |x: u32| x + 1;
+    //~^ ERROR item has unused generic parameters
+    add_one(3)
+}
+
+fn main() {
+    unused::<u32>(&3);
+    used::<u32>(&3);
+}
diff --git a/tests/ui/polymorphization/lifetimes.stderr b/tests/ui/polymorphization/lifetimes.stderr
new file mode 100644
index 00000000000..4773dd4fa2e
--- /dev/null
+++ b/tests/ui/polymorphization/lifetimes.stderr
@@ -0,0 +1,17 @@
+error: item has unused generic parameters
+  --> $DIR/lifetimes.rs:10:8
+   |
+LL | pub fn unused<'a, T>(_: &'a u32) {
+   |        ^^^^^^     - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/lifetimes.rs:17:19
+   |
+LL | pub fn used<'a, T: Default>(_: &'a u32) -> u32 {
+   |                 - generic parameter `T` is unused
+LL |     let _: T = Default::default();
+LL |     let add_one = |x: u32| x + 1;
+   |                   ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/polymorphization/normalized_sig_types.rs b/tests/ui/polymorphization/normalized_sig_types.rs
new file mode 100644
index 00000000000..d732b1071d8
--- /dev/null
+++ b/tests/ui/polymorphization/normalized_sig_types.rs
@@ -0,0 +1,26 @@
+// build-pass
+// compile-flags:-Zpolymorphize=on
+
+pub trait ParallelIterator: Sized {
+    fn drive<C: Consumer<()>>(_: C) {
+        C::into_folder();
+    }
+}
+
+pub trait Consumer<T>: Sized {
+    type Result;
+    fn into_folder() -> Self::Result;
+}
+
+impl ParallelIterator for () {}
+
+impl<F: Fn(), T> Consumer<T> for F {
+    type Result = ();
+    fn into_folder() -> Self::Result {
+        unimplemented!()
+    }
+}
+
+fn main() {
+    <()>::drive(|| ());
+}
diff --git a/tests/ui/polymorphization/predicates.rs b/tests/ui/polymorphization/predicates.rs
new file mode 100644
index 00000000000..6a5fc2e33de
--- /dev/null
+++ b/tests/ui/polymorphization/predicates.rs
@@ -0,0 +1,95 @@
+// build-fail
+// compile-flags: -Copt-level=0 -Zpolymorphize=on
+
+#![feature(rustc_attrs)]
+
+// This test checks that `T` is considered used in `foo`, because it is used in a predicate for
+// `I`, which is used.
+
+#[rustc_polymorphize_error]
+fn bar<I>() {
+    //~^ ERROR item has unused generic parameters
+}
+
+#[rustc_polymorphize_error]
+fn foo<I, T>(_: I)
+//~^ ERROR item has unused generic parameters
+where
+    I: Iterator<Item = T>,
+{
+    bar::<I>()
+}
+
+#[rustc_polymorphize_error]
+fn baz<I, T>(_: I)
+//~^ ERROR item has unused generic parameters
+where
+    std::iter::Repeat<I>: Iterator<Item = T>,
+{
+    bar::<I>()
+}
+
+// In addition, check that `I` is considered used in `next::{{closure}}`, because `T` is used and
+// `T` is really just `I::Item`. `E` is used due to the fixed-point marking of predicates.
+
+pub(crate) struct Foo<'a, I, E>(I, &'a E);
+
+impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
+where
+    I: Iterator<Item = &'a (T, E)>,
+{
+    type Item = T;
+
+    #[rustc_polymorphize_error]
+    fn next(&mut self) -> Option<Self::Item> {
+        self.find(|_| true)
+        //~^ ERROR item has unused generic parameters
+    }
+}
+
+// Furthermore, check that `B` is considered used because `C` is used, and that `A` is considered
+// used because `B` is now used.
+
+trait Baz<Z> {}
+
+impl Baz<u16> for u8 {}
+impl Baz<u32> for u16 {}
+
+#[rustc_polymorphize_error]
+fn quux<A, B, C: Default>() -> usize
+//~^ ERROR item has unused generic parameters
+where
+    A: Baz<B>,
+    B: Baz<C>,
+{
+    std::mem::size_of::<C>()
+}
+
+// Finally, check that `F` is considered used because `G` is used when neither are in the self-ty
+// of the predicate.
+
+trait Foobar<F, G> {}
+
+impl Foobar<u32, u32> for () {}
+
+#[rustc_polymorphize_error]
+fn foobar<F, G>() -> usize
+//~^ ERROR item has unused generic parameters
+where
+    (): Foobar<F, G>,
+{
+    std::mem::size_of::<G>()
+}
+
+fn main() {
+    let x = &[2u32];
+    foo(x.iter());
+    baz(x.iter());
+
+    let mut a = Foo([(1u32, 1u16)].iter(), &1u16);
+    let _ = a.next();
+
+    let _ = quux::<u8, u16, u32>();
+
+    let _ = foobar::<u32, u32>();
+}
diff --git a/tests/ui/polymorphization/predicates.stderr b/tests/ui/polymorphization/predicates.stderr
new file mode 100644
index 00000000000..80bb2af25cc
--- /dev/null
+++ b/tests/ui/polymorphization/predicates.stderr
@@ -0,0 +1,51 @@
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:15:4
+   |
+LL | fn foo<I, T>(_: I)
+   |    ^^^    - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:24:4
+   |
+LL | fn baz<I, T>(_: I)
+   |    ^^^    - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:45:19
+   |
+LL | impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
+   |          -         - generic parameter `E` is unused
+   |          |
+   |          generic parameter `I` is unused
+...
+LL |         self.find(|_| true)
+   |                   ^^^
+
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:59:4
+   |
+LL | fn quux<A, B, C: Default>() -> usize
+   |    ^^^^ -  - generic parameter `B` is unused
+   |         |
+   |         generic parameter `A` is unused
+
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:76:4
+   |
+LL | fn foobar<F, G>() -> usize
+   |    ^^^^^^ - generic parameter `F` is unused
+
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:10:4
+   |
+LL | fn bar<I>() {
+   |    ^^^ - generic parameter `I` is unused
+
+note: the above error was encountered while instantiating `fn foo::<std::slice::Iter<'_, u32>, T>`
+  --> $DIR/predicates.rs:86:5
+   |
+LL |     foo(x.iter());
+   |     ^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/polymorphization/promoted-function-1.rs b/tests/ui/polymorphization/promoted-function-1.rs
new file mode 100644
index 00000000000..2cd02673442
--- /dev/null
+++ b/tests/ui/polymorphization/promoted-function-1.rs
@@ -0,0 +1,12 @@
+// build-fail
+// compile-flags: -Zpolymorphize=on
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+
+fn foo<'a>(_: &'a ()) {}
+
+#[rustc_polymorphize_error]
+pub fn test<T>() {
+    //~^ ERROR item has unused generic parameters
+    foo(&());
+}
diff --git a/tests/ui/polymorphization/promoted-function-1.stderr b/tests/ui/polymorphization/promoted-function-1.stderr
new file mode 100644
index 00000000000..fcbb8694923
--- /dev/null
+++ b/tests/ui/polymorphization/promoted-function-1.stderr
@@ -0,0 +1,8 @@
+error: item has unused generic parameters
+  --> $DIR/promoted-function-1.rs:9:8
+   |
+LL | pub fn test<T>() {
+   |        ^^^^ - generic parameter `T` is unused
+
+error: aborting due to previous error
+
diff --git a/tests/ui/polymorphization/promoted-function-2.rs b/tests/ui/polymorphization/promoted-function-2.rs
new file mode 100644
index 00000000000..d2d0f336812
--- /dev/null
+++ b/tests/ui/polymorphization/promoted-function-2.rs
@@ -0,0 +1,16 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![crate_type = "lib"]
+#![feature(generic_const_exprs, rustc_attrs)]
+//~^ WARN the feature `generic_const_exprs` is incomplete
+
+#[rustc_polymorphize_error]
+fn test<T>() {
+    //~^ ERROR item has unused generic parameters
+    let x = [0; 3 + 4];
+}
+
+pub fn caller() {
+    test::<String>();
+    test::<Vec<String>>();
+}
diff --git a/tests/ui/polymorphization/promoted-function-2.stderr b/tests/ui/polymorphization/promoted-function-2.stderr
new file mode 100644
index 00000000000..547569df7dc
--- /dev/null
+++ b/tests/ui/polymorphization/promoted-function-2.stderr
@@ -0,0 +1,17 @@
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/promoted-function-2.rs:4:12
+   |
+LL | #![feature(generic_const_exprs, rustc_attrs)]
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: item has unused generic parameters
+  --> $DIR/promoted-function-2.rs:8:4
+   |
+LL | fn test<T>() {
+   |    ^^^^ - generic parameter `T` is unused
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/ui/polymorphization/promoted-function-3.rs b/tests/ui/polymorphization/promoted-function-3.rs
new file mode 100644
index 00000000000..bbd991e36cc
--- /dev/null
+++ b/tests/ui/polymorphization/promoted-function-3.rs
@@ -0,0 +1,14 @@
+// run-pass
+// compile-flags: -Zpolymorphize=on -Zmir-opt-level=4
+
+fn caller<T, U>() -> &'static usize {
+    callee::<U>()
+}
+
+fn callee<T>() -> &'static usize {
+    &std::mem::size_of::<T>()
+}
+
+fn main() {
+    assert_eq!(caller::<(), ()>(), &0);
+}
diff --git a/tests/ui/polymorphization/promoted-function.rs b/tests/ui/polymorphization/promoted-function.rs
new file mode 100644
index 00000000000..a56a8e70e4c
--- /dev/null
+++ b/tests/ui/polymorphization/promoted-function.rs
@@ -0,0 +1,15 @@
+// run-pass
+// compile-flags:-Zpolymorphize=on
+
+fn fop<T>() {}
+
+fn bar<T>() -> &'static fn() {
+    &(fop::<T> as fn())
+}
+pub const FN: &'static fn() = &(fop::<i32> as fn());
+
+fn main() {
+    bar::<u32>();
+    bar::<i32>();
+    (FN)();
+}
diff --git a/tests/ui/polymorphization/symbol-ambiguity.rs b/tests/ui/polymorphization/symbol-ambiguity.rs
new file mode 100644
index 00000000000..6277a902fa2
--- /dev/null
+++ b/tests/ui/polymorphization/symbol-ambiguity.rs
@@ -0,0 +1,22 @@
+// build-pass
+// compile-flags: -Zpolymorphize=on -Csymbol-mangling-version=v0
+
+pub(crate) struct Foo<'a, I, E>(I, &'a E);
+
+impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
+where
+    I: Iterator<Item = &'a (T, E)>,
+{
+    type Item = T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.find(|_| true)
+    }
+}
+
+fn main() {
+    let mut a = Foo([(1u32, 1u16)].iter(), &1u16);
+    let mut b = Foo([(1u16, 1u32)].iter(), &1u32);
+    let _ = a.next();
+    let _ = b.next();
+}
diff --git a/tests/ui/polymorphization/too-many-generic-params.rs b/tests/ui/polymorphization/too-many-generic-params.rs
new file mode 100644
index 00000000000..ec6244630fd
--- /dev/null
+++ b/tests/ui/polymorphization/too-many-generic-params.rs
@@ -0,0 +1,85 @@
+// build-pass
+#![feature(rustc_attrs)]
+
+// This test checks that the analysis doesn't panic when there are >64 generic parameters, but
+// instead considers those parameters used.
+
+#[rustc_polymorphize_error]
+fn bar<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA,
+       AB, AC, AD, AE, AF, AG, AH, AI, AJ, AK, AL, AM, AN, AO, AP, AQ, AR, AS, AT, AU, AV, AW,
+       AX, AY, AZ, BA, BB, BC, BD, BE, BF, BG, BH, BI, BJ, BK, BL, BM>()
+{
+    let _: Option<A> = None;
+    let _: Option<B> = None;
+    let _: Option<C> = None;
+    let _: Option<D> = None;
+    let _: Option<E> = None;
+    let _: Option<F> = None;
+    let _: Option<G> = None;
+    let _: Option<H> = None;
+    let _: Option<I> = None;
+    let _: Option<J> = None;
+    let _: Option<K> = None;
+    let _: Option<L> = None;
+    let _: Option<M> = None;
+    let _: Option<N> = None;
+    let _: Option<O> = None;
+    let _: Option<P> = None;
+    let _: Option<Q> = None;
+    let _: Option<R> = None;
+    let _: Option<S> = None;
+    let _: Option<T> = None;
+    let _: Option<U> = None;
+    let _: Option<V> = None;
+    let _: Option<W> = None;
+    let _: Option<X> = None;
+    let _: Option<Y> = None;
+    let _: Option<Z> = None;
+    let _: Option<AA> = None;
+    let _: Option<AB> = None;
+    let _: Option<AC> = None;
+    let _: Option<AD> = None;
+    let _: Option<AE> = None;
+    let _: Option<AF> = None;
+    let _: Option<AG> = None;
+    let _: Option<AH> = None;
+    let _: Option<AI> = None;
+    let _: Option<AJ> = None;
+    let _: Option<AK> = None;
+    let _: Option<AL> = None;
+    let _: Option<AM> = None;
+    let _: Option<AN> = None;
+    let _: Option<AO> = None;
+    let _: Option<AP> = None;
+    let _: Option<AQ> = None;
+    let _: Option<AR> = None;
+    let _: Option<AS> = None;
+    let _: Option<AT> = None;
+    let _: Option<AU> = None;
+    let _: Option<AV> = None;
+    let _: Option<AW> = None;
+    let _: Option<AX> = None;
+    let _: Option<AY> = None;
+    let _: Option<AZ> = None;
+    let _: Option<BA> = None;
+    let _: Option<BB> = None;
+    let _: Option<BC> = None;
+    let _: Option<BD> = None;
+    let _: Option<BE> = None;
+    let _: Option<BF> = None;
+    let _: Option<BG> = None;
+    let _: Option<BH> = None;
+    let _: Option<BI> = None;
+    let _: Option<BJ> = None;
+    let _: Option<BK> = None;
+    let _: Option<BL> = None;
+    let _: Option<BM> = None;
+}
+
+fn main() {
+    bar::<u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+          u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+          u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+          u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+          u32>();
+}
diff --git a/tests/ui/polymorphization/type_parameters/closures.rs b/tests/ui/polymorphization/type_parameters/closures.rs
new file mode 100644
index 00000000000..07ab1355a47
--- /dev/null
+++ b/tests/ui/polymorphization/type_parameters/closures.rs
@@ -0,0 +1,161 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(stmt_expr_attributes, rustc_attrs)]
+
+// This test checks that the polymorphization analysis correctly detects unused type
+// parameters in closures.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {
+    let _ = || {};
+}
+
+// Function has an unused generic parameter in parent and closure.
+#[rustc_polymorphize_error]
+pub fn unused<T>() -> u32 {
+    //~^ ERROR item has unused generic parameters
+
+    let add_one = |x: u32| x + 1;
+    //~^ ERROR item has unused generic parameters
+    add_one(3)
+}
+
+// Function has an unused generic parameter in closure, but not in parent.
+#[rustc_polymorphize_error]
+pub fn used_parent<T: Default>() -> u32 {
+    let _: T = Default::default();
+    let add_one = |x: u32| x + 1;
+    //~^ ERROR item has unused generic parameters
+    add_one(3)
+}
+
+// Function uses generic parameter in value of a binding in closure.
+#[rustc_polymorphize_error]
+pub fn used_binding_value<T: Default>() -> T {
+    let x = || {
+        let y: T = Default::default();
+        y
+    };
+
+    x()
+}
+
+// Function uses generic parameter in generic of a binding in closure.
+#[rustc_polymorphize_error]
+pub fn used_binding_generic<T>() -> Option<T> {
+    let x = || {
+        let y: Option<T> = None;
+        y
+    };
+
+    x()
+}
+
+// Function and closure uses generic parameter in argument.
+#[rustc_polymorphize_error]
+pub fn used_argument<T>(t: T) -> u32 {
+    let x = |_: T| 3;
+    x(t)
+}
+
+// Closure uses generic parameter in argument.
+#[rustc_polymorphize_error]
+pub fn used_argument_closure<T: Default>() -> u32 {
+    let t: T = Default::default();
+
+    let x = |_: T| 3;
+    x(t)
+}
+
+// Closure uses generic parameter as upvar.
+#[rustc_polymorphize_error]
+pub fn used_upvar<T: Default>() -> T {
+    let x: T = Default::default();
+
+    let y = || x;
+    y()
+}
+
+// Closure uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<T>() -> u32 {
+    let x = || unused::<T>();
+    x()
+}
+
+struct Foo<F>(F);
+
+impl<F: Default> Foo<F> {
+    // Function has an unused generic parameter from impl and fn.
+    #[rustc_polymorphize_error]
+    pub fn unused_all<G: Default>() -> u32 {
+        //~^ ERROR item has unused generic parameters
+        let add_one = |x: u32| x + 1;
+        //~^ ERROR item has unused generic parameters
+        add_one(3)
+    }
+
+    // Function uses generic parameter from impl and fn in closure.
+    #[rustc_polymorphize_error]
+    pub fn used_both<G: Default>() -> u32 {
+        let add_one = |x: u32| {
+            let _: F = Default::default();
+            let _: G = Default::default();
+            x + 1
+        };
+
+        add_one(3)
+    }
+
+    // Function uses generic parameter from fn in closure.
+    #[rustc_polymorphize_error]
+    pub fn used_fn<G: Default>() -> u32 {
+        //~^ ERROR item has unused generic parameters
+        let add_one = |x: u32| {
+            //~^ ERROR item has unused generic parameters
+            let _: G = Default::default();
+            x + 1
+        };
+
+        add_one(3)
+    }
+
+    // Function uses generic parameter from impl in closure.
+    #[rustc_polymorphize_error]
+    pub fn used_impl<G: Default>() -> u32 {
+        //~^ ERROR item has unused generic parameters
+        let add_one = |x: u32| {
+            //~^ ERROR item has unused generic parameters
+            let _: F = Default::default();
+            x + 1
+        };
+
+        add_one(3)
+    }
+
+    // Closure uses generic parameter in substitutions to another function.
+    #[rustc_polymorphize_error]
+    pub fn used_substs() -> u32 {
+        let x = || unused::<F>();
+        x()
+    }
+}
+
+fn main() {
+    no_parameters();
+    let _ = unused::<u32>();
+    let _ = used_parent::<u32>();
+    let _ = used_binding_value::<u32>();
+    let _ = used_binding_generic::<u32>();
+    let _ = used_argument(3u32);
+    let _ = used_argument_closure::<u32>();
+    let _ = used_upvar::<u32>();
+    let _ = used_substs::<u32>();
+
+    let _ = Foo::<u32>::unused_all::<u32>();
+    let _ = Foo::<u32>::used_both::<u32>();
+    let _ = Foo::<u32>::used_impl::<u32>();
+    let _ = Foo::<u32>::used_fn::<u32>();
+    let _ = Foo::<u32>::used_substs();
+}
diff --git a/tests/ui/polymorphization/type_parameters/closures.stderr b/tests/ui/polymorphization/type_parameters/closures.stderr
new file mode 100644
index 00000000000..94a4a08bd2f
--- /dev/null
+++ b/tests/ui/polymorphization/type_parameters/closures.stderr
@@ -0,0 +1,80 @@
+error: item has unused generic parameters
+  --> $DIR/closures.rs:19:19
+   |
+LL | pub fn unused<T>() -> u32 {
+   |               - generic parameter `T` is unused
+...
+LL |     let add_one = |x: u32| x + 1;
+   |                   ^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:16:8
+   |
+LL | pub fn unused<T>() -> u32 {
+   |        ^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:28:19
+   |
+LL | pub fn used_parent<T: Default>() -> u32 {
+   |                    - generic parameter `T` is unused
+LL |     let _: T = Default::default();
+LL |     let add_one = |x: u32| x + 1;
+   |                   ^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:94:23
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn unused_all<G: Default>() -> u32 {
+   |                       - generic parameter `G` is unused
+LL |
+LL |         let add_one = |x: u32| x + 1;
+   |                       ^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:92:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn unused_all<G: Default>() -> u32 {
+   |            ^^^^^^^^^^ - generic parameter `G` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:128:23
+   |
+LL |     pub fn used_impl<G: Default>() -> u32 {
+   |                      - generic parameter `G` is unused
+LL |
+LL |         let add_one = |x: u32| {
+   |                       ^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:126:12
+   |
+LL |     pub fn used_impl<G: Default>() -> u32 {
+   |            ^^^^^^^^^ - generic parameter `G` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:115:23
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |         let add_one = |x: u32| {
+   |                       ^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:113:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn used_fn<G: Default>() -> u32 {
+   |            ^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/polymorphization/type_parameters/functions.rs b/tests/ui/polymorphization/type_parameters/functions.rs
new file mode 100644
index 00000000000..aad957e1dd3
--- /dev/null
+++ b/tests/ui/polymorphization/type_parameters/functions.rs
@@ -0,0 +1,96 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(rustc_attrs)]
+
+// This test checks that the polymorphization analysis correctly detects unused type
+// parameters in functions.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {}
+
+// Function has an unused generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused<T>() {
+    //~^ ERROR item has unused generic parameters
+}
+
+// Function uses generic parameter in value of a binding.
+#[rustc_polymorphize_error]
+pub fn used_binding_value<T: Default>() {
+    let _: T = Default::default();
+}
+
+// Function uses generic parameter in generic of a binding.
+#[rustc_polymorphize_error]
+pub fn used_binding_generic<T>() {
+    let _: Option<T> = None;
+}
+
+// Function uses generic parameter in argument.
+#[rustc_polymorphize_error]
+pub fn used_argument<T>(_: T) {}
+
+// Function uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<T>() {
+    unused::<T>()
+}
+
+struct Foo<F>(F);
+
+impl<F: Default> Foo<F> {
+    // Function has an unused generic parameter from impl.
+    #[rustc_polymorphize_error]
+    pub fn unused_impl() {
+        //~^ ERROR item has unused generic parameters
+    }
+
+    // Function has an unused generic parameter from impl and fn.
+    #[rustc_polymorphize_error]
+    pub fn unused_both<G: Default>() {
+        //~^ ERROR item has unused generic parameters
+    }
+
+    // Function uses generic parameter from impl.
+    #[rustc_polymorphize_error]
+    pub fn used_impl() {
+        let _: F = Default::default();
+    }
+
+    // Function uses generic parameter from impl.
+    #[rustc_polymorphize_error]
+    pub fn used_fn<G: Default>() {
+        //~^ ERROR item has unused generic parameters
+        let _: G = Default::default();
+    }
+
+    // Function uses generic parameter from impl.
+    #[rustc_polymorphize_error]
+    pub fn used_both<G: Default>() {
+        let _: F = Default::default();
+        let _: G = Default::default();
+    }
+
+    // Function uses generic parameter in substitutions to another function.
+    #[rustc_polymorphize_error]
+    pub fn used_substs() {
+        unused::<F>()
+    }
+}
+
+fn main() {
+    no_parameters();
+    unused::<u32>();
+    used_binding_value::<u32>();
+    used_binding_generic::<u32>();
+    used_argument(3u32);
+    used_substs::<u32>();
+
+    Foo::<u32>::unused_impl();
+    Foo::<u32>::unused_both::<u32>();
+    Foo::<u32>::used_impl();
+    Foo::<u32>::used_fn::<u32>();
+    Foo::<u32>::used_both::<u32>();
+    Foo::<u32>::used_substs();
+}
diff --git a/tests/ui/polymorphization/type_parameters/functions.stderr b/tests/ui/polymorphization/type_parameters/functions.stderr
new file mode 100644
index 00000000000..d629ff7bb4d
--- /dev/null
+++ b/tests/ui/polymorphization/type_parameters/functions.stderr
@@ -0,0 +1,35 @@
+error: item has unused generic parameters
+  --> $DIR/functions.rs:14:8
+   |
+LL | pub fn unused<T>() {
+   |        ^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/functions.rs:45:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn unused_impl() {
+   |            ^^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/functions.rs:51:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn unused_both<G: Default>() {
+   |            ^^^^^^^^^^^ - generic parameter `G` is unused
+
+error: item has unused generic parameters
+  --> $DIR/functions.rs:63:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+...
+LL |     pub fn used_fn<G: Default>() {
+   |            ^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/polymorphization/unsized_cast.rs b/tests/ui/polymorphization/unsized_cast.rs
new file mode 100644
index 00000000000..b803fec2ccf
--- /dev/null
+++ b/tests/ui/polymorphization/unsized_cast.rs
@@ -0,0 +1,30 @@
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(fn_traits, rustc_attrs, unboxed_closures)]
+
+// This test checks that the polymorphization analysis considers a closure
+// as using all generic parameters if it does an unsizing cast.
+
+#[rustc_polymorphize_error]
+fn foo<T: Default>() {
+    let _: T = Default::default();
+    (|| Box::new(|| {}) as Box<dyn Fn()>)();
+    //~^ ERROR item has unused generic parameters
+    //~^^ ERROR item has unused generic parameters
+}
+
+#[rustc_polymorphize_error]
+fn foo2<T: Default>() {
+    let _: T = Default::default();
+    (|| {
+        //~^ ERROR item has unused generic parameters
+        let call: extern "rust-call" fn(_, _) = Fn::call;
+        call(&|| {}, ());
+        //~^ ERROR item has unused generic parameters
+    })();
+}
+
+fn main() {
+    foo::<u32>();
+    foo2::<u32>();
+}
diff --git a/tests/ui/polymorphization/unsized_cast.stderr b/tests/ui/polymorphization/unsized_cast.stderr
new file mode 100644
index 00000000000..27f88d28174
--- /dev/null
+++ b/tests/ui/polymorphization/unsized_cast.stderr
@@ -0,0 +1,38 @@
+error: item has unused generic parameters
+  --> $DIR/unsized_cast.rs:11:18
+   |
+LL | fn foo<T: Default>() {
+   |        - generic parameter `T` is unused
+LL |     let _: T = Default::default();
+LL |     (|| Box::new(|| {}) as Box<dyn Fn()>)();
+   |                  ^^
+
+error: item has unused generic parameters
+  --> $DIR/unsized_cast.rs:11:6
+   |
+LL | fn foo<T: Default>() {
+   |        - generic parameter `T` is unused
+LL |     let _: T = Default::default();
+LL |     (|| Box::new(|| {}) as Box<dyn Fn()>)();
+   |      ^^
+
+error: item has unused generic parameters
+  --> $DIR/unsized_cast.rs:22:15
+   |
+LL | fn foo2<T: Default>() {
+   |         - generic parameter `T` is unused
+...
+LL |         call(&|| {}, ());
+   |               ^^
+
+error: item has unused generic parameters
+  --> $DIR/unsized_cast.rs:19:6
+   |
+LL | fn foo2<T: Default>() {
+   |         - generic parameter `T` is unused
+LL |     let _: T = Default::default();
+LL |     (|| {
+   |      ^^
+
+error: aborting due to 4 previous errors
+