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>
This commit is contained in:
David Wood 2020-06-22 13:57:03 +01:00
parent 47756bb0fa
commit 2989fea88a
No known key found for this signature in database
GPG key ID: 2592E76C87381FD9
44 changed files with 1627 additions and 84 deletions

View file

@ -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>();
}

View file

@ -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

View file

@ -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>();
}

View file

@ -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

View file

@ -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, || {});
}

View file

@ -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, || {});
}

View file

@ -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>());
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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());
}

View file

@ -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

View file

@ -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() { }

View file

@ -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();
}

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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>();
}

View file

@ -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