diff options
Diffstat (limited to 'tests/ui/polymorphization')
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 000000000..e10308588 --- /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 000000000..62164ff94 --- /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 000000000..7a364882f --- /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 000000000..27d59ec88 --- /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 000000000..2f41beeb9 --- /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 000000000..4e927f773 --- /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 000000000..cbc1b63fb --- /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 000000000..9d0922ac7 --- /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 000000000..2695dc6d4 --- /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 000000000..c22891171 --- /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 000000000..779bac0ac --- /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 000000000..84888f6fb --- /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 000000000..8b0c00b13 --- /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 000000000..4c532f451 --- /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 000000000..f26df4523 --- /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 000000000..4773dd4fa --- /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 000000000..d732b1071 --- /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 000000000..6a5fc2e33 --- /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 000000000..80bb2af25 --- /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 000000000..2cd026734 --- /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 000000000..fcbb86949 --- /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 000000000..d2d0f3368 --- /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 000000000..547569df7 --- /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 000000000..bbd991e36 --- /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 000000000..a56a8e70e --- /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 000000000..6277a902f --- /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 000000000..ec6244630 --- /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 000000000..07ab1355a --- /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 000000000..94a4a08bd --- /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 000000000..aad957e1d --- /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 000000000..d629ff7bb --- /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 000000000..b803fec2c --- /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 000000000..27f88d281 --- /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 + |