diff options
Diffstat (limited to 'tests/ui/traits/object')
35 files changed, 1015 insertions, 0 deletions
diff --git a/tests/ui/traits/object/auto-dedup-in-impl.rs b/tests/ui/traits/object/auto-dedup-in-impl.rs new file mode 100644 index 000000000..85698f194 --- /dev/null +++ b/tests/ui/traits/object/auto-dedup-in-impl.rs @@ -0,0 +1,19 @@ +// Checks to make sure that `dyn Trait + Send` and `dyn Trait + Send + Send` are the same type. +// Issue: #47010 + +struct Struct; +impl Trait for Struct {} +trait Trait {} + +type Send1 = dyn Trait + Send; +type Send2 = dyn Trait + Send + Send; + +fn main () {} + +impl dyn Trait + Send { + fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test` +} + +impl dyn Trait + Send + Send { + fn test(&self) { println!("two"); } +} diff --git a/tests/ui/traits/object/auto-dedup-in-impl.stderr b/tests/ui/traits/object/auto-dedup-in-impl.stderr new file mode 100644 index 000000000..5f13c7813 --- /dev/null +++ b/tests/ui/traits/object/auto-dedup-in-impl.stderr @@ -0,0 +1,12 @@ +error[E0592]: duplicate definitions with name `test` + --> $DIR/auto-dedup-in-impl.rs:14:5 + | +LL | fn test(&self) { println!("one"); } + | ^^^^^^^^^^^^^^ duplicate definitions for `test` +... +LL | fn test(&self) { println!("two"); } + | -------------- other definition for `test` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0592`. diff --git a/tests/ui/traits/object/auto-dedup.rs b/tests/ui/traits/object/auto-dedup.rs new file mode 100644 index 000000000..39d25eb7f --- /dev/null +++ b/tests/ui/traits/object/auto-dedup.rs @@ -0,0 +1,46 @@ +// run-pass + +#![allow(unused_assignments)] + +// Test that duplicate auto trait bounds in trait objects don't create new types. +#[allow(unused_assignments)] +use std::marker::Send as SendAlias; + +// A dummy trait for the non-auto trait. +trait Trait {} + +// A dummy struct to implement `Trait` and `Send`. +struct Struct; + +impl Trait for Struct {} + +// These three functions should be equivalent. +fn takes_dyn_trait_send(_: Box<dyn Trait + Send>) {} +fn takes_dyn_trait_send_send(_: Box<dyn Trait + Send + Send>) {} +fn takes_dyn_trait_send_sendalias(_: Box<dyn Trait + Send + SendAlias>) {} + +impl dyn Trait + Send + Send { + fn do_nothing(&self) {} +} + +fn main() { + // 1. Moving into a variable with more `Send`s and back. + let mut dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>; + let dyn_trait_send_send: Box<dyn Trait + Send + Send> = dyn_trait_send; + dyn_trait_send = dyn_trait_send_send; + + // 2. Calling methods with different number of `Send`s. + let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>; + takes_dyn_trait_send_send(dyn_trait_send); + + let dyn_trait_send_send = Box::new(Struct) as Box<dyn Trait + Send + Send>; + takes_dyn_trait_send(dyn_trait_send_send); + + // 3. Aliases to the trait are transparent. + let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>; + takes_dyn_trait_send_sendalias(dyn_trait_send); + + // 4. Calling an impl that duplicates an auto trait. + let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>; + dyn_trait_send.do_nothing(); +} diff --git a/tests/ui/traits/object/bounds-cycle-1.rs b/tests/ui/traits/object/bounds-cycle-1.rs new file mode 100644 index 000000000..314676492 --- /dev/null +++ b/tests/ui/traits/object/bounds-cycle-1.rs @@ -0,0 +1,24 @@ +// Check that we don't have a cycle when we try to normalize `Self::U` in the +// bound below. + +// check-pass + +trait Is { + type T; +} + +impl<U> Is for U { + type T = U; +} + +trait Obj { + type U: Is<T = Self::U>; +} + +fn is_obj<T: ?Sized + Obj>(_: &T) {} + +fn f(x: &dyn Obj<U = i32>) { + is_obj(x) +} + +fn main() {} diff --git a/tests/ui/traits/object/bounds-cycle-2.rs b/tests/ui/traits/object/bounds-cycle-2.rs new file mode 100644 index 000000000..4c1df3805 --- /dev/null +++ b/tests/ui/traits/object/bounds-cycle-2.rs @@ -0,0 +1,28 @@ +// Check that we don't have a cycle when we try to normalize `Self::V` in the +// bound below. + +// check-pass + +trait Is { + type T; +} + +impl<U> Is for U { + type T = U; +} + +trait Super { + type V; +} + +trait Obj: Super { + type U: Is<T = Self::V>; +} + +fn is_obj<T: ?Sized + Obj>(_: &T) {} + +fn f(x: &dyn Obj<U = i32, V = i32>) { + is_obj(x) +} + +fn main() {} diff --git a/tests/ui/traits/object/bounds-cycle-3.rs b/tests/ui/traits/object/bounds-cycle-3.rs new file mode 100644 index 000000000..55726a5ae --- /dev/null +++ b/tests/ui/traits/object/bounds-cycle-3.rs @@ -0,0 +1,25 @@ +// Check that we don't have a cycle when we try to normalize `Self::V` in the +// bound below. + +// check-pass + +trait Is { + type T; +} + +impl<U> Is for U { + type T = U; +} + +trait Obj { + type U: Is<T = Self::V>; + type V; +} + +fn is_obj<T: ?Sized + Obj>(_: &T) {} + +fn f(x: &dyn Obj<U = i32, V = i32>) { + is_obj(x) +} + +fn main() {} diff --git a/tests/ui/traits/object/bounds-cycle-4.rs b/tests/ui/traits/object/bounds-cycle-4.rs new file mode 100644 index 000000000..f83cb75c7 --- /dev/null +++ b/tests/ui/traits/object/bounds-cycle-4.rs @@ -0,0 +1,25 @@ +// Check that we don't have a cycle when we try to normalize `Self::U` in the +// bound below. Make sure that having a lifetime on the trait object doesn't break things + +// check-pass + +trait Is { + type T; +} + +impl<U> Is for U { + type T = U; +} + +trait Obj<'a> { + type U: Is<T = Self::V>; + type V; +} + +fn is_obj<'a, T: ?Sized + Obj<'a>>(_: &T) {} + +fn f<'a>(x: &dyn Obj<'a, U = i32, V = i32>) { + is_obj(x) +} + +fn main() {} diff --git a/tests/ui/traits/object/enforce-supertrait-projection.rs b/tests/ui/traits/object/enforce-supertrait-projection.rs new file mode 100644 index 000000000..2c9b41eea --- /dev/null +++ b/tests/ui/traits/object/enforce-supertrait-projection.rs @@ -0,0 +1,24 @@ +trait SuperTrait { + type A; + type B; +} + +trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {} + +fn transmute<A, B>(x: A) -> B { + foo::<A, B, dyn Trait<A = A, B = B>>(x) + //~^ ERROR type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B` +} + +fn foo<A, B, T: ?Sized>(x: T::A) -> B +where + T: Trait<B = B>, +{ + x +} + +static X: u8 = 0; +fn main() { + let x = transmute::<&u8, &[u8; 1_000_000]>(&X); + println!("{:?}", x[100_000]); +} diff --git a/tests/ui/traits/object/enforce-supertrait-projection.stderr b/tests/ui/traits/object/enforce-supertrait-projection.stderr new file mode 100644 index 000000000..cbf093866 --- /dev/null +++ b/tests/ui/traits/object/enforce-supertrait-projection.stderr @@ -0,0 +1,26 @@ +error[E0271]: type mismatch resolving `<dyn Trait<B = B, A = A> as SuperTrait>::A == B` + --> $DIR/enforce-supertrait-projection.rs:9:17 + | +LL | fn transmute<A, B>(x: A) -> B { + | - - expected type parameter + | | + | found type parameter +LL | foo::<A, B, dyn Trait<A = A, B = B>>(x) + | ^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `B`, found type parameter `A` + | + = note: expected type parameter `B` + found type parameter `A` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters +note: required by a bound in `foo` + --> $DIR/enforce-supertrait-projection.rs:15:8 + | +LL | fn foo<A, B, T: ?Sized>(x: T::A) -> B + | --- required by a bound in this +LL | where +LL | T: Trait<B = B>, + | ^^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/object/exclusion.rs b/tests/ui/traits/object/exclusion.rs new file mode 100644 index 000000000..766dceeaf --- /dev/null +++ b/tests/ui/traits/object/exclusion.rs @@ -0,0 +1,19 @@ +// run-pass +trait Future: 'static { + // The requirement for Self: Sized must prevent instantiation of + // Future::forget in vtables, otherwise there's an infinite type + // recursion through <Map<...> as Future>::forget. + fn forget(self) where Self: Sized { + Box::new(Map(self)) as Box<dyn Future>; + } +} + +struct Map<A>(#[allow(unused_tuple_struct_fields)] A); +impl<A: Future> Future for Map<A> {} + +pub struct Promise; +impl Future for Promise {} + +fn main() { + Promise.forget(); +} diff --git a/tests/ui/traits/object/generics.rs b/tests/ui/traits/object/generics.rs new file mode 100644 index 000000000..5a4a6aecc --- /dev/null +++ b/tests/ui/traits/object/generics.rs @@ -0,0 +1,41 @@ +// run-pass +// test for #8664 + +use std::marker; + +pub trait Trait2<A> { + fn doit(&self) -> A; +} + +pub struct Impl<A1, A2, A3> { + m1: marker::PhantomData<(A1,A2,A3)>, + /* + * With A2 we get the ICE: + * task <unnamed> failed at 'index out of bounds: the len is 1 but the index is 1', + * src/librustc/middle/subst.rs:58 + */ + t: Box<dyn Trait2<A2>+'static> +} + +impl<A1, A2, A3> Impl<A1, A2, A3> { + pub fn step(&self) { + self.t.doit(); + } +} + +// test for #8601 + +enum Type<T> { Constant(#[allow(unused_tuple_struct_fields)] T) } + +trait Trait<K,V> { + fn method(&self, _: Type<(K,V)>) -> isize; +} + +impl<V> Trait<u8,V> for () { + fn method(&self, _x: Type<(u8,V)>) -> isize { 0 } +} + +pub fn main() { + let a = Box::new(()) as Box<dyn Trait<u8, u8>>; + assert_eq!(a.method(Type::Constant((1, 2))), 0); +} diff --git a/tests/ui/traits/object/issue-33140-traitobject-crate.rs b/tests/ui/traits/object/issue-33140-traitobject-crate.rs new file mode 100644 index 000000000..8abd92da3 --- /dev/null +++ b/tests/ui/traits/object/issue-33140-traitobject-crate.rs @@ -0,0 +1,108 @@ +// check-pass + +#![warn(order_dependent_trait_objects)] +#![allow(dyn_drop)] + +// Check that traitobject 0.1.0 compiles + +//! # traitobject +//! +//! Unsafe helpers for working with raw TraitObjects. + +/// A trait implemented for all trait objects. +/// +/// Implementations for all traits in std are provided. +pub unsafe trait Trait {} + +unsafe impl Trait for dyn (::std::any::Any) + Send { } +unsafe impl Trait for dyn (::std::any::Any) + Sync { } +unsafe impl Trait for dyn (::std::any::Any) + Send + Sync { } +unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::Borrow<T>) + Send { } +unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::Borrow<T>) + Sync { } +unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::Borrow<T>) + Send + Sync { } +unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::BorrowMut<T>) + Send { } +unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::BorrowMut<T>) + Sync { } +unsafe impl<T: ?Sized> Trait for dyn (::std::borrow::BorrowMut<T>) + Send + Sync { } +unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsMut<T>) + Send { } +unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsMut<T>) + Sync { } +unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsMut<T>) + Send + Sync { } +unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsRef<T>) + Send { } +unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsRef<T>) + Sync { } +unsafe impl<T: ?Sized> Trait for dyn (::std::convert::AsRef<T>) + Send + Sync { } +unsafe impl Trait for dyn (::std::error::Error) + Send { } +unsafe impl Trait for dyn (::std::error::Error) + Sync { } +unsafe impl Trait for dyn (::std::error::Error) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Binary) + Send { } +unsafe impl Trait for dyn (::std::fmt::Binary) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Binary) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Debug) + Send { } +unsafe impl Trait for dyn (::std::fmt::Debug) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Debug) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Display) + Send { } +unsafe impl Trait for dyn (::std::fmt::Display) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Display) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::LowerExp) + Send { } +unsafe impl Trait for dyn (::std::fmt::LowerExp) + Sync { } +unsafe impl Trait for dyn (::std::fmt::LowerExp) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::LowerHex) + Send { } +unsafe impl Trait for dyn (::std::fmt::LowerHex) + Sync { } +unsafe impl Trait for dyn (::std::fmt::LowerHex) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Octal) + Send { } +unsafe impl Trait for dyn (::std::fmt::Octal) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Octal) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Pointer) + Send { } +unsafe impl Trait for dyn (::std::fmt::Pointer) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Pointer) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::UpperExp) + Send { } +unsafe impl Trait for dyn (::std::fmt::UpperExp) + Sync { } +unsafe impl Trait for dyn (::std::fmt::UpperExp) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::UpperHex) + Send { } +unsafe impl Trait for dyn (::std::fmt::UpperHex) + Sync { } +unsafe impl Trait for dyn (::std::fmt::UpperHex) + Send + Sync { } +unsafe impl Trait for dyn (::std::fmt::Write) + Send { } +unsafe impl Trait for dyn (::std::fmt::Write) + Sync { } +unsafe impl Trait for dyn (::std::fmt::Write) + Send + Sync { } +unsafe impl Trait for dyn (::std::hash::Hasher) + Send { } +unsafe impl Trait for dyn (::std::hash::Hasher) + Sync { } +unsafe impl Trait for dyn (::std::hash::Hasher) + Send + Sync { } +unsafe impl Trait for dyn (::std::io::BufRead) + Send { } +unsafe impl Trait for dyn (::std::io::BufRead) + Sync { } +unsafe impl Trait for dyn (::std::io::BufRead) + Send + Sync { } +unsafe impl Trait for dyn (::std::io::Read) + Send { } +unsafe impl Trait for dyn (::std::io::Read) + Sync { } +unsafe impl Trait for dyn (::std::io::Read) + Send + Sync { } +unsafe impl Trait for dyn (::std::io::Seek) + Send { } +unsafe impl Trait for dyn (::std::io::Seek) + Sync { } +unsafe impl Trait for dyn (::std::io::Seek) + Send + Sync { } +unsafe impl Trait for dyn (::std::io::Write) + Send { } +unsafe impl Trait for dyn (::std::io::Write) + Sync { } +unsafe impl Trait for dyn (::std::io::Write) + Send + Sync { } +unsafe impl<T, I> Trait for dyn (::std::iter::IntoIterator<IntoIter=I, Item=T>) { } +unsafe impl<T> Trait for dyn (::std::iter::Iterator<Item=T>) + Send { } +unsafe impl<T> Trait for dyn (::std::iter::Iterator<Item=T>) + Sync { } +unsafe impl<T> Trait for dyn (::std::iter::Iterator<Item=T>) + Send + Sync { } +unsafe impl Trait for dyn (::std::marker::Send) + Send { } +unsafe impl Trait for dyn (::std::marker::Send) + Sync { } +unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } +//~^ WARNING conflicting implementations of trait `Trait` for type +//~| WARNING this was previously accepted by the compiler but is being phased out +unsafe impl Trait for dyn (::std::marker::Sync) + Send { } +//~^ WARNING conflicting implementations of trait `Trait` for type +//~| WARNING this was previously accepted by the compiler but is being phased out +unsafe impl Trait for dyn (::std::marker::Sync) + Sync { } +unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { } +//~^ WARNING conflicting implementations of trait `Trait` for type +//~| WARNING this was previously accepted by the compiler but is being phased out +unsafe impl Trait for dyn (::std::ops::Drop) + Send { } +unsafe impl Trait for dyn (::std::ops::Drop) + Sync { } +unsafe impl Trait for dyn (::std::ops::Drop) + Send + Sync { } +unsafe impl Trait for dyn (::std::string::ToString) + Send { } +unsafe impl Trait for dyn (::std::string::ToString) + Sync { } +unsafe impl Trait for dyn (::std::string::ToString) + Send + Sync { } +fn assert_trait<T: Trait + ?Sized>() {} + +fn main() { + assert_trait::<dyn Send>(); + assert_trait::<dyn Sync>(); + assert_trait::<dyn Send + Sync>(); +} diff --git a/tests/ui/traits/object/issue-33140-traitobject-crate.stderr b/tests/ui/traits/object/issue-33140-traitobject-crate.stderr new file mode 100644 index 000000000..525401f9d --- /dev/null +++ b/tests/ui/traits/object/issue-33140-traitobject-crate.stderr @@ -0,0 +1,95 @@ +warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) + --> $DIR/issue-33140-traitobject-crate.rs:86:1 + | +LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { } + | ------------------------------------------------------ first implementation here +LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> +note: the lint level is defined here + --> $DIR/issue-33140-traitobject-crate.rs:3:9 + | +LL | #![warn(order_dependent_trait_objects)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) + --> $DIR/issue-33140-traitobject-crate.rs:89:1 + | +LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } + | ------------------------------------------------------------- first implementation here +... +LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> + +warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) + --> $DIR/issue-33140-traitobject-crate.rs:93:1 + | +LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } + | ------------------------------------------------------ first implementation here +... +LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> + +warning: 3 warnings emitted + +Future incompatibility report: Future breakage diagnostic: +warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) + --> $DIR/issue-33140-traitobject-crate.rs:86:1 + | +LL | unsafe impl Trait for dyn (::std::marker::Send) + Sync { } + | ------------------------------------------------------ first implementation here +LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> +note: the lint level is defined here + --> $DIR/issue-33140-traitobject-crate.rs:3:9 + | +LL | #![warn(order_dependent_trait_objects)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) + --> $DIR/issue-33140-traitobject-crate.rs:89:1 + | +LL | unsafe impl Trait for dyn (::std::marker::Send) + Send + Sync { } + | ------------------------------------------------------------- first implementation here +... +LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> +note: the lint level is defined here + --> $DIR/issue-33140-traitobject-crate.rs:3:9 + | +LL | #![warn(order_dependent_trait_objects)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +warning: conflicting implementations of trait `Trait` for type `(dyn Send + Sync + 'static)`: (E0119) + --> $DIR/issue-33140-traitobject-crate.rs:93:1 + | +LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send { } + | ------------------------------------------------------ first implementation here +... +LL | unsafe impl Trait for dyn (::std::marker::Sync) + Send + Sync { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Send + Sync + 'static)` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484> +note: the lint level is defined here + --> $DIR/issue-33140-traitobject-crate.rs:3:9 + | +LL | #![warn(order_dependent_trait_objects)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/traits/object/issue-44454-1.rs b/tests/ui/traits/object/issue-44454-1.rs new file mode 100644 index 000000000..bbaf3188a --- /dev/null +++ b/tests/ui/traits/object/issue-44454-1.rs @@ -0,0 +1,22 @@ +// Taken from https://github.com/rust-lang/rust/issues/44454#issue-256435333 + +trait Animal<X>: 'static {} + +fn foo<Y, X>() +where + Y: Animal<X> + ?Sized, +{ + // `Y` implements `Animal<X>` so `Y` is 'static. + baz::<Y>() +} + +fn bar<'a>(_arg: &'a i32) { + foo::<dyn Animal<&'a i32>, &'a i32>() //~ ERROR: lifetime may not live long enough +} + +fn baz<T: 'static + ?Sized>() {} + +fn main() { + let a = 5; + bar(&a); +} diff --git a/tests/ui/traits/object/issue-44454-1.stderr b/tests/ui/traits/object/issue-44454-1.stderr new file mode 100644 index 000000000..859487f50 --- /dev/null +++ b/tests/ui/traits/object/issue-44454-1.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/issue-44454-1.rs:14:5 + | +LL | fn bar<'a>(_arg: &'a i32) { + | -- lifetime `'a` defined here +LL | foo::<dyn Animal<&'a i32>, &'a i32>() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/tests/ui/traits/object/issue-44454-2.rs b/tests/ui/traits/object/issue-44454-2.rs new file mode 100644 index 000000000..f5178bcdb --- /dev/null +++ b/tests/ui/traits/object/issue-44454-2.rs @@ -0,0 +1,22 @@ +// Taken from https://github.com/rust-lang/rust/issues/44454#issuecomment-1175925928 + +trait Trait<ARG: 'static>: 'static { + type Assoc: AsRef<str>; +} + +fn hr<T: ?Sized, ARG>(x: T::Assoc) -> Box<dyn AsRef<str> + 'static> +where + T: Trait<ARG> +{ + Box::new(x) +} + +fn extend_lt<'a>(x: &'a str) -> Box<dyn AsRef<str> + 'static> { + type DynTrait = dyn for<'a> Trait<&'a str, Assoc = &'a str>; + hr::<DynTrait, _>(x) //~ ERROR: borrowed data escapes outside of function +} + +fn main() { + let extended = extend_lt(&String::from("hello")); + println!("{}", extended.as_ref().as_ref()); +} diff --git a/tests/ui/traits/object/issue-44454-2.stderr b/tests/ui/traits/object/issue-44454-2.stderr new file mode 100644 index 000000000..7f574769b --- /dev/null +++ b/tests/ui/traits/object/issue-44454-2.stderr @@ -0,0 +1,17 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/issue-44454-2.rs:16:5 + | +LL | fn extend_lt<'a>(x: &'a str) -> Box<dyn AsRef<str> + 'static> { + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here +LL | type DynTrait = dyn for<'a> Trait<&'a str, Assoc = &'a str>; +LL | hr::<DynTrait, _>(x) + | ^^^^^^^^^^^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/traits/object/issue-44454-3.rs b/tests/ui/traits/object/issue-44454-3.rs new file mode 100644 index 000000000..bff727035 --- /dev/null +++ b/tests/ui/traits/object/issue-44454-3.rs @@ -0,0 +1,33 @@ +// Taken from https://github.com/rust-lang/rust/issues/44454#issuecomment-1332781290 + +use std::any::Any; + +trait Animal<X>: 'static {} + +trait Projector { + type Foo; +} + +impl<X> Projector for dyn Animal<X> { + type Foo = X; +} + +fn make_static<'a, T>(t: &'a T) -> &'static T { + let x: <dyn Animal<&'a T> as Projector>::Foo = t; + let any = generic::<dyn Animal<&'a T>, &'a T>(x); + //~^ ERROR: lifetime may not live long enough + any.downcast_ref::<&'static T>().unwrap() +} + +fn generic<T: Projector + Animal<U> + ?Sized, U>(x: <T as Projector>::Foo) -> Box<dyn Any> { + make_static_any(x) +} + +fn make_static_any<U: 'static>(u: U) -> Box<dyn Any> { + Box::new(u) +} + +fn main() { + let a = make_static(&"salut".to_string()); + println!("{}", *a); +} diff --git a/tests/ui/traits/object/issue-44454-3.stderr b/tests/ui/traits/object/issue-44454-3.stderr new file mode 100644 index 000000000..294684d26 --- /dev/null +++ b/tests/ui/traits/object/issue-44454-3.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/issue-44454-3.rs:17:15 + | +LL | fn make_static<'a, T>(t: &'a T) -> &'static T { + | -- lifetime `'a` defined here +LL | let x: <dyn Animal<&'a T> as Projector>::Foo = t; +LL | let any = generic::<dyn Animal<&'a T>, &'a T>(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/tests/ui/traits/object/lifetime-first.rs b/tests/ui/traits/object/lifetime-first.rs new file mode 100644 index 000000000..33757cb7c --- /dev/null +++ b/tests/ui/traits/object/lifetime-first.rs @@ -0,0 +1,13 @@ +// run-pass +use std::fmt::Display; + +static BYTE: u8 = 33; + +fn main() { + let x: &(dyn 'static + Display) = &BYTE; + let y: Box<dyn 'static + Display> = Box::new(BYTE); + let xstr = format!("{}", x); + let ystr = format!("{}", y); + assert_eq!(xstr, "33"); + assert_eq!(ystr, "33"); +} diff --git a/tests/ui/traits/object/macro-matcher.rs b/tests/ui/traits/object/macro-matcher.rs new file mode 100644 index 000000000..910978749 --- /dev/null +++ b/tests/ui/traits/object/macro-matcher.rs @@ -0,0 +1,12 @@ +// `ty` matcher accepts trait object types + +macro_rules! m { + ($t: ty) => ( let _: $t; ) +} + +fn main() { + m!(dyn Copy + Send + 'static); + //~^ ERROR the trait `Copy` cannot be made into an object + m!(dyn 'static + Send); + m!(dyn 'static +); //~ ERROR at least one trait is required for an object type +} diff --git a/tests/ui/traits/object/macro-matcher.stderr b/tests/ui/traits/object/macro-matcher.stderr new file mode 100644 index 000000000..6d1e236c0 --- /dev/null +++ b/tests/ui/traits/object/macro-matcher.stderr @@ -0,0 +1,19 @@ +error[E0224]: at least one trait is required for an object type + --> $DIR/macro-matcher.rs:11:8 + | +LL | m!(dyn 'static +); + | ^^^^^^^^^^^^^ + +error[E0038]: the trait `Copy` cannot be made into an object + --> $DIR/macro-matcher.rs:8:8 + | +LL | m!(dyn Copy + Send + 'static); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` cannot be made into an object + | + = note: the trait cannot be made into an object because it requires `Self: Sized` + = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0038, E0224. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/object/safety.rs b/tests/ui/traits/object/safety.rs new file mode 100644 index 000000000..f43d332d6 --- /dev/null +++ b/tests/ui/traits/object/safety.rs @@ -0,0 +1,17 @@ +// Check that static methods are not object-safe. + +trait Tr { + fn foo(); + fn bar(&self) { } +} + +struct St; + +impl Tr for St { + fn foo() {} +} + +fn main() { + let _: &dyn Tr = &St; //~ ERROR E0038 + //~^ ERROR E0038 +} diff --git a/tests/ui/traits/object/safety.stderr b/tests/ui/traits/object/safety.stderr new file mode 100644 index 000000000..dc18adeaf --- /dev/null +++ b/tests/ui/traits/object/safety.stderr @@ -0,0 +1,49 @@ +error[E0038]: the trait `Tr` cannot be made into an object + --> $DIR/safety.rs:15:22 + | +LL | let _: &dyn Tr = &St; + | ^^^ `Tr` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/safety.rs:4:8 + | +LL | trait Tr { + | -- this trait cannot be made into an object... +LL | fn foo(); + | ^^^ ...because associated function `foo` has no `self` parameter + = note: required for `&St` to implement `CoerceUnsized<&dyn Tr>` + = note: required by cast to type `&dyn Tr` +help: consider turning `foo` into a method by giving it a `&self` argument + | +LL | fn foo(&self); + | +++++ +help: alternatively, consider constraining `foo` so it does not apply to trait objects + | +LL | fn foo() where Self: Sized; + | +++++++++++++++++ + +error[E0038]: the trait `Tr` cannot be made into an object + --> $DIR/safety.rs:15:12 + | +LL | let _: &dyn Tr = &St; + | ^^^^^^^ `Tr` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/safety.rs:4:8 + | +LL | trait Tr { + | -- this trait cannot be made into an object... +LL | fn foo(); + | ^^^ ...because associated function `foo` has no `self` parameter +help: consider turning `foo` into a method by giving it a `&self` argument + | +LL | fn foo(&self); + | +++++ +help: alternatively, consider constraining `foo` so it does not apply to trait objects + | +LL | fn foo() where Self: Sized; + | +++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/object/supertrait-lifetime-bound.rs b/tests/ui/traits/object/supertrait-lifetime-bound.rs new file mode 100644 index 000000000..f929a9bb6 --- /dev/null +++ b/tests/ui/traits/object/supertrait-lifetime-bound.rs @@ -0,0 +1,14 @@ +trait Foo: 'static { } + +trait Bar<T>: Foo { } + +fn test1<T: ?Sized + Bar<S>, S>() { } + +fn test2<'a>() { + // Here: the type `dyn Bar<&'a u32>` references `'a`, + // and so it does not outlive `'static`. + test1::<dyn Bar<&'a u32>, _>(); + //~^ ERROR lifetime may not live long enough +} + +fn main() { } diff --git a/tests/ui/traits/object/supertrait-lifetime-bound.stderr b/tests/ui/traits/object/supertrait-lifetime-bound.stderr new file mode 100644 index 000000000..ed2f86243 --- /dev/null +++ b/tests/ui/traits/object/supertrait-lifetime-bound.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/supertrait-lifetime-bound.rs:10:5 + | +LL | fn test2<'a>() { + | -- lifetime `'a` defined here +... +LL | test1::<dyn Bar<&'a u32>, _>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/tests/ui/traits/object/vs-lifetime-2.rs b/tests/ui/traits/object/vs-lifetime-2.rs new file mode 100644 index 000000000..0b33dc7f6 --- /dev/null +++ b/tests/ui/traits/object/vs-lifetime-2.rs @@ -0,0 +1,11 @@ +// A few contrived examples where lifetime should (or should not) be parsed as an object type. +// Lifetimes parsed as types are still rejected later by semantic checks. + +// `'static` is a lifetime, `'static +` is a type, `'a` is a type +fn g() where + 'static: 'static, + dyn 'static +: 'static + Copy, + //~^ ERROR at least one trait is required for an object type +{} + +fn main() {} diff --git a/tests/ui/traits/object/vs-lifetime-2.stderr b/tests/ui/traits/object/vs-lifetime-2.stderr new file mode 100644 index 000000000..9b8e793df --- /dev/null +++ b/tests/ui/traits/object/vs-lifetime-2.stderr @@ -0,0 +1,9 @@ +error[E0224]: at least one trait is required for an object type + --> $DIR/vs-lifetime-2.rs:7:5 + | +LL | dyn 'static +: 'static + Copy, + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0224`. diff --git a/tests/ui/traits/object/vs-lifetime.rs b/tests/ui/traits/object/vs-lifetime.rs new file mode 100644 index 000000000..14ae67cff --- /dev/null +++ b/tests/ui/traits/object/vs-lifetime.rs @@ -0,0 +1,17 @@ +// A few contrived examples where lifetime should (or should not) be parsed as an object type. +// Lifetimes parsed as types are still rejected later by semantic checks. + +struct S<'a, T>(&'a u8, T); + +fn main() { + // `'static` is a lifetime argument, `'static +` is a type argument + let _: S<'static, u8>; + let _: S<'static, dyn 'static +>; + //~^ at least one trait is required for an object type + let _: S<'static, 'static>; + //~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments were supplied + //~| ERROR this struct takes 1 generic argument but 0 generic arguments were supplied + let _: S<dyn 'static +, 'static>; + //~^ ERROR type provided when a lifetime was expected + //~| ERROR at least one trait is required for an object type +} diff --git a/tests/ui/traits/object/vs-lifetime.stderr b/tests/ui/traits/object/vs-lifetime.stderr new file mode 100644 index 000000000..224465228 --- /dev/null +++ b/tests/ui/traits/object/vs-lifetime.stderr @@ -0,0 +1,52 @@ +error[E0224]: at least one trait is required for an object type + --> $DIR/vs-lifetime.rs:9:23 + | +LL | let _: S<'static, dyn 'static +>; + | ^^^^^^^^^^^^^ + +error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied + --> $DIR/vs-lifetime.rs:11:12 + | +LL | let _: S<'static, 'static>; + | ^ ------- help: remove this lifetime argument + | | + | expected 1 lifetime argument + | +note: struct defined here, with 1 lifetime parameter: `'a` + --> $DIR/vs-lifetime.rs:4:8 + | +LL | struct S<'a, T>(&'a u8, T); + | ^ -- + +error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied + --> $DIR/vs-lifetime.rs:11:12 + | +LL | let _: S<'static, 'static>; + | ^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `T` + --> $DIR/vs-lifetime.rs:4:8 + | +LL | struct S<'a, T>(&'a u8, T); + | ^ - +help: add missing generic argument + | +LL | let _: S<'static, 'static, T>; + | +++ + +error[E0224]: at least one trait is required for an object type + --> $DIR/vs-lifetime.rs:14:14 + | +LL | let _: S<dyn 'static +, 'static>; + | ^^^^^^^^^^^^^ + +error[E0747]: type provided when a lifetime was expected + --> $DIR/vs-lifetime.rs:14:14 + | +LL | let _: S<dyn 'static +, 'static>; + | ^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0107, E0224, E0747. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/object/with-lifetime-bound.rs b/tests/ui/traits/object/with-lifetime-bound.rs new file mode 100644 index 000000000..05aab5e3b --- /dev/null +++ b/tests/ui/traits/object/with-lifetime-bound.rs @@ -0,0 +1,34 @@ +// run-pass +// Uncovered during work on new scoping rules for safe destructors +// as an important use case to support properly. + + +pub struct E<'a> { + pub f: &'a u8, +} +impl<'b> E<'b> { + pub fn m(&self) -> &'b u8 { self.f } +} + +pub struct P<'c> { + pub g: &'c u8, +} +pub trait M { + fn n(&self) -> u8; +} +impl<'d> M for P<'d> { + fn n(&self) -> u8 { *self.g } +} + +fn extension<'e>(x: &'e E<'e>) -> Box<dyn M+'e> { + loop { + let p = P { g: x.m() }; + return Box::new(p) as Box<dyn M+'e>; + } +} + +fn main() { + let w = E { f: &10 }; + let o = extension(&w); + assert_eq!(o.n(), 10); +} diff --git a/tests/ui/traits/object/with-self-in-projection-output-bad.rs b/tests/ui/traits/object/with-self-in-projection-output-bad.rs new file mode 100644 index 000000000..f34fa80a0 --- /dev/null +++ b/tests/ui/traits/object/with-self-in-projection-output-bad.rs @@ -0,0 +1,50 @@ +// Regression test for #56288. Checks that if a supertrait defines an associated type +// projection that references `Self`, then that associated type must still be explicitly +// specified in the `dyn Trait` variant, since we don't know what `Self` is anymore. + +trait Base { + type Output; +} + +trait Helper: Base<Output=<Self as Helper>::Target> { + type Target; +} + +impl Base for u32 +{ + type Output = i32; +} + +impl Helper for u32 +{ + type Target = i32; +} + +trait ConstI32 { + type Out; +} + +impl<T: ?Sized> ConstI32 for T { + type Out = i32; +} + +// Test that you still need to manually give a projection type if the Output type +// is normalizable. +trait NormalizableHelper: + Base<Output=<Self as ConstI32>::Out> +{ + type Target; +} + +impl NormalizableHelper for u32 +{ + type Target = i32; +} + +fn main() { + let _x: Box<dyn Helper<Target=i32>> = Box::new(2u32); + //~^ ERROR the value of the associated type `Output` (from trait `Base`) must be specified + + let _y: Box<dyn NormalizableHelper<Target=i32>> = Box::new(2u32); + //~^ ERROR the value of the associated type `Output` (from trait `Base`) must be specified +} diff --git a/tests/ui/traits/object/with-self-in-projection-output-bad.stderr b/tests/ui/traits/object/with-self-in-projection-output-bad.stderr new file mode 100644 index 000000000..641bfe236 --- /dev/null +++ b/tests/ui/traits/object/with-self-in-projection-output-bad.stderr @@ -0,0 +1,21 @@ +error[E0191]: the value of the associated type `Output` (from trait `Base`) must be specified + --> $DIR/with-self-in-projection-output-bad.rs:45:21 + | +LL | type Output; + | ----------- `Output` defined here +... +LL | let _x: Box<dyn Helper<Target=i32>> = Box::new(2u32); + | ^^^^^^^^^^^^^^^^^^ help: specify the associated type: `Helper<Target=i32, Output = Type>` + +error[E0191]: the value of the associated type `Output` (from trait `Base`) must be specified + --> $DIR/with-self-in-projection-output-bad.rs:48:21 + | +LL | type Output; + | ----------- `Output` defined here +... +LL | let _y: Box<dyn NormalizableHelper<Target=i32>> = Box::new(2u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `NormalizableHelper<Target=i32, Output = Type>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0191`. diff --git a/tests/ui/traits/object/with-self-in-projection-output-good.rs b/tests/ui/traits/object/with-self-in-projection-output-good.rs new file mode 100644 index 000000000..d1b7bf6c2 --- /dev/null +++ b/tests/ui/traits/object/with-self-in-projection-output-good.rs @@ -0,0 +1,28 @@ +// build-pass (FIXME(62277): could be check-pass?) + +// Regression test related to #56288. Check that a supertrait projection (of +// `Output`) that references `Self` can be ok if it is referencing a projection (of +// `Self::Target`, in this case). Note that we still require the user to manually +// specify both `Target` and `Output` for now. + +trait Base { + type Output; +} + +trait Helper: Base<Output=<Self as Helper>::Target> { + type Target; +} + +impl Base for u32 +{ + type Output = i32; +} + +impl Helper for u32 +{ + type Target = i32; +} + +fn main() { + let _x: Box<dyn Helper<Target=i32, Output=i32>> = Box::new(2u32); +} diff --git a/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs new file mode 100644 index 000000000..39e817168 --- /dev/null +++ b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs @@ -0,0 +1,51 @@ +// build-pass (FIXME(62277): could be check-pass?) + +// FIXME(eddyb) shorten the name so windows doesn't choke on it. +#![crate_name = "trait_test"] + +// Regression test related to #56288. Check that a supertrait projection (of +// `Output`) that references `Self` is ok if there is another occurrence of +// the same supertrait that specifies the projection explicitly, even if +// the projection's associated type is not explicitly specified in the object type. +// +// Note that in order for this to compile, we need the `Self`-referencing projection +// to normalize fairly directly to a concrete type, otherwise the trait resolver +// will hate us. +// +// There is a test in `trait-object-with-self-in-projection-output-bad.rs` that +// having a normalizing, but `Self`-containing projection does not *by itself* +// allow you to avoid writing the projected type (`Output`, in this example) +// explicitly. + +trait ConstI32 { + type Out; +} + +impl<T: ?Sized> ConstI32 for T { + type Out = i32; +} + +trait Base { + type Output; +} + +trait NormalizingHelper: Base<Output=<Self as ConstI32>::Out> + Base<Output=i32> { + type Target; +} + +impl Base for u32 +{ + type Output = i32; +} + +impl NormalizingHelper for u32 +{ + type Target = i32; +} + +fn main() { + // Make sure this works both with and without the associated type + // being specified. + let _x: Box<dyn NormalizingHelper<Target=i32>> = Box::new(2u32); + let _y: Box<dyn NormalizingHelper<Target=i32, Output=i32>> = Box::new(2u32); +} |