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:
parent
47756bb0fa
commit
2989fea88a
44 changed files with 1627 additions and 84 deletions
61
src/test/ui/polymorphization/const_parameters/closures.rs
Normal file
61
src/test/ui/polymorphization/const_parameters/closures.rs
Normal 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>();
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
33
src/test/ui/polymorphization/const_parameters/functions.rs
Normal file
33
src/test/ui/polymorphization/const_parameters/functions.rs
Normal 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>();
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
21
src/test/ui/polymorphization/drop_shims/simple.rs
Normal file
21
src/test/ui/polymorphization/drop_shims/simple.rs
Normal 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, || {});
|
||||
}
|
||||
26
src/test/ui/polymorphization/drop_shims/transitive.rs
Normal file
26
src/test/ui/polymorphization/drop_shims/transitive.rs
Normal 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, || {});
|
||||
}
|
||||
88
src/test/ui/polymorphization/generators.rs
Normal file
88
src/test/ui/polymorphization/generators.rs
Normal 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>());
|
||||
}
|
||||
49
src/test/ui/polymorphization/generators.stderr
Normal file
49
src/test/ui/polymorphization/generators.stderr
Normal 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
|
||||
|
||||
22
src/test/ui/polymorphization/lifetimes.rs
Normal file
22
src/test/ui/polymorphization/lifetimes.rs
Normal 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);
|
||||
}
|
||||
17
src/test/ui/polymorphization/lifetimes.stderr
Normal file
17
src/test/ui/polymorphization/lifetimes.stderr
Normal 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
|
||||
|
||||
21
src/test/ui/polymorphization/predicates.rs
Normal file
21
src/test/ui/polymorphization/predicates.rs
Normal 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());
|
||||
}
|
||||
8
src/test/ui/polymorphization/predicates.stderr
Normal file
8
src/test/ui/polymorphization/predicates.stderr
Normal 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
|
||||
|
||||
76
src/test/ui/polymorphization/too-many-generic-params.rs
Normal file
76
src/test/ui/polymorphization/too-many-generic-params.rs
Normal 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() { }
|
||||
143
src/test/ui/polymorphization/type_parameters/closures.rs
Normal file
143
src/test/ui/polymorphization/type_parameters/closures.rs
Normal 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();
|
||||
}
|
||||
90
src/test/ui/polymorphization/type_parameters/closures.stderr
Normal file
90
src/test/ui/polymorphization/type_parameters/closures.stderr
Normal 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
|
||||
|
||||
84
src/test/ui/polymorphization/type_parameters/functions.rs
Normal file
84
src/test/ui/polymorphization/type_parameters/functions.rs
Normal 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();
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
27
src/test/ui/polymorphization/unsized_cast.rs
Normal file
27
src/test/ui/polymorphization/unsized_cast.rs
Normal 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>();
|
||||
}
|
||||
29
src/test/ui/polymorphization/unsized_cast.stderr
Normal file
29
src/test/ui/polymorphization/unsized_cast.stderr
Normal 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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue