about summary refs log tree commit diff
path: root/src/test/ui/polymorphization
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2020-06-22 13:57:03 +0100
committerDavid Wood <david@davidtw.co>2020-07-20 19:35:30 +0100
commit2989fea88a489a01b3e2243bb84b0ec20b8a0e28 (patch)
tree3fc7bedb5e5c8531c204b79510f7d61dd33f1e65 /src/test/ui/polymorphization
parent47756bb0faaf49be5c4086fd0fdbdd57f055781b (diff)
downloadrust-2989fea88a489a01b3e2243bb84b0ec20b8a0e28.tar.gz
rust-2989fea88a489a01b3e2243bb84b0ec20b8a0e28.zip
mir: `unused_generic_params` query
This commit implements the `unused_generic_params` query, an initial
version of polymorphization which detects when an item does not use
generic parameters and is being needlessly monomorphized as a result.

Signed-off-by: David Wood <david@davidtw.co>
Diffstat (limited to 'src/test/ui/polymorphization')
-rw-r--r--src/test/ui/polymorphization/const_parameters/closures.rs61
-rw-r--r--src/test/ui/polymorphization/const_parameters/closures.stderr44
-rw-r--r--src/test/ui/polymorphization/const_parameters/functions.rs33
-rw-r--r--src/test/ui/polymorphization/const_parameters/functions.stderr17
-rw-r--r--src/test/ui/polymorphization/drop_shims/simple.rs21
-rw-r--r--src/test/ui/polymorphization/drop_shims/transitive.rs26
-rw-r--r--src/test/ui/polymorphization/generators.rs88
-rw-r--r--src/test/ui/polymorphization/generators.stderr49
-rw-r--r--src/test/ui/polymorphization/lifetimes.rs22
-rw-r--r--src/test/ui/polymorphization/lifetimes.stderr17
-rw-r--r--src/test/ui/polymorphization/predicates.rs21
-rw-r--r--src/test/ui/polymorphization/predicates.stderr8
-rw-r--r--src/test/ui/polymorphization/too-many-generic-params.rs76
-rw-r--r--src/test/ui/polymorphization/type_parameters/closures.rs143
-rw-r--r--src/test/ui/polymorphization/type_parameters/closures.stderr90
-rw-r--r--src/test/ui/polymorphization/type_parameters/functions.rs84
-rw-r--r--src/test/ui/polymorphization/type_parameters/functions.stderr35
-rw-r--r--src/test/ui/polymorphization/unsized_cast.rs27
-rw-r--r--src/test/ui/polymorphization/unsized_cast.stderr29
19 files changed, 891 insertions, 0 deletions
diff --git a/src/test/ui/polymorphization/const_parameters/closures.rs b/src/test/ui/polymorphization/const_parameters/closures.rs
new file mode 100644
index 00000000000..da83cc1bee4
--- /dev/null
+++ b/src/test/ui/polymorphization/const_parameters/closures.rs
@@ -0,0 +1,61 @@
+// build-fail
+// compile-flags: -Zpolymorphize-errors
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` 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.
+pub fn no_parameters() {
+    let _ = || {};
+}
+
+// Function has an unused generic parameter in parent and closure.
+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.
+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.
+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.
+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.
+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/src/test/ui/polymorphization/const_parameters/closures.stderr b/src/test/ui/polymorphization/const_parameters/closures.stderr
new file mode 100644
index 00000000000..73a071f346a
--- /dev/null
+++ b/src/test/ui/polymorphization/const_parameters/closures.stderr
@@ -0,0 +1,44 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/closures.rs:3:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:17: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:15:8
+   |
+LL | pub fn unused<const T: usize>() -> usize {
+   |        ^^^^^^       - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:25: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:43: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/src/test/ui/polymorphization/const_parameters/functions.rs b/src/test/ui/polymorphization/const_parameters/functions.rs
new file mode 100644
index 00000000000..1c19f9480b4
--- /dev/null
+++ b/src/test/ui/polymorphization/const_parameters/functions.rs
@@ -0,0 +1,33 @@
+// build-fail
+// compile-flags: -Zpolymorphize-errors
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` 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.
+pub fn no_parameters() {}
+
+// Function has an unused generic parameter.
+pub fn unused<const T: usize>() {
+//~^ ERROR item has unused generic parameters
+}
+
+// Function uses generic parameter in value of a binding.
+pub fn used_binding<const T: usize>() -> usize {
+    let x: usize = T;
+    x
+}
+
+// Function uses generic parameter in substitutions to another function.
+pub fn used_substs<const T: usize>() {
+    unused::<T>()
+}
+
+fn main() {
+    no_parameters();
+    unused::<1>();
+    used_binding::<1>();
+    used_substs::<1>();
+}
diff --git a/src/test/ui/polymorphization/const_parameters/functions.stderr b/src/test/ui/polymorphization/const_parameters/functions.stderr
new file mode 100644
index 00000000000..a503ec51942
--- /dev/null
+++ b/src/test/ui/polymorphization/const_parameters/functions.stderr
@@ -0,0 +1,17 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/functions.rs:3:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: item has unused generic parameters
+  --> $DIR/functions.rs:13: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/src/test/ui/polymorphization/drop_shims/simple.rs b/src/test/ui/polymorphization/drop_shims/simple.rs
new file mode 100644
index 00000000000..ce56b7a3588
--- /dev/null
+++ b/src/test/ui/polymorphization/drop_shims/simple.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+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/src/test/ui/polymorphization/drop_shims/transitive.rs b/src/test/ui/polymorphization/drop_shims/transitive.rs
new file mode 100644
index 00000000000..b7ea07b6bc6
--- /dev/null
+++ b/src/test/ui/polymorphization/drop_shims/transitive.rs
@@ -0,0 +1,26 @@
+// check-pass
+
+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/src/test/ui/polymorphization/generators.rs b/src/test/ui/polymorphization/generators.rs
new file mode 100644
index 00000000000..dd7c3497de2
--- /dev/null
+++ b/src/test/ui/polymorphization/generators.rs
@@ -0,0 +1,88 @@
+// build-fail
+// compile-flags: -Zpolymorphize-errors
+#![feature(const_generics, generators, generator_trait)]
+//~^ WARN the feature `const_generics` 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.
+
+pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+    //~^ ERROR item has unused generic parameters
+    || {
+        //~^ ERROR item has unused generic parameters
+        yield 1;
+        2
+    }
+}
+
+pub fn used_type_in_yield<Y: Default>() -> impl Generator<(), Yield = Y, Return = u32> + Unpin {
+    || {
+        yield Y::default();
+        2
+    }
+}
+
+pub fn used_type_in_return<R: Default>() -> impl Generator<(), Yield = u32, Return = R> + Unpin {
+    || {
+        yield 3;
+        R::default()
+    }
+}
+
+pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+    //~^ ERROR item has unused generic parameters
+    || {
+        //~^ ERROR item has unused generic parameters
+        yield 1;
+        2
+    }
+}
+
+pub fn used_const_in_yield<const Y: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin
+{
+    || {
+        yield Y;
+        2
+    }
+}
+
+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/src/test/ui/polymorphization/generators.stderr b/src/test/ui/polymorphization/generators.stderr
new file mode 100644
index 00000000000..9e3ee130234
--- /dev/null
+++ b/src/test/ui/polymorphization/generators.stderr
@@ -0,0 +1,49 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/generators.rs:3:12
+   |
+LL | #![feature(const_generics, generators, generator_trait)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+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 |
+LL | /     || {
+LL | |
+LL | |         yield 1;
+LL | |         2
+LL | |     }
+   | |_____^
+
+error: item has unused generic parameters
+  --> $DIR/generators.rs:33:8
+   |
+LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+   |        ^^^^^^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/generators.rs:58:5
+   |
+LL |   pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+   |                             - generic parameter `T` is unused
+LL |
+LL | /     || {
+LL | |
+LL | |         yield 1;
+LL | |         2
+LL | |     }
+   | |_____^
+
+error: item has unused generic parameters
+  --> $DIR/generators.rs:56:8
+   |
+LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+   |        ^^^^^^^^^^^^       - generic parameter `T` is unused
+
+error: aborting due to 4 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/polymorphization/lifetimes.rs b/src/test/ui/polymorphization/lifetimes.rs
new file mode 100644
index 00000000000..873a9c7baaa
--- /dev/null
+++ b/src/test/ui/polymorphization/lifetimes.rs
@@ -0,0 +1,22 @@
+// build-fail
+// compile-flags: -Zpolymorphize-errors
+
+// 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.
+pub fn unused<'a, T>(_: &'a u32) {
+//~^ ERROR item has unused generic parameters
+}
+
+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/src/test/ui/polymorphization/lifetimes.stderr b/src/test/ui/polymorphization/lifetimes.stderr
new file mode 100644
index 00000000000..5629857f85e
--- /dev/null
+++ b/src/test/ui/polymorphization/lifetimes.stderr
@@ -0,0 +1,17 @@
+error: item has unused generic parameters
+  --> $DIR/lifetimes.rs:8:8
+   |
+LL | pub fn unused<'a, T>(_: &'a u32) {
+   |        ^^^^^^     - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/lifetimes.rs:14: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/src/test/ui/polymorphization/predicates.rs b/src/test/ui/polymorphization/predicates.rs
new file mode 100644
index 00000000000..49f8668cff8
--- /dev/null
+++ b/src/test/ui/polymorphization/predicates.rs
@@ -0,0 +1,21 @@
+// build-fail
+// compile-flags: -Zpolymorphize-errors
+
+// This test checks that `T` is considered used in `foo`, because it is used in a predicate for
+// `I`, which is used.
+
+fn bar<I>() {
+//~^ ERROR item has unused generic parameters
+}
+
+fn foo<I, T>(_: I)
+where
+    I: Iterator<Item = T>,
+{
+    bar::<I>()
+}
+
+fn main() {
+    let x = &[2u32];
+    foo(x.iter());
+}
diff --git a/src/test/ui/polymorphization/predicates.stderr b/src/test/ui/polymorphization/predicates.stderr
new file mode 100644
index 00000000000..b7bc2ccce57
--- /dev/null
+++ b/src/test/ui/polymorphization/predicates.stderr
@@ -0,0 +1,8 @@
+error: item has unused generic parameters
+  --> $DIR/predicates.rs:7:4
+   |
+LL | fn bar<I>() {
+   |    ^^^ - generic parameter `I` is unused
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/polymorphization/too-many-generic-params.rs b/src/test/ui/polymorphization/too-many-generic-params.rs
new file mode 100644
index 00000000000..3bb77a1c1e6
--- /dev/null
+++ b/src/test/ui/polymorphization/too-many-generic-params.rs
@@ -0,0 +1,76 @@
+// build-pass
+// compile-flags: -Zpolymorphize-errors
+
+// This test checks that the analysis doesn't panic when there are >64 generic parameters, but
+// instead considers those parameters used.
+
+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>()
+{
+    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<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;
+}
+
+fn main() { }
diff --git a/src/test/ui/polymorphization/type_parameters/closures.rs b/src/test/ui/polymorphization/type_parameters/closures.rs
new file mode 100644
index 00000000000..cf5a4b1cec5
--- /dev/null
+++ b/src/test/ui/polymorphization/type_parameters/closures.rs
@@ -0,0 +1,143 @@
+// build-fail
+// compile-flags: -Zpolymorphize-errors
+
+// This test checks that the polymorphization analysis correctly detects unused type
+// parameters in closures.
+
+// Function doesn't have any generic parameters to be unused.
+pub fn no_parameters() {
+    let _ = || {};
+}
+
+// Function has an unused generic parameter in parent and closure.
+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.
+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.
+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.
+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.
+pub fn used_argument<T>(t: T) -> u32 {
+    let x = |_: T| 3;
+    x(t)
+}
+
+// Closure uses generic parameter in argument.
+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.
+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.
+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.
+    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.
+    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.
+    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.
+    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.
+    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/src/test/ui/polymorphization/type_parameters/closures.stderr b/src/test/ui/polymorphization/type_parameters/closures.stderr
new file mode 100644
index 00000000000..914cb628bd0
--- /dev/null
+++ b/src/test/ui/polymorphization/type_parameters/closures.stderr
@@ -0,0 +1,90 @@
+error: item has unused generic parameters
+  --> $DIR/closures.rs:15:19
+   |
+LL | pub fn unused<T>() -> u32 {
+   |               - generic parameter `T` is unused
+LL |
+LL |     let add_one = |x: u32| x + 1;
+   |                   ^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:13:8
+   |
+LL | pub fn unused<T>() -> u32 {
+   |        ^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:23: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:80:23
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+LL |     // Function has an unused generic parameter from impl and fn.
+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:78:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+LL |     // Function has an unused generic parameter from impl and fn.
+LL |     pub fn unused_all<G: Default>() -> u32 {
+   |            ^^^^^^^^^^ - generic parameter `G` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:111:23
+   |
+LL |       pub fn used_impl<G: Default>() -> u32 {
+   |                        - generic parameter `G` is unused
+LL |
+LL |           let add_one = |x: u32| {
+   |  _______________________^
+LL | |
+LL | |             let _: F = Default::default();
+LL | |             x + 1
+LL | |         };
+   | |_________^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:109:12
+   |
+LL |     pub fn used_impl<G: Default>() -> u32 {
+   |            ^^^^^^^^^ - generic parameter `G` is unused
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:99:23
+   |
+LL |   impl<F: Default> Foo<F> {
+   |        - generic parameter `F` is unused
+...
+LL |           let add_one = |x: u32| {
+   |  _______________________^
+LL | |
+LL | |             let _: G = Default::default();
+LL | |             x + 1
+LL | |         };
+   | |_________^
+
+error: item has unused generic parameters
+  --> $DIR/closures.rs:97: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/src/test/ui/polymorphization/type_parameters/functions.rs b/src/test/ui/polymorphization/type_parameters/functions.rs
new file mode 100644
index 00000000000..3caf2631a57
--- /dev/null
+++ b/src/test/ui/polymorphization/type_parameters/functions.rs
@@ -0,0 +1,84 @@
+// build-fail
+// compile-flags: -Zpolymorphize-errors
+
+// This test checks that the polymorphization analysis correctly detects unused type
+// parameters in functions.
+
+// Function doesn't have any generic parameters to be unused.
+pub fn no_parameters() {}
+
+// Function has an unused generic parameter.
+pub fn unused<T>() {
+//~^ ERROR item has unused generic parameters
+}
+
+// Function uses generic parameter in value of a binding.
+pub fn used_binding_value<T: Default>() {
+    let _: T = Default::default();
+}
+
+// Function uses generic parameter in generic of a binding.
+pub fn used_binding_generic<T>() {
+    let _: Option<T> = None;
+}
+
+// Function uses generic parameter in argument.
+pub fn used_argument<T>(_: T) {
+}
+
+// Function uses generic parameter in substitutions to another function.
+pub fn used_substs<T>() {
+    unused::<T>()
+}
+
+struct Foo<F>(F);
+
+impl<F: Default> Foo<F> {
+    // Function has an unused generic parameter from impl.
+    pub fn unused_impl() {
+//~^ ERROR item has unused generic parameters
+    }
+
+    // Function has an unused generic parameter from impl and fn.
+    pub fn unused_both<G: Default>() {
+//~^ ERROR item has unused generic parameters
+    }
+
+    // Function uses generic parameter from impl.
+    pub fn used_impl() {
+        let _: F = Default::default();
+    }
+
+    // Function uses generic parameter from impl.
+    pub fn used_fn<G: Default>() {
+//~^ ERROR item has unused generic parameters
+        let _: G = Default::default();
+    }
+
+    // Function uses generic parameter from impl.
+    pub fn used_both<G: Default>() {
+        let _: F = Default::default();
+        let _: G = Default::default();
+    }
+
+    // Function uses generic parameter in substitutions to another function.
+    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/src/test/ui/polymorphization/type_parameters/functions.stderr b/src/test/ui/polymorphization/type_parameters/functions.stderr
new file mode 100644
index 00000000000..a34e677a765
--- /dev/null
+++ b/src/test/ui/polymorphization/type_parameters/functions.stderr
@@ -0,0 +1,35 @@
+error: item has unused generic parameters
+  --> $DIR/functions.rs:11:8
+   |
+LL | pub fn unused<T>() {
+   |        ^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+  --> $DIR/functions.rs:38:12
+   |
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
+LL |     // Function has an unused generic parameter from impl.
+LL |     pub fn unused_impl() {
+   |            ^^^^^^^^^^^
+
+error: item has unused generic parameters
+  --> $DIR/functions.rs:43: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:53: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/src/test/ui/polymorphization/unsized_cast.rs b/src/test/ui/polymorphization/unsized_cast.rs
new file mode 100644
index 00000000000..3bc25d18981
--- /dev/null
+++ b/src/test/ui/polymorphization/unsized_cast.rs
@@ -0,0 +1,27 @@
+// build-fail
+// compile-flags: -Zpolymorphize-errors
+#![feature(fn_traits, unboxed_closures)]
+
+// This test checks that the polymorphization analysis considers a closure
+// as using all generic parameters if it does an unsizing cast.
+
+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
+}
+
+fn foo2<T: Default>() {
+    let _: T = Default::default();
+    (|| {
+        let call: extern "rust-call" fn(_, _) = Fn::call;
+        call(&|| {}, ());
+        //~^ ERROR item has unused generic parameters
+    })();
+}
+
+fn main() {
+    foo::<u32>();
+    foo2::<u32>();
+}
diff --git a/src/test/ui/polymorphization/unsized_cast.stderr b/src/test/ui/polymorphization/unsized_cast.stderr
new file mode 100644
index 00000000000..61fd3884117
--- /dev/null
+++ b/src/test/ui/polymorphization/unsized_cast.stderr
@@ -0,0 +1,29 @@
+error: item has unused generic parameters
+  --> $DIR/unsized_cast.rs:10: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:10:5
+   |
+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:19:15
+   |
+LL | fn foo2<T: Default>() {
+   |         - generic parameter `T` is unused
+...
+LL |         call(&|| {}, ());
+   |               ^^^^^
+
+error: aborting due to 3 previous errors
+