From e8a05e201ee6cea12fe05e4271e91fd40c2fb235 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 8 Jan 2020 06:39:38 -0500 Subject: [PATCH] permit negative impls for non-auto traits --- src/libcore/clone.rs | 5 +++ src/libcore/ops/deref.rs | 4 ++ src/librustc_error_codes/error_codes.rs | 4 +- src/librustc_error_codes/error_codes/E0749.md | 4 ++ src/librustc_error_codes/error_codes/E0750.md | 4 ++ src/librustc_typeck/check/mod.rs | 44 ++++++++++++++----- src/librustc_typeck/check/wfcheck.rs | 30 ++++++------- src/test/ui/error-codes/E0192.rs | 12 ----- src/test/ui/error-codes/E0192.stderr | 11 ----- .../specialization/defaultimpl/validation.rs | 3 +- .../defaultimpl/validation.stderr | 18 +++++--- src/test/ui/syntax-trait-polarity.rs | 2 - src/test/ui/syntax-trait-polarity.stderr | 25 ++--------- .../negative-impls/auxiliary/foreign_trait.rs | 6 +++ .../negated-auto-traits-error.rs} | 0 .../negated-auto-traits-error.stderr} | 14 +++--- .../negated-auto-traits-rpass.rs} | 0 .../negative-impls/negative-default-impls.rs | 10 +++++ .../negative-default-impls.stderr | 9 ++++ .../negative-specializes-positive-item.rs | 13 ++++++ .../negative-specializes-positive-item.stderr | 12 +++++ .../negative-specializes-positive.rs | 14 ++++++ .../negative-specializes-positive.stderr | 11 +++++ src/test/ui/traits/negative-impls/no-items.rs | 11 +++++ .../ui/traits/negative-impls/no-items.stderr | 9 ++++ .../pin-unsound-issue-66544-clone.rs | 26 +++++++++++ .../pin-unsound-issue-66544-clone.stderr | 13 ++++++ .../pin-unsound-issue-66544-derefmut.rs | 33 ++++++++++++++ .../pin-unsound-issue-66544-derefmut.stderr | 13 ++++++ .../positive-specializes-negative.rs | 9 ++++ .../positive-specializes-negative.stderr | 11 +++++ .../rely-on-negative-impl-in-coherence.rs | 21 +++++++++ .../rely-on-negative-impl-in-coherence.stderr | 11 +++++ .../typeck-negative-impls-builtin.rs | 6 ++- .../typeck-negative-impls-builtin.stderr | 11 ----- 35 files changed, 328 insertions(+), 101 deletions(-) create mode 100644 src/librustc_error_codes/error_codes/E0749.md create mode 100644 src/librustc_error_codes/error_codes/E0750.md delete mode 100644 src/test/ui/error-codes/E0192.rs delete mode 100644 src/test/ui/error-codes/E0192.stderr create mode 100644 src/test/ui/traits/negative-impls/auxiliary/foreign_trait.rs rename src/test/ui/traits/{traits-negative-impls.rs => negative-impls/negated-auto-traits-error.rs} (100%) rename src/test/ui/traits/{traits-negative-impls.stderr => negative-impls/negated-auto-traits-error.stderr} (92%) rename src/test/ui/traits/{traits-negative-impls-rpass.rs => negative-impls/negated-auto-traits-rpass.rs} (100%) create mode 100644 src/test/ui/traits/negative-impls/negative-default-impls.rs create mode 100644 src/test/ui/traits/negative-impls/negative-default-impls.stderr create mode 100644 src/test/ui/traits/negative-impls/negative-specializes-positive-item.rs create mode 100644 src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr create mode 100644 src/test/ui/traits/negative-impls/negative-specializes-positive.rs create mode 100644 src/test/ui/traits/negative-impls/negative-specializes-positive.stderr create mode 100644 src/test/ui/traits/negative-impls/no-items.rs create mode 100644 src/test/ui/traits/negative-impls/no-items.stderr create mode 100644 src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.rs create mode 100644 src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.stderr create mode 100644 src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.rs create mode 100644 src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.stderr create mode 100644 src/test/ui/traits/negative-impls/positive-specializes-negative.rs create mode 100644 src/test/ui/traits/negative-impls/positive-specializes-negative.stderr create mode 100644 src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs create mode 100644 src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.stderr rename src/test/ui/{typeck => traits/negative-impls}/typeck-negative-impls-builtin.rs (67%) delete mode 100644 src/test/ui/typeck/typeck-negative-impls-builtin.stderr diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 9a412e57294..629c197e376 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -227,4 +227,9 @@ mod impls { *self } } + + // Shared references can be cloned, but mutable references *cannot*! + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(bootstrap))] + impl !Clone for &mut T {} } diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 68244fdb381..e2deeb55661 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -81,6 +81,10 @@ impl Deref for &T { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl !DerefMut for &T {} + #[stable(feature = "rust1", since = "1.0.0")] impl Deref for &mut T { type Target = T; diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 86da425060e..bff20c2a62c 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -97,7 +97,6 @@ E0184: include_str!("./error_codes/E0184.md"), E0185: include_str!("./error_codes/E0185.md"), E0186: include_str!("./error_codes/E0186.md"), E0191: include_str!("./error_codes/E0191.md"), -E0192: include_str!("./error_codes/E0192.md"), E0193: include_str!("./error_codes/E0193.md"), E0195: include_str!("./error_codes/E0195.md"), E0197: include_str!("./error_codes/E0197.md"), @@ -426,6 +425,8 @@ E0745: include_str!("./error_codes/E0745.md"), E0746: include_str!("./error_codes/E0746.md"), E0747: include_str!("./error_codes/E0747.md"), E0748: include_str!("./error_codes/E0748.md"), +E0749: include_str!("./error_codes/E0749.md"), +E0750: include_str!("./error_codes/E0750.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard @@ -460,6 +461,7 @@ E0748: include_str!("./error_codes/E0748.md"), // E0188, // can not cast an immutable reference to a mutable pointer // E0189, // deprecated: can only cast a boxed pointer to a boxed object // E0190, // deprecated: can only cast a &-pointer to an &-object +// E0192, // negative impl only applicable to auto traits // E0194, // merged into E0403 // E0196, // cannot determine a type for this closure E0208, diff --git a/src/librustc_error_codes/error_codes/E0749.md b/src/librustc_error_codes/error_codes/E0749.md new file mode 100644 index 00000000000..9eb8ee4e3fd --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0749.md @@ -0,0 +1,4 @@ +Negative impls are not allowed to have any items. Negative impls +declare that a trait is **not** implemented (and never will be) and +hence there is no need to specify the values for trait methods or +other items. diff --git a/src/librustc_error_codes/error_codes/E0750.md b/src/librustc_error_codes/error_codes/E0750.md new file mode 100644 index 00000000000..e0cf56f716f --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0750.md @@ -0,0 +1,4 @@ +Negative impls cannot be default impls. A default impl supplies +default values for the items within to be used by other impls, whereas +a negative impl declares that there are no other impls. These don't +make sense to combine. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e7ba00ac245..98ff5ccc82f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1659,11 +1659,14 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: DefId, span: _ => unreachable!(), }; - tcx.sess.span_err(span, &format!( + tcx.sess.span_err( + span, + &format!( "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ a parent scope", if is_async { "async fn" } else { "impl Trait" }, - )); + ), + ); } } @@ -1841,8 +1844,8 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: DefId, span: Span) Ok(ConstValue::ByRef { alloc, .. }) => { if alloc.relocations().len() != 0 { let msg = "statics with a custom `#[link_section]` must be a \ - simple list of bytes on the wasm target with no \ - extra levels of indirection such as references"; + simple list of bytes on the wasm target with no \ + extra levels of indirection such as references"; tcx.sess.span_err(span, msg); } } @@ -1971,6 +1974,24 @@ fn check_impl_items_against_trait<'tcx>( return; } + // Negative impls are not expected to have any items + match tcx.impl_polarity(impl_id) { + ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {} + ty::ImplPolarity::Negative => { + if !impl_item_refs.is_empty() { + let first_item_span = tcx.hir().impl_item(impl_item_refs[0].id).span; + struct_span_err!( + tcx.sess, + first_item_span, + E0749, + "negative impls cannot have any items" + ) + .emit(); + } + return; + } + } + // Locate trait definition and items let trait_def = tcx.trait_def(impl_trait_ref.def_id); @@ -2010,7 +2031,7 @@ fn check_impl_items_against_trait<'tcx>( impl_item.span, E0323, "item `{}` is an associated const, \ - which doesn't match its trait `{}`", + which doesn't match its trait `{}`", ty_impl_item.ident, impl_trait_ref.print_only_trait_path() ); @@ -3554,7 +3575,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let adjusted_ty = autoderef.unambiguous_final_ty(self); debug!( "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ - index_ty={:?})", + index_ty={:?})", expr, base_expr, adjusted_ty, index_ty ); @@ -4705,7 +4726,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label( fn_span, "implicitly returns `()` as its body has no tail or `return` \ - expression", + expression", ); } }, @@ -5577,11 +5598,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { - self.tcx.sess.delay_span_bug(span, &format!( + self.tcx.sess.delay_span_bug( + span, + &format!( "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", self_ty, impl_ty, - )); + ), + ); } } } @@ -5767,7 +5791,7 @@ fn fatally_break_rust(sess: &Session) { handler.note_without_error("the compiler expectedly panicked. this is a feature."); handler.note_without_error( "we would appreciate a joke overview: \ - https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", + https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", ); handler.note_without_error(&format!( "rustc {} running on {}", diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 27be0faade8..c89c4b028b4 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -124,18 +124,16 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: DefId) { } (ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => { // FIXME(#27579): what amount of WF checking do we need for neg impls? - if let (Some(of_trait), false) = (of_trait, is_auto) { + if let hir::Defaultness::Default { .. } = defaultness { + let mut spans = vec![span]; + spans.extend(defaultness_span); struct_span_err!( tcx.sess, - span.to(of_trait.path.span), - E0192, - "invalid negative impl" + spans, + E0750, + "negative impls cannot be default impls" ) - .note( - "negative impls are only allowed for auto traits, like `Send` and \ - `Sync`", - ) - .emit() + .emit(); } } (ty::ImplPolarity::Reservation, _) => { @@ -902,13 +900,13 @@ fn check_opaque_types<'fcx, 'tcx>( .struct_span_err( span, "non-defining opaque type use \ - in defining scope", + in defining scope", ) .span_label( param_span, "cannot use static lifetime; use a bound lifetime \ - instead or remove the lifetime parameter from the \ - opaque type", + instead or remove the lifetime parameter from the \ + opaque type", ) .emit(); } else { @@ -923,13 +921,13 @@ fn check_opaque_types<'fcx, 'tcx>( .struct_span_err( span, "non-defining opaque type use \ - in defining scope", + in defining scope", ) .span_note( tcx.def_span(param.def_id), &format!( "used non-generic const {} for \ - generic parameter", + generic parameter", ty, ), ) @@ -944,7 +942,7 @@ fn check_opaque_types<'fcx, 'tcx>( .struct_span_err( span, "non-defining opaque type use \ - in defining scope", + in defining scope", ) .span_note(spans, "lifetime used multiple times") .emit(); @@ -1030,7 +1028,7 @@ fn check_method_receiver<'fcx, 'tcx>( span, &format!( "`{}` cannot be used as the type of `self` without \ - the `arbitrary_self_types` feature", + the `arbitrary_self_types` feature", receiver_ty, ), ) diff --git a/src/test/ui/error-codes/E0192.rs b/src/test/ui/error-codes/E0192.rs deleted file mode 100644 index c52977e49b4..00000000000 --- a/src/test/ui/error-codes/E0192.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![feature(optin_builtin_traits)] - -trait Trait { - type Bar; -} - -struct Foo; - -impl !Trait for Foo { } //~ ERROR E0192 - -fn main() { -} diff --git a/src/test/ui/error-codes/E0192.stderr b/src/test/ui/error-codes/E0192.stderr deleted file mode 100644 index da706dea167..00000000000 --- a/src/test/ui/error-codes/E0192.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0192]: invalid negative impl - --> $DIR/E0192.rs:9:6 - | -LL | impl !Trait for Foo { } - | ^^^^^^ - | - = note: negative impls are only allowed for auto traits, like `Send` and `Sync` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0192`. diff --git a/src/test/ui/specialization/defaultimpl/validation.rs b/src/test/ui/specialization/defaultimpl/validation.rs index 5b8a72104e3..ac8742c70c8 100644 --- a/src/test/ui/specialization/defaultimpl/validation.rs +++ b/src/test/ui/specialization/defaultimpl/validation.rs @@ -8,8 +8,9 @@ default impl S {} //~ ERROR inherent impls cannot be `default` default unsafe impl Send for S {} //~ ERROR impls of auto traits cannot be default default impl !Send for Z {} //~ ERROR impls of auto traits cannot be default + //~^ ERROR negative impls cannot be default impls trait Tr {} -default impl !Tr for S {} //~ ERROR invalid negative impl +default impl !Tr for S {} //~ ERROR negative impls cannot be default impls fn main() {} diff --git a/src/test/ui/specialization/defaultimpl/validation.stderr b/src/test/ui/specialization/defaultimpl/validation.stderr index e03153f343b..9bf59bd4f63 100644 --- a/src/test/ui/specialization/defaultimpl/validation.stderr +++ b/src/test/ui/specialization/defaultimpl/validation.stderr @@ -24,14 +24,18 @@ LL | default impl !Send for Z {} | | | default because of this -error[E0192]: invalid negative impl - --> $DIR/validation.rs:13:14 +error[E0750]: negative impls cannot be default impls + --> $DIR/validation.rs:10:14 + | +LL | default impl !Send for Z {} + | ^^^^^^^ ^ + +error[E0750]: negative impls cannot be default impls + --> $DIR/validation.rs:14:14 | LL | default impl !Tr for S {} - | ^^^ - | - = note: negative impls are only allowed for auto traits, like `Send` and `Sync` + | ^^^^^^^ ^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0192`. +For more information about this error, try `rustc --explain E0750`. diff --git a/src/test/ui/syntax-trait-polarity.rs b/src/test/ui/syntax-trait-polarity.rs index bfbe6394c16..739a3c12dfb 100644 --- a/src/test/ui/syntax-trait-polarity.rs +++ b/src/test/ui/syntax-trait-polarity.rs @@ -12,7 +12,6 @@ trait TestTrait {} unsafe impl !Send for TestType {} //~^ ERROR negative impls cannot be unsafe impl !TestTrait for TestType {} -//~^ ERROR invalid negative impl struct TestType2(T); @@ -22,6 +21,5 @@ impl !TestType2 {} unsafe impl !Send for TestType2 {} //~^ ERROR negative impls cannot be unsafe impl !TestTrait for TestType2 {} -//~^ ERROR invalid negative impl fn main() {} diff --git a/src/test/ui/syntax-trait-polarity.stderr b/src/test/ui/syntax-trait-polarity.stderr index f70d67ec7dc..1fd40fb6657 100644 --- a/src/test/ui/syntax-trait-polarity.stderr +++ b/src/test/ui/syntax-trait-polarity.stderr @@ -16,7 +16,7 @@ LL | unsafe impl !Send for TestType {} | unsafe because of this error: inherent impls cannot be negative - --> $DIR/syntax-trait-polarity.rs:19:10 + --> $DIR/syntax-trait-polarity.rs:18:10 | LL | impl !TestType2 {} | -^^^^^^^^^^^^ inherent impl for this type @@ -24,7 +24,7 @@ LL | impl !TestType2 {} | negative because of this error[E0198]: negative impls cannot be unsafe - --> $DIR/syntax-trait-polarity.rs:22:16 + --> $DIR/syntax-trait-polarity.rs:21:16 | LL | unsafe impl !Send for TestType2 {} | ------ -^^^^ @@ -32,23 +32,6 @@ LL | unsafe impl !Send for TestType2 {} | | negative because of this | unsafe because of this -error[E0192]: invalid negative impl - --> $DIR/syntax-trait-polarity.rs:14:6 - | -LL | impl !TestTrait for TestType {} - | ^^^^^^^^^^ - | - = note: negative impls are only allowed for auto traits, like `Send` and `Sync` +error: aborting due to 4 previous errors -error[E0192]: invalid negative impl - --> $DIR/syntax-trait-polarity.rs:24:9 - | -LL | impl !TestTrait for TestType2 {} - | ^^^^^^^^^^ - | - = note: negative impls are only allowed for auto traits, like `Send` and `Sync` - -error: aborting due to 6 previous errors - -Some errors have detailed explanations: E0192, E0198. -For more information about an error, try `rustc --explain E0192`. +For more information about this error, try `rustc --explain E0198`. diff --git a/src/test/ui/traits/negative-impls/auxiliary/foreign_trait.rs b/src/test/ui/traits/negative-impls/auxiliary/foreign_trait.rs new file mode 100644 index 00000000000..1790b24be33 --- /dev/null +++ b/src/test/ui/traits/negative-impls/auxiliary/foreign_trait.rs @@ -0,0 +1,6 @@ +#![feature(optin_builtin_traits)] + +pub trait ForeignTrait { } + +impl ForeignTrait for u32 { } +impl !ForeignTrait for String {} diff --git a/src/test/ui/traits/traits-negative-impls.rs b/src/test/ui/traits/negative-impls/negated-auto-traits-error.rs similarity index 100% rename from src/test/ui/traits/traits-negative-impls.rs rename to src/test/ui/traits/negative-impls/negated-auto-traits-error.rs diff --git a/src/test/ui/traits/traits-negative-impls.stderr b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr similarity index 92% rename from src/test/ui/traits/traits-negative-impls.stderr rename to src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr index 599bbfe2225..69a91b09e3e 100644 --- a/src/test/ui/traits/traits-negative-impls.stderr +++ b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -1,5 +1,5 @@ error[E0277]: `dummy::TestType` cannot be sent between threads safely - --> $DIR/traits-negative-impls.rs:23:11 + --> $DIR/negated-auto-traits-error.rs:23:11 | LL | struct Outer(T); | ------------------------- required by `Outer` @@ -10,7 +10,7 @@ LL | Outer(TestType); = help: the trait `std::marker::Send` is not implemented for `dummy::TestType` error[E0277]: `dummy::TestType` cannot be sent between threads safely - --> $DIR/traits-negative-impls.rs:23:5 + --> $DIR/negated-auto-traits-error.rs:23:5 | LL | struct Outer(T); | ------------------------- required by `Outer` @@ -21,7 +21,7 @@ LL | Outer(TestType); = help: the trait `std::marker::Send` is not implemented for `dummy::TestType` error[E0277]: `dummy1b::TestType` cannot be sent between threads safely - --> $DIR/traits-negative-impls.rs:32:13 + --> $DIR/negated-auto-traits-error.rs:32:13 | LL | fn is_send(_: T) {} | ------- ---- required by this bound in `is_send` @@ -32,7 +32,7 @@ LL | is_send(TestType); = help: the trait `std::marker::Send` is not implemented for `dummy1b::TestType` error[E0277]: `dummy1c::TestType` cannot be sent between threads safely - --> $DIR/traits-negative-impls.rs:40:13 + --> $DIR/negated-auto-traits-error.rs:40:13 | LL | fn is_send(_: T) {} | ------- ---- required by this bound in `is_send` @@ -44,7 +44,7 @@ LL | is_send((8, TestType)); = note: required because it appears within the type `({integer}, dummy1c::TestType)` error[E0277]: `dummy2::TestType` cannot be sent between threads safely - --> $DIR/traits-negative-impls.rs:48:13 + --> $DIR/negated-auto-traits-error.rs:48:13 | LL | fn is_send(_: T) {} | ------- ---- required by this bound in `is_send` @@ -60,7 +60,7 @@ LL | is_send(Box::new(TestType)); = note: required because it appears within the type `std::boxed::Box` error[E0277]: `dummy3::TestType` cannot be sent between threads safely - --> $DIR/traits-negative-impls.rs:56:13 + --> $DIR/negated-auto-traits-error.rs:56:13 | LL | fn is_send(_: T) {} | ------- ---- required by this bound in `is_send` @@ -74,7 +74,7 @@ LL | is_send(Box::new(Outer2(TestType))); = note: required because it appears within the type `std::boxed::Box>` error[E0277]: `main::TestType` cannot be sent between threads safely - --> $DIR/traits-negative-impls.rs:66:13 + --> $DIR/negated-auto-traits-error.rs:66:13 | LL | fn is_sync(_: T) {} | ------- ---- required by this bound in `is_sync` diff --git a/src/test/ui/traits/traits-negative-impls-rpass.rs b/src/test/ui/traits/negative-impls/negated-auto-traits-rpass.rs similarity index 100% rename from src/test/ui/traits/traits-negative-impls-rpass.rs rename to src/test/ui/traits/negative-impls/negated-auto-traits-rpass.rs diff --git a/src/test/ui/traits/negative-impls/negative-default-impls.rs b/src/test/ui/traits/negative-impls/negative-default-impls.rs new file mode 100644 index 00000000000..b23ac87f899 --- /dev/null +++ b/src/test/ui/traits/negative-impls/negative-default-impls.rs @@ -0,0 +1,10 @@ +#![feature(optin_builtin_traits)] +#![feature(specialization)] + +trait MyTrait { + type Foo; +} + +default impl !MyTrait for u32 {} //~ ERROR negative impls cannot be default impls + +fn main() {} diff --git a/src/test/ui/traits/negative-impls/negative-default-impls.stderr b/src/test/ui/traits/negative-impls/negative-default-impls.stderr new file mode 100644 index 00000000000..d2423d01a9a --- /dev/null +++ b/src/test/ui/traits/negative-impls/negative-default-impls.stderr @@ -0,0 +1,9 @@ +error[E0750]: negative impls cannot be default impls + --> $DIR/negative-default-impls.rs:8:14 + | +LL | default impl !MyTrait for u32 {} + | ^^^^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0750`. diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.rs b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.rs new file mode 100644 index 00000000000..2ebf0bdcbe9 --- /dev/null +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.rs @@ -0,0 +1,13 @@ +#![feature(specialization)] +#![feature(optin_builtin_traits)] + +// Negative impl for u32 cannot "specialize" the base impl. +trait MyTrait { + fn foo(); +} +impl MyTrait for T { + default fn foo() { } +} +impl !MyTrait for u32 { } //~ ERROR conflicting implementations + +fn main() { } diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr new file mode 100644 index 00000000000..83421b4d7a1 --- /dev/null +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `MyTrait` for type `u32`: + --> $DIR/negative-specializes-positive-item.rs:11:1 + | +LL | impl MyTrait for T { + | --------------------- first implementation here +... +LL | impl !MyTrait for u32 { } + | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive.rs b/src/test/ui/traits/negative-impls/negative-specializes-positive.rs new file mode 100644 index 00000000000..7ab01612295 --- /dev/null +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive.rs @@ -0,0 +1,14 @@ +#![feature(specialization)] +#![feature(optin_builtin_traits)] + +// Negative impl for u32 cannot "specialize" the base impl. +trait MyTrait { } +impl MyTrait for T { } +impl !MyTrait for u32 { } //~ ERROR conflicting implementations + +// The second impl specializes the first, no error. +trait MyTrait2 { } +impl MyTrait2 for T { } +impl MyTrait2 for u32 { } + +fn main() { } diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr b/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr new file mode 100644 index 00000000000..a542e88673e --- /dev/null +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `MyTrait` for type `u32`: + --> $DIR/negative-specializes-positive.rs:7:1 + | +LL | impl MyTrait for T { } + | --------------------- first implementation here +LL | impl !MyTrait for u32 { } + | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/traits/negative-impls/no-items.rs b/src/test/ui/traits/negative-impls/no-items.rs new file mode 100644 index 00000000000..5bfbf9653ab --- /dev/null +++ b/src/test/ui/traits/negative-impls/no-items.rs @@ -0,0 +1,11 @@ +#![feature(optin_builtin_traits)] + +trait MyTrait { + type Foo; +} + +impl !MyTrait for u32 { + type Foo = i32; //~ ERROR negative impls cannot have any items +} + +fn main() {} diff --git a/src/test/ui/traits/negative-impls/no-items.stderr b/src/test/ui/traits/negative-impls/no-items.stderr new file mode 100644 index 00000000000..67b94bba121 --- /dev/null +++ b/src/test/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/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.rs b/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.rs new file mode 100644 index 00000000000..5c3e7fe3d01 --- /dev/null +++ b/src/test/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>>, PhantomPinned); + +impl<'a> Clone for &'a mut MyType<'a> { //~ ERROR conflicting implementations + fn clone(&self) -> &'a mut MyType<'a> { + self.0.replace(None).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/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.stderr b/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.stderr new file mode 100644 index 00000000000..1655d806fb4 --- /dev/null +++ b/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-clone.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `std::clone::Clone` for type `&mut MyType<'_>`: + --> $DIR/pin-unsound-issue-66544-clone.rs:7:1 + | +LL | impl<'a> Clone for &'a mut MyType<'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl std::clone::Clone for &mut T + where T: ?Sized; + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.rs b/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.rs new file mode 100644 index 00000000000..a34b8d635ab --- /dev/null +++ b/src/test/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>>, PhantomPinned); + +impl<'a> DerefMut for &'a MyType<'a> { //~ ERROR conflicting implementations + fn deref_mut(&mut self) -> &mut MyType<'a> { + self.0.replace(None).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/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.stderr b/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.stderr new file mode 100644 index 00000000000..80c9682a010 --- /dev/null +++ b/src/test/ui/traits/negative-impls/pin-unsound-issue-66544-derefmut.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `std::ops::DerefMut` for type `&MyType<'_>`: + --> $DIR/pin-unsound-issue-66544-derefmut.rs:12:1 + | +LL | impl<'a> DerefMut for &'a MyType<'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl std::ops::DerefMut for &T + where T: ?Sized; + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/traits/negative-impls/positive-specializes-negative.rs b/src/test/ui/traits/negative-impls/positive-specializes-negative.rs new file mode 100644 index 00000000000..20267cf3aba --- /dev/null +++ b/src/test/ui/traits/negative-impls/positive-specializes-negative.rs @@ -0,0 +1,9 @@ +#![feature(specialization)] +#![feature(optin_builtin_traits)] + +trait MyTrait { } + +impl !MyTrait for T { } +impl MyTrait for u32 { } //~ ERROR conflicting implementations + +fn main() { } diff --git a/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr b/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr new file mode 100644 index 00000000000..6e41759d2a2 --- /dev/null +++ b/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `MyTrait` for type `u32`: + --> $DIR/positive-specializes-negative.rs:7:1 + | +LL | impl !MyTrait for T { } + | ---------------------- first implementation here +LL | impl MyTrait for u32 { } + | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs b/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs new file mode 100644 index 00000000000..b823c0f7864 --- /dev/null +++ b/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs @@ -0,0 +1,21 @@ +#![feature(optin_builtin_traits)] + +// 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 LocalTrait for T { } +impl LocalTrait for String { } //~ ERROR conflicting implementations + +fn main() { } diff --git a/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.stderr b/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.stderr new file mode 100644 index 00000000000..7cce45d2c8f --- /dev/null +++ b/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `LocalTrait` for type `std::string::String`: + --> $DIR/rely-on-negative-impl-in-coherence.rs:19:1 + | +LL | impl LocalTrait for T { } + | -------------------------------------- first implementation here +LL | impl LocalTrait for String { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::string::String` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/typeck/typeck-negative-impls-builtin.rs b/src/test/ui/traits/negative-impls/typeck-negative-impls-builtin.rs similarity index 67% rename from src/test/ui/typeck/typeck-negative-impls-builtin.rs rename to src/test/ui/traits/negative-impls/typeck-negative-impls-builtin.rs index fef98977cc4..6a2e99f8147 100644 --- a/src/test/ui/typeck/typeck-negative-impls-builtin.rs +++ b/src/test/ui/traits/negative-impls/typeck-negative-impls-builtin.rs @@ -1,12 +1,14 @@ +// run-pass + #![feature(optin_builtin_traits)] +#![allow(dead_code)] struct TestType; trait TestTrait { - fn dummy(&self) { } + fn dummy(&self) {} } impl !TestTrait for TestType {} -//~^ ERROR invalid negative impl fn main() {} diff --git a/src/test/ui/typeck/typeck-negative-impls-builtin.stderr b/src/test/ui/typeck/typeck-negative-impls-builtin.stderr deleted file mode 100644 index c90655086ac..00000000000 --- a/src/test/ui/typeck/typeck-negative-impls-builtin.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0192]: invalid negative impl - --> $DIR/typeck-negative-impls-builtin.rs:9:6 - | -LL | impl !TestTrait for TestType {} - | ^^^^^^^^^^ - | - = note: negative impls are only allowed for auto traits, like `Send` and `Sync` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0192`.