diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
commit | 218caa410aa38c29984be31a5229b9fa717560ee (patch) | |
tree | c54bd55eeb6e4c508940a30e94c0032fbd45d677 /tests/ui/traits/negative-impls | |
parent | Releasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip |
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/traits/negative-impls')
27 files changed, 652 insertions, 0 deletions
diff --git a/tests/ui/traits/negative-impls/auxiliary/foreign_trait.rs b/tests/ui/traits/negative-impls/auxiliary/foreign_trait.rs new file mode 100644 index 000000000..0e17f0890 --- /dev/null +++ b/tests/ui/traits/negative-impls/auxiliary/foreign_trait.rs @@ -0,0 +1,7 @@ +#![feature(negative_impls)] +#![feature(with_negative_coherence)] + +pub trait ForeignTrait {} + +impl ForeignTrait for u32 {} +impl !ForeignTrait for String {} diff --git a/tests/ui/traits/negative-impls/eager-mono.rs b/tests/ui/traits/negative-impls/eager-mono.rs new file mode 100644 index 000000000..ce770376c --- /dev/null +++ b/tests/ui/traits/negative-impls/eager-mono.rs @@ -0,0 +1,12 @@ +// build-pass +// compile-flags:-C link-dead-code=y + +#![feature(negative_impls)] + +trait Foo { + fn foo() {} +} + +impl !Foo for () {} + +fn main() {} diff --git a/tests/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs b/tests/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs new file mode 100644 index 000000000..17ddaa312 --- /dev/null +++ b/tests/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs @@ -0,0 +1,53 @@ +// This tests issue #79683: note in the error message that the trait is +// explicitly unimplemented instead of suggesting to implement it. + +#![feature(negative_impls)] + +struct Qux; +//~^ NOTE method `clone` not found for this +//~^^ NOTE method `foo` not found for this + +impl !Clone for Qux {} + +trait Bar { + fn bar(&self); +} + +impl !Bar for u32 {} + +trait Foo { + fn foo(&self); +} +//~^^^ NOTE `Foo` defines an item `foo`, perhaps you need to implement it + +trait FooBar { + fn foo(&self); +} + +impl !Foo for Qux {} + +impl !FooBar for Qux {} + +impl !FooBar for u32 {} + +fn main() { + Qux.clone(); + //~^ ERROR no method named `clone` found for struct `Qux` + //~| NOTE method not found in `Qux` + //~| NOTE `Clone` defines an item `clone`, but is explicitly unimplemented + + 0_u32.bar(); + //~^ ERROR no method named `bar` found for type `u32` + //~| NOTE method not found in `u32` + //~| NOTE `Bar` defines an item `bar`, but is explicitly unimplemented + + Qux.foo(); + //~^ ERROR no method named `foo` found for struct `Qux` + //~| NOTE method not found in `Qux` + //~| NOTE the following traits define an item `foo`, but are explicitly unimplemented + + 0_u32.foo(); + //~^ ERROR no method named `foo` found for type `u32` + //~| NOTE method not found in `u32` + //~| NOTE `FooBar` defines an item `foo`, but is explicitly unimplemented +} diff --git a/tests/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr b/tests/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr new file mode 100644 index 000000000..b29442d7b --- /dev/null +++ b/tests/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr @@ -0,0 +1,52 @@ +error[E0599]: no method named `clone` found for struct `Qux` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:34:9 + | +LL | struct Qux; + | ---------- method `clone` not found for this struct +... +LL | Qux.clone(); + | ^^^^^ method not found in `Qux` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the trait `Clone` defines an item `clone`, but is explicitly unimplemented + +error[E0599]: no method named `bar` found for type `u32` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:39:11 + | +LL | 0_u32.bar(); + | ^^^ method not found in `u32` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the trait `Bar` defines an item `bar`, but is explicitly unimplemented + +error[E0599]: no method named `foo` found for struct `Qux` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:44:9 + | +LL | struct Qux; + | ---------- method `foo` not found for this struct +... +LL | Qux.foo(); + | ^^^ method not found in `Qux` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following traits define an item `foo`, but are explicitly unimplemented: + Foo + FooBar + +error[E0599]: no method named `foo` found for type `u32` in the current scope + --> $DIR/explicitly-unimplemented-error-message.rs:49:11 + | +LL | 0_u32.foo(); + | ^^^ method not found in `u32` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Foo` defines an item `foo`, perhaps you need to implement it + --> $DIR/explicitly-unimplemented-error-message.rs:18:1 + | +LL | trait Foo { + | ^^^^^^^^^ + = note: the trait `FooBar` defines an item `foo`, but is explicitly unimplemented + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/traits/negative-impls/feature-gate-negative_impls.rs b/tests/ui/traits/negative-impls/feature-gate-negative_impls.rs new file mode 100644 index 000000000..683fd6db6 --- /dev/null +++ b/tests/ui/traits/negative-impls/feature-gate-negative_impls.rs @@ -0,0 +1,3 @@ +trait MyTrait {} +impl !MyTrait for u32 {} //~ ERROR negative trait bounds are not yet fully implemented +fn main() {} diff --git a/tests/ui/traits/negative-impls/feature-gate-negative_impls.stderr b/tests/ui/traits/negative-impls/feature-gate-negative_impls.stderr new file mode 100644 index 000000000..b253fbd0d --- /dev/null +++ b/tests/ui/traits/negative-impls/feature-gate-negative_impls.stderr @@ -0,0 +1,12 @@ +error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now + --> $DIR/feature-gate-negative_impls.rs:2:6 + | +LL | impl !MyTrait for u32 {} + | ^^^^^^^^ + | + = note: see issue #68318 <https://github.com/rust-lang/rust/issues/68318> for more information + = help: add `#![feature(negative_impls)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/negative-impls/negated-auto-traits-error.rs b/tests/ui/traits/negative-impls/negated-auto-traits-error.rs new file mode 100644 index 000000000..4bdad5dc5 --- /dev/null +++ b/tests/ui/traits/negative-impls/negated-auto-traits-error.rs @@ -0,0 +1,68 @@ +// The dummy functions are used to avoid adding new cfail files. +// What happens is that the compiler attempts to squash duplicates and some +// errors are not reported. This way, we make sure that, for each function, different +// typeck phases are involved and all errors are reported. + +#![feature(negative_impls)] + +use std::marker::Send; + +struct Outer<T: Send>(T); + +struct Outer2<T>(T); + +unsafe impl<T: Send> Sync for Outer2<T> {} + +fn is_send<T: Send>(_: T) {} +fn is_sync<T: Sync>(_: T) {} + +fn dummy() { + struct TestType; + impl !Send for TestType {} + + Outer(TestType); + //~^ ERROR `dummy::TestType` cannot be sent between threads safely + //~| ERROR `dummy::TestType` cannot be sent between threads safely +} + +fn dummy1b() { + struct TestType; + impl !Send for TestType {} + + is_send(TestType); + //~^ ERROR `dummy1b::TestType` cannot be sent between threads safely +} + +fn dummy1c() { + struct TestType; + impl !Send for TestType {} + + is_send((8, TestType)); + //~^ ERROR `dummy1c::TestType` cannot be sent between threads safely +} + +fn dummy2() { + struct TestType; + impl !Send for TestType {} + + is_send(Box::new(TestType)); + //~^ ERROR `dummy2::TestType` cannot be sent between threads safely +} + +fn dummy3() { + struct TestType; + impl !Send for TestType {} + + is_send(Box::new(Outer2(TestType))); + //~^ ERROR `dummy3::TestType` cannot be sent between threads safely +} + +fn main() { + struct TestType; + impl !Send for TestType {} + + // This will complain about a missing Send impl because `Sync` is implement *just* + // for T that are `Send`. Look at #20366 and #19950 + is_sync(Outer2(TestType)); + //~^ ERROR `main::TestType` cannot be sent between threads safely +} diff --git a/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr new file mode 100644 index 000000000..ce690b749 --- /dev/null +++ b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -0,0 +1,127 @@ +error[E0277]: `dummy::TestType` cannot be sent between threads safely + --> $DIR/negated-auto-traits-error.rs:23:11 + | +LL | Outer(TestType); + | ----- ^^^^^^^^ `dummy::TestType` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Send` is not implemented for `dummy::TestType` +note: required by a bound in `Outer` + --> $DIR/negated-auto-traits-error.rs:10:17 + | +LL | struct Outer<T: Send>(T); + | ^^^^ required by this bound in `Outer` + +error[E0277]: `dummy::TestType` cannot be sent between threads safely + --> $DIR/negated-auto-traits-error.rs:23:5 + | +LL | Outer(TestType); + | ^^^^^^^^^^^^^^^ `dummy::TestType` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `dummy::TestType` +note: required by a bound in `Outer` + --> $DIR/negated-auto-traits-error.rs:10:17 + | +LL | struct Outer<T: Send>(T); + | ^^^^ required by this bound in `Outer` + +error[E0277]: `dummy1b::TestType` cannot be sent between threads safely + --> $DIR/negated-auto-traits-error.rs:32:13 + | +LL | is_send(TestType); + | ------- ^^^^^^^^ `dummy1b::TestType` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Send` is not implemented for `dummy1b::TestType` +note: required by a bound in `is_send` + --> $DIR/negated-auto-traits-error.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error[E0277]: `dummy1c::TestType` cannot be sent between threads safely + --> $DIR/negated-auto-traits-error.rs:40:13 + | +LL | is_send((8, TestType)); + | ------- ^^^^^^^^^^^^^ `dummy1c::TestType` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType` + = note: required because it appears within the type `({integer}, TestType)` +note: required by a bound in `is_send` + --> $DIR/negated-auto-traits-error.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error[E0277]: `dummy2::TestType` cannot be sent between threads safely + --> $DIR/negated-auto-traits-error.rs:48:13 + | +LL | is_send(Box::new(TestType)); + | ------- ^^^^^^^^^^^^^^^^^^ the trait `Send` is not implemented for `Unique<dummy2::TestType>` + | | + | required by a bound introduced by this call + | + = note: the trait bound `Unique<dummy2::TestType>: Send` is not satisfied + = note: required for `Unique<dummy2::TestType>` to implement `Send` + = note: required because it appears within the type `Box<TestType>` +note: required by a bound in `is_send` + --> $DIR/negated-auto-traits-error.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` +help: consider borrowing here + | +LL | is_send(&Box::new(TestType)); + | + + +error[E0277]: `dummy3::TestType` cannot be sent between threads safely + --> $DIR/negated-auto-traits-error.rs:56:13 + | +LL | is_send(Box::new(Outer2(TestType))); + | ------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ `dummy3::TestType` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType` +note: required because it appears within the type `Outer2<TestType>` + --> $DIR/negated-auto-traits-error.rs:12:8 + | +LL | struct Outer2<T>(T); + | ^^^^^^ + = note: required for `Unique<Outer2<dummy3::TestType>>` to implement `Send` + = note: required because it appears within the type `Box<Outer2<TestType>>` +note: required by a bound in `is_send` + --> $DIR/negated-auto-traits-error.rs:16:15 + | +LL | fn is_send<T: Send>(_: T) {} + | ^^^^ required by this bound in `is_send` + +error[E0277]: `main::TestType` cannot be sent between threads safely + --> $DIR/negated-auto-traits-error.rs:66:13 + | +LL | is_sync(Outer2(TestType)); + | ------- ^^^^^^^^^^^^^^^^ `main::TestType` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Send` is not implemented for `main::TestType` +note: required for `Outer2<main::TestType>` to implement `Sync` + --> $DIR/negated-auto-traits-error.rs:14:22 + | +LL | unsafe impl<T: Send> Sync for Outer2<T> {} + | ---- ^^^^ ^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `is_sync` + --> $DIR/negated-auto-traits-error.rs:17:15 + | +LL | fn is_sync<T: Sync>(_: T) {} + | ^^^^ required by this bound in `is_sync` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/negative-impls/negated-auto-traits-rpass.rs b/tests/ui/traits/negative-impls/negated-auto-traits-rpass.rs new file mode 100644 index 000000000..a1042f831 --- /dev/null +++ b/tests/ui/traits/negative-impls/negated-auto-traits-rpass.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(unused_variables)] +#![feature(negative_impls)] + +use std::marker::Send; + +pub struct WaitToken; +impl !Send for WaitToken {} + +pub struct Test<T>(#[allow(unused_tuple_struct_fields)] T); +unsafe impl<T: 'static> Send for Test<T> {} + +pub fn spawn<F>(_: F) -> () where F: FnOnce(), F: Send + 'static {} + +fn main() { + let wt = Test(WaitToken); + spawn(move || { + let x = wt; + println!("Hello, World!"); + }); +} diff --git a/tests/ui/traits/negative-impls/negative-default-impls.rs b/tests/ui/traits/negative-impls/negative-default-impls.rs new file mode 100644 index 000000000..c68bca432 --- /dev/null +++ b/tests/ui/traits/negative-impls/negative-default-impls.rs @@ -0,0 +1,11 @@ +#![feature(negative_impls)] +#![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete + +trait MyTrait { + type Foo; +} + +default impl !MyTrait for u32 {} //~ ERROR negative impls cannot be default impls + +fn main() {} diff --git a/tests/ui/traits/negative-impls/negative-default-impls.stderr b/tests/ui/traits/negative-impls/negative-default-impls.stderr new file mode 100644 index 000000000..7b54cf542 --- /dev/null +++ b/tests/ui/traits/negative-impls/negative-default-impls.stderr @@ -0,0 +1,19 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/negative-default-impls.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0750]: negative impls cannot be default impls + --> $DIR/negative-default-impls.rs:9:1 + | +LL | default impl !MyTrait for u32 {} + | ^^^^^^^ ^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0750`. diff --git a/tests/ui/traits/negative-impls/negative-impls-basic.rs b/tests/ui/traits/negative-impls/negative-impls-basic.rs new file mode 100644 index 000000000..474e03817 --- /dev/null +++ b/tests/ui/traits/negative-impls/negative-impls-basic.rs @@ -0,0 +1,17 @@ +// A simple test that we are able to create negative impls, when the +// feature gate is given. +// +// run-pass + +#![feature(negative_impls)] +#![allow(dead_code)] + +struct TestType; + +trait TestTrait { + fn dummy(&self) {} +} + +impl !TestTrait for TestType {} + +fn main() {} diff --git a/tests/ui/traits/negative-impls/negative-specializes-negative.rs b/tests/ui/traits/negative-impls/negative-specializes-negative.rs new file mode 100644 index 000000000..35297ab12 --- /dev/null +++ b/tests/ui/traits/negative-impls/negative-specializes-negative.rs @@ -0,0 +1,13 @@ +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(negative_impls)] + +// Test a negative impl that "specializes" another negative impl. +// +// run-pass + +trait MyTrait {} + +impl<T> !MyTrait for T {} +impl !MyTrait for u32 {} + +fn main() {} diff --git a/tests/ui/traits/negative-impls/negative-specializes-negative.stderr b/tests/ui/traits/negative-impls/negative-specializes-negative.stderr new file mode 100644 index 000000000..751e29c3b --- /dev/null +++ b/tests/ui/traits/negative-impls/negative-specializes-negative.stderr @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/negative-specializes-negative.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/negative-impls/negative-specializes-positive-item.rs b/tests/ui/traits/negative-impls/negative-specializes-positive-item.rs new file mode 100644 index 000000000..4281eedaf --- /dev/null +++ b/tests/ui/traits/negative-impls/negative-specializes-positive-item.rs @@ -0,0 +1,13 @@ +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(negative_impls)] + +// Negative impl for u32 cannot "specialize" the base impl. +trait MyTrait { + fn foo(); +} +impl<T> MyTrait for T { + default fn foo() {} +} +impl !MyTrait for u32 {} //~ ERROR E0751 + +fn main() {} diff --git a/tests/ui/traits/negative-impls/negative-specializes-positive-item.stderr b/tests/ui/traits/negative-impls/negative-specializes-positive-item.stderr new file mode 100644 index 000000000..1cfa49b20 --- /dev/null +++ b/tests/ui/traits/negative-impls/negative-specializes-positive-item.stderr @@ -0,0 +1,22 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/negative-specializes-positive-item.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: + --> $DIR/negative-specializes-positive-item.rs:11:1 + | +LL | impl<T> MyTrait for T { + | --------------------- positive implementation here +... +LL | impl !MyTrait for u32 {} + | ^^^^^^^^^^^^^^^^^^^^^ negative implementation here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0751`. diff --git a/tests/ui/traits/negative-impls/negative-specializes-positive.rs b/tests/ui/traits/negative-impls/negative-specializes-positive.rs new file mode 100644 index 000000000..0e227691e --- /dev/null +++ b/tests/ui/traits/negative-impls/negative-specializes-positive.rs @@ -0,0 +1,14 @@ +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(negative_impls)] + +// Negative impl for u32 cannot "specialize" the base impl. +trait MyTrait {} +impl<T> MyTrait for T {} +impl !MyTrait for u32 {} //~ ERROR E0751 + +// The second impl specializes the first, no error. +trait MyTrait2 {} +impl<T> MyTrait2 for T {} +impl MyTrait2 for u32 {} + +fn main() {} diff --git a/tests/ui/traits/negative-impls/negative-specializes-positive.stderr b/tests/ui/traits/negative-impls/negative-specializes-positive.stderr new file mode 100644 index 000000000..9f9e28678 --- /dev/null +++ b/tests/ui/traits/negative-impls/negative-specializes-positive.stderr @@ -0,0 +1,21 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/negative-specializes-positive.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: + --> $DIR/negative-specializes-positive.rs:7:1 + | +LL | impl<T> MyTrait for T {} + | --------------------- positive implementation here +LL | impl !MyTrait for u32 {} + | ^^^^^^^^^^^^^^^^^^^^^ negative implementation here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0751`. diff --git a/tests/ui/traits/negative-impls/no-items.rs b/tests/ui/traits/negative-impls/no-items.rs new file mode 100644 index 000000000..5fc6be9b3 --- /dev/null +++ b/tests/ui/traits/negative-impls/no-items.rs @@ -0,0 +1,11 @@ +#![feature(negative_impls)] + +trait MyTrait { + type Foo; +} + +impl !MyTrait for u32 { + type Foo = i32; //~ ERROR negative impls cannot have any items +} + +fn main() {} diff --git a/tests/ui/traits/negative-impls/no-items.stderr b/tests/ui/traits/negative-impls/no-items.stderr new file mode 100644 index 000000000..67b94bba1 --- /dev/null +++ b/tests/ui/traits/negative-impls/no-items.stderr @@ -0,0 +1,9 @@ +error[E0749]: negative impls cannot have any items + --> $DIR/no-items.rs:8:5 + | +LL | type Foo = i32; + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0749`. diff --git a/tests/ui/traits/negative-impls/pin-unsound-issue-66544-clone.rs b/tests/ui/traits/negative-impls/pin-unsound-issue-66544-clone.rs new file mode 100644 index 000000000..a5b856465 --- /dev/null +++ b/tests/ui/traits/negative-impls/pin-unsound-issue-66544-clone.rs @@ -0,0 +1,26 @@ +use std::cell::Cell; +use std::marker::PhantomPinned; +use std::pin::Pin; + +struct MyType<'a>(Cell<Option<&'a mut MyType<'a>>>, PhantomPinned); + +impl<'a> Clone for &'a mut MyType<'a> { + //~^ ERROR E0751 + fn clone(&self) -> &'a mut MyType<'a> { + self.0.take().unwrap() + } +} + +fn main() { + let mut unpinned = MyType(Cell::new(None), PhantomPinned); + let bad_addr = &unpinned as *const MyType<'_> as usize; + let mut p = Box::pin(MyType(Cell::new(Some(&mut unpinned)), PhantomPinned)); + + // p_mut1 is okay: it does not point to the bad_addr + let p_mut1: Pin<&mut MyType<'_>> = p.as_mut(); + assert_ne!(bad_addr, &*p_mut1 as *const _ as usize); + + // but p_mut2 does point to bad_addr! this is unsound + let p_mut2: Pin<&mut MyType<'_>> = p_mut1.clone(); + assert_eq!(bad_addr, &*p_mut2 as *const _ as usize); +} diff --git a/tests/ui/traits/negative-impls/pin-unsound-issue-66544-clone.stderr b/tests/ui/traits/negative-impls/pin-unsound-issue-66544-clone.stderr new file mode 100644 index 000000000..a87acb1fb --- /dev/null +++ b/tests/ui/traits/negative-impls/pin-unsound-issue-66544-clone.stderr @@ -0,0 +1,11 @@ +error[E0751]: found both positive and negative implementation of trait `Clone` for type `&mut MyType<'_>`: + --> $DIR/pin-unsound-issue-66544-clone.rs:7:1 + | +LL | impl<'a> Clone for &'a mut MyType<'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ positive implementation here + | + = note: negative implementation in crate `core` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0751`. diff --git a/tests/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.rs b/tests/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.rs new file mode 100644 index 000000000..606cc65a8 --- /dev/null +++ b/tests/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.rs @@ -0,0 +1,33 @@ +// Demonstrate that "rogue" `DerefMut` impls for `&T` are not allowed. +// +// https://github.com/rust-lang/rust/issues/66544 + +use std::cell::Cell; +use std::marker::PhantomPinned; +use std::ops::DerefMut; +use std::pin::Pin; + +struct MyType<'a>(Cell<Option<&'a mut MyType<'a>>>, PhantomPinned); + +impl<'a> DerefMut for &'a MyType<'a> { + //~^ ERROR E0751 + fn deref_mut(&mut self) -> &mut MyType<'a> { + self.0.take().unwrap() + } +} + +fn main() { + let mut unpinned = MyType(Cell::new(None), PhantomPinned); + let bad_addr = &unpinned as *const MyType<'_> as usize; + let p = Box::pin(MyType(Cell::new(Some(&mut unpinned)), PhantomPinned)); + + // p_ref is okay: it does not point to the bad_addr + let mut p_ref: Pin<&MyType<'_>> = p.as_ref(); + assert_ne!(bad_addr, &*p_ref as *const _ as usize); + + // but p_mut does point to bad_addr! this is unsound + let p_mut: Pin<&mut MyType<'_>> = p_ref.as_mut(); + assert_eq!(bad_addr, &*p_mut as *const _ as usize); + + println!("oh no!"); +} diff --git a/tests/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.stderr b/tests/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.stderr new file mode 100644 index 000000000..9185e8f84 --- /dev/null +++ b/tests/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.stderr @@ -0,0 +1,11 @@ +error[E0751]: found both positive and negative implementation of trait `DerefMut` for type `&MyType<'_>`: + --> $DIR/pin-unsound-issue-66544-derefmut.rs:12:1 + | +LL | impl<'a> DerefMut for &'a MyType<'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ positive implementation here + | + = note: negative implementation in crate `core` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0751`. diff --git a/tests/ui/traits/negative-impls/positive-specializes-negative.rs b/tests/ui/traits/negative-impls/positive-specializes-negative.rs new file mode 100644 index 000000000..a06b35765 --- /dev/null +++ b/tests/ui/traits/negative-impls/positive-specializes-negative.rs @@ -0,0 +1,9 @@ +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete +#![feature(negative_impls)] + +trait MyTrait {} + +impl<T> !MyTrait for T {} +impl MyTrait for u32 {} //~ ERROR E0751 + +fn main() {} diff --git a/tests/ui/traits/negative-impls/positive-specializes-negative.stderr b/tests/ui/traits/negative-impls/positive-specializes-negative.stderr new file mode 100644 index 000000000..545f94143 --- /dev/null +++ b/tests/ui/traits/negative-impls/positive-specializes-negative.stderr @@ -0,0 +1,21 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/positive-specializes-negative.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: + --> $DIR/positive-specializes-negative.rs:7:1 + | +LL | impl<T> !MyTrait for T {} + | ---------------------- negative implementation here +LL | impl MyTrait for u32 {} + | ^^^^^^^^^^^^^^^^^^^^ positive implementation here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0751`. diff --git a/tests/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs b/tests/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs new file mode 100644 index 000000000..c1f96ab8c --- /dev/null +++ b/tests/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs @@ -0,0 +1,24 @@ +// check-pass + +#![feature(negative_impls)] +#![feature(with_negative_coherence)] + +// aux-build: foreign_trait.rs + +// Test that we cannot implement `LocalTrait` for `String`, +// even though there is a `String: !ForeignTrait` impl. +// +// This may not be the behavior we want long term, but it's the +// current semantics that we implemented so as to land `!Foo` impls +// quickly. See internals thread: +// +// https://internals.rust-lang.org/t/foo/11587/ + +extern crate foreign_trait; +use foreign_trait::ForeignTrait; + +trait LocalTrait {} +impl<T: ForeignTrait> LocalTrait for T {} +impl LocalTrait for String {} + +fn main() {} |