From 6545b07dbf5200c272c722b1bb555de64933677f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 22 Jul 2020 21:12:37 +0200 Subject: [PATCH 1/3] restrict auto traits --- src/librustc_typeck/check/dropck.rs | 46 +++++++++++-------- src/librustc_typeck/check/wfcheck.rs | 9 ++-- ...ck-default-trait-impl-constituent-types.rs | 2 +- src/test/ui/issues/issue-17959.rs | 2 +- src/test/ui/issues/issue-17959.stderr | 2 +- src/test/ui/issues/issue-29516.rs | 4 +- src/test/ui/issues/issue-29516.stderr | 8 ++++ src/test/ui/issues/issue-38868.stderr | 2 +- src/test/ui/issues/issue-41974.rs | 14 +++--- src/test/ui/issues/issue-41974.stderr | 26 ++++++++--- src/test/ui/reject-specialized-drops-8142.rs | 18 ++++---- .../ui/reject-specialized-drops-8142.stderr | 18 ++++---- .../specialization/defaultimpl/validation.rs | 6 +-- .../defaultimpl/validation.stderr | 22 +++++++-- .../ui/traits/negative-impls/issue-74629.rs | 30 ++++++++++++ .../traits/negative-impls/issue-74629.stderr | 15 ++++++ .../negative-impls/negative-default-impls.rs | 2 +- .../negative-default-impls.stderr | 5 +- .../negative-impls/negative-impl-sized.rs | 9 ++++ .../negative-impls/negative-impl-sized.stderr | 8 ++++ .../negative-specializes-negative.rs | 2 +- 21 files changed, 178 insertions(+), 72 deletions(-) create mode 100644 src/test/ui/issues/issue-29516.stderr create mode 100644 src/test/ui/traits/negative-impls/issue-74629.rs create mode 100644 src/test/ui/traits/negative-impls/issue-74629.stderr create mode 100644 src/test/ui/traits/negative-impls/negative-impl-sized.rs create mode 100644 src/test/ui/traits/negative-impls/negative-impl-sized.stderr diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index f6991120f3479..ca35e2a7841b6 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -1,6 +1,5 @@ use crate::check::regionck::RegionCtxt; use crate::hir; -use crate::hir::def_id::{DefId, LocalDefId}; use rustc_errors::{struct_span_err, ErrorReported}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferOk, RegionckMode, TyCtxtInferExt}; @@ -9,6 +8,7 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, Predicate, Ty, TyCtxt}; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::query::dropck_outlives::AtExt; @@ -32,6 +32,9 @@ use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt /// cannot do `struct S; impl Drop for S { ... }`). /// pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorReported> { + check_restricted_impl(tcx, drop_impl_did) +} +pub fn check_restricted_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorReported> { let dtor_self_type = tcx.type_of(drop_impl_did); let dtor_predicates = tcx.predicates_of(drop_impl_did); match dtor_self_type.kind { @@ -45,21 +48,25 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro ensure_drop_predicates_are_implied_by_item_defn( tcx, + drop_impl_did.expect_local(), dtor_predicates, - adt_def.did.expect_local(), + adt_def.did, self_to_impl_substs, ) } _ => { - // Destructors only work on nominal types. This was - // already checked by coherence, but compilation may - // not have been terminated. - let span = tcx.def_span(drop_impl_did); - tcx.sess.delay_span_bug( - span, - &format!("should have been rejected by coherence check: {}", dtor_self_type), - ); - Err(ErrorReported) + // Destructors only work on nominal types. This was + // already checked by coherence, for auto impls we + // simply check that there are no bounds here. + if dtor_predicates.predicates.is_empty() { + Ok(()) + } else { + tcx.sess.span_err( + tcx.def_span(drop_impl_did), + "auto traits must not contain where bounds", + ); + Err(ErrorReported) + } } } } @@ -94,11 +101,13 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( Err(_) => { let item_span = tcx.def_span(self_type_did); let self_descr = tcx.def_kind(self_type_did).descr(self_type_did); + let trait_ref = tcx.impl_trait_ref(drop_impl_did).unwrap(); struct_span_err!( tcx.sess, drop_impl_span, E0366, - "`Drop` impls cannot be specialized" + "`{}` impls cannot be specialized", + trait_ref.print_only_trait_path() ) .span_note( item_span, @@ -142,8 +151,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( /// implied by assuming the predicates attached to self_type_did. fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( tcx: TyCtxt<'tcx>, + drop_impl_did: LocalDefId, dtor_predicates: ty::GenericPredicates<'tcx>, - self_type_did: LocalDefId, + self_type_did: DefId, self_to_impl_substs: SubstsRef<'tcx>, ) -> Result<(), ErrorReported> { let mut result = Ok(()); @@ -183,8 +193,6 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // absent. So we report an error that the Drop impl injected a // predicate that is not present on the struct definition. - let self_type_hir_id = tcx.hir().as_local_hir_id(self_type_did); - // We can assume the predicates attached to struct/enum definition // hold. let generic_assumptions = tcx.predicates_of(self_type_did); @@ -238,13 +246,15 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( }; if !assumptions_in_impl_context.iter().copied().any(predicate_matches_closure) { - let item_span = tcx.hir().span(self_type_hir_id); - let self_descr = tcx.def_kind(self_type_did).descr(self_type_did.to_def_id()); + let item_span = tcx.def_span(self_type_did); + let self_descr = tcx.def_kind(self_type_did).descr(self_type_did); + let trait_ref = tcx.impl_trait_ref(drop_impl_did).unwrap(); struct_span_err!( tcx.sess, predicate_sp, E0367, - "`Drop` impl requires `{}` but the {} it is implemented for does not", + "`{}` impl requires `{}` but the {} it is implemented for does not", + trait_ref.print_only_trait_path(), predicate, self_descr, ) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index dabae6cbc4137..20ffdf7ebe457 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -1,9 +1,9 @@ -use crate::check::{FnCtxt, Inherited}; +use crate::check::{dropck::check_restricted_impl, FnCtxt, Inherited}; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::itemlikevisit::ParItemLikeVisitor; @@ -123,7 +123,10 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_impl(tcx, item, self_ty, of_trait); } (ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => { - // FIXME(#27579): what amount of WF checking do we need for neg impls? + if let Err(ErrorReported) = check_restricted_impl(tcx, def_id.to_def_id()) { + return; + } + if let hir::Defaultness::Default { .. } = defaultness { let mut spans = vec![span]; spans.extend(defaultness_span); diff --git a/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.rs b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.rs index 6483b9213dc53..1ec5d20ad6f49 100644 --- a/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.rs +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.rs @@ -3,7 +3,7 @@ auto trait MyTrait {} -impl !MyTrait for *mut T {} +impl !MyTrait for *mut T {} struct MyS; diff --git a/src/test/ui/issues/issue-17959.rs b/src/test/ui/issues/issue-17959.rs index 01416a0d79e5f..0d4ede6d653ff 100644 --- a/src/test/ui/issues/issue-17959.rs +++ b/src/test/ui/issues/issue-17959.rs @@ -9,7 +9,7 @@ struct G { } impl Drop for G { -//~^ ERROR `Drop` impl requires `T: std::marker::Sized` +//~^ ERROR `std::ops::Drop` impl requires `T: std::marker::Sized` fn drop(&mut self) { if !self._ptr.is_null() { } diff --git a/src/test/ui/issues/issue-17959.stderr b/src/test/ui/issues/issue-17959.stderr index 29d32c1f3cec6..bd31dcadd3c4b 100644 --- a/src/test/ui/issues/issue-17959.stderr +++ b/src/test/ui/issues/issue-17959.stderr @@ -1,4 +1,4 @@ -error[E0367]: `Drop` impl requires `T: std::marker::Sized` but the struct it is implemented for does not +error[E0367]: `std::ops::Drop` impl requires `T: std::marker::Sized` but the struct it is implemented for does not --> $DIR/issue-17959.rs:11:6 | LL | impl Drop for G { diff --git a/src/test/ui/issues/issue-29516.rs b/src/test/ui/issues/issue-29516.rs index 035f904b15bb3..b377dc4a40441 100644 --- a/src/test/ui/issues/issue-29516.rs +++ b/src/test/ui/issues/issue-29516.rs @@ -1,10 +1,10 @@ -// check-pass #![feature(optin_builtin_traits)] #![feature(negative_impls)] auto trait NotSame {} -impl !NotSame for (A, A) {} +impl !NotSame for (A, A) {} //~ ERROR auto traits must not contain where bounds +// FIXME: Consider allowing (A, B) with `A: Sized`. trait OneOfEach {} diff --git a/src/test/ui/issues/issue-29516.stderr b/src/test/ui/issues/issue-29516.stderr new file mode 100644 index 0000000000000..fd6440da06af2 --- /dev/null +++ b/src/test/ui/issues/issue-29516.stderr @@ -0,0 +1,8 @@ +error: auto traits must not contain where bounds + --> $DIR/issue-29516.rs:6:1 + | +LL | impl !NotSame for (A, A) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-38868.stderr b/src/test/ui/issues/issue-38868.stderr index 10d1e7c4e66dc..5443893721487 100644 --- a/src/test/ui/issues/issue-38868.stderr +++ b/src/test/ui/issues/issue-38868.stderr @@ -1,4 +1,4 @@ -error[E0366]: `Drop` impls cannot be specialized +error[E0366]: `std::ops::Drop` impls cannot be specialized --> $DIR/issue-38868.rs:5:1 | LL | / impl Drop for List { diff --git a/src/test/ui/issues/issue-41974.rs b/src/test/ui/issues/issue-41974.rs index 7875b432d7be4..c1754a7e2ae3b 100644 --- a/src/test/ui/issues/issue-41974.rs +++ b/src/test/ui/issues/issue-41974.rs @@ -1,14 +1,14 @@ #[derive(Copy, Clone)] struct Flags; -trait A { -} +trait A {} -impl Drop for T where T: A { //~ ERROR E0119 - //~^ ERROR E0120 - //~| ERROR E0210 - fn drop(&mut self) { - } +impl Drop for T where T: A { + //~^ ERROR auto traits must not contain where bounds + //~| ERROR E0119 + //~| ERROR E0120 + //~| ERROR E0210 + fn drop(&mut self) {} } fn main() {} diff --git a/src/test/ui/issues/issue-41974.stderr b/src/test/ui/issues/issue-41974.stderr index d082e0a6b5dc4..3afa1f3275ae7 100644 --- a/src/test/ui/issues/issue-41974.stderr +++ b/src/test/ui/issues/issue-41974.stderr @@ -1,7 +1,7 @@ error[E0119]: conflicting implementations of trait `std::ops::Drop` for type `std::boxed::Box<_>`: - --> $DIR/issue-41974.rs:7:1 + --> $DIR/issue-41974.rs:6:1 | -LL | impl Drop for T where T: A { +LL | impl Drop for T where T: A { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `alloc`: @@ -10,21 +10,33 @@ LL | impl Drop for T where T: A { = note: downstream crates may implement trait `A` for type `std::boxed::Box<_>` error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions - --> $DIR/issue-41974.rs:7:18 + --> $DIR/issue-41974.rs:6:18 | -LL | impl Drop for T where T: A { +LL | impl Drop for T where T: A { | ^ must be a struct, enum, or union +error: auto traits must not contain where bounds + --> $DIR/issue-41974.rs:6:1 + | +LL | / impl Drop for T where T: A { +LL | | +LL | | +LL | | +LL | | +LL | | fn drop(&mut self) {} +LL | | } + | |_^ + error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) - --> $DIR/issue-41974.rs:7:6 + --> $DIR/issue-41974.rs:6:6 | -LL | impl Drop for T where T: A { +LL | impl Drop for T where T: A { | ^ type parameter `T` must be used as the type parameter for some local type | = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local = note: only traits defined in the current crate can be implemented for a type parameter -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0119, E0120, E0210. For more information about an error, try `rustc --explain E0119`. diff --git a/src/test/ui/reject-specialized-drops-8142.rs b/src/test/ui/reject-specialized-drops-8142.rs index c4671736d79ec..a751f4bff9a5d 100644 --- a/src/test/ui/reject-specialized-drops-8142.rs +++ b/src/test/ui/reject-specialized-drops-8142.rs @@ -21,11 +21,11 @@ struct TupleStruct(T); union Union { f: T } impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT - //~^ ERROR `Drop` impl requires `'adds_bnd: 'al` + //~^ ERROR `std::ops::Drop` impl requires `'adds_bnd: 'al` fn drop(&mut self) { } } impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT - //~^ ERROR `Drop` impl requires `'adds_bnd: 'al` + //~^ ERROR `std::ops::Drop` impl requires `'adds_bnd: 'al` fn drop(&mut self) { } } impl<'ml> Drop for M<'ml> { fn drop(&mut self) { } } // ACCEPT @@ -38,13 +38,13 @@ impl Drop for N<'static> { fn drop(&mut self) { } } // RE impl Drop for O { fn drop(&mut self) { } } // ACCEPT impl Drop for P { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impls cannot be specialized +//~^ ERROR `std::ops::Drop` impls cannot be specialized impl Drop for Q { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impl requires `AddsBnd: Bound` +//~^ ERROR `std::ops::Drop` impl requires `AddsBnd: Bound` impl<'rbnd,AddsRBnd:'rbnd> Drop for R { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impl requires `AddsRBnd: 'rbnd` +//~^ ERROR `std::ops::Drop` impl requires `AddsRBnd: 'rbnd` impl Drop for S { fn drop(&mut self) { } } // ACCEPT @@ -53,18 +53,18 @@ impl<'t,Bt:'t> Drop for T<'t,Bt> { fn drop(&mut self) { } } // ACCEPT impl Drop for U { fn drop(&mut self) { } } // ACCEPT impl Drop for V { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impls cannot be specialized +//~^ ERROR `std::ops::Drop` impls cannot be specialized impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT //~^ ERROR cannot infer an appropriate lifetime for lifetime parameter `'lw` impl Drop for Enum { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impl requires `AddsBnd: Bound` +//~^ ERROR `std::ops::Drop` impl requires `AddsBnd: Bound` impl Drop for TupleStruct { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impl requires `AddsBnd: Bound` +//~^ ERROR `std::ops::Drop` impl requires `AddsBnd: Bound` impl Drop for Union { fn drop(&mut self) { } } // REJECT -//~^ ERROR `Drop` impl requires `AddsBnd: Bound` +//~^ ERROR `std::ops::Drop` impl requires `AddsBnd: Bound` pub fn main() { } diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr index f819faa278995..7191a06b99e75 100644 --- a/src/test/ui/reject-specialized-drops-8142.stderr +++ b/src/test/ui/reject-specialized-drops-8142.stderr @@ -1,4 +1,4 @@ -error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not +error[E0367]: `std::ops::Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:67:21 | LL | impl Drop for Union { fn drop(&mut self) { } } // REJECT @@ -10,7 +10,7 @@ note: the implementor must specify the same requirement LL | union Union { f: T } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not +error[E0367]: `std::ops::Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:23:20 | LL | impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT @@ -22,7 +22,7 @@ note: the implementor must specify the same requirement LL | struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not +error[E0367]: `std::ops::Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:27:67 | LL | impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT @@ -49,7 +49,7 @@ LL | struct N<'n> { x: &'n i8 } | ^^ = note: ...does not necessarily outlive the static lifetime -error[E0366]: `Drop` impls cannot be specialized +error[E0366]: `std::ops::Drop` impls cannot be specialized --> $DIR/reject-specialized-drops-8142.rs:40:1 | LL | impl Drop for P { fn drop(&mut self) { } } // REJECT @@ -61,7 +61,7 @@ note: use the same sequence of generic type, lifetime and const parameters as th LL | struct P { x: *const Tp } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not +error[E0367]: `std::ops::Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:43:14 | LL | impl Drop for Q { fn drop(&mut self) { } } // REJECT @@ -73,7 +73,7 @@ note: the implementor must specify the same requirement LL | struct Q { x: *const Tq } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0367]: `Drop` impl requires `AddsRBnd: 'rbnd` but the struct it is implemented for does not +error[E0367]: `std::ops::Drop` impl requires `AddsRBnd: 'rbnd` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:46:21 | LL | impl<'rbnd,AddsRBnd:'rbnd> Drop for R { fn drop(&mut self) { } } // REJECT @@ -85,7 +85,7 @@ note: the implementor must specify the same requirement LL | struct R { x: *const Tr } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0366]: `Drop` impls cannot be specialized +error[E0366]: `std::ops::Drop` impls cannot be specialized --> $DIR/reject-specialized-drops-8142.rs:55:1 | LL | impl Drop for V { fn drop(&mut self) { } } // REJECT @@ -121,7 +121,7 @@ LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJ = note: expected `W<'l1, 'l2>` found `W<'_, '_>` -error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not +error[E0367]: `std::ops::Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:61:14 | LL | impl Drop for Enum { fn drop(&mut self) { } } // REJECT @@ -133,7 +133,7 @@ note: the implementor must specify the same requirement LL | enum Enum { Variant(T) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not +error[E0367]: `std::ops::Drop` impl requires `AddsBnd: Bound` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:64:14 | LL | impl Drop for TupleStruct { fn drop(&mut self) { } } // REJECT diff --git a/src/test/ui/specialization/defaultimpl/validation.rs b/src/test/ui/specialization/defaultimpl/validation.rs index 8558a1efb82f3..3b65caa7b4878 100644 --- a/src/test/ui/specialization/defaultimpl/validation.rs +++ b/src/test/ui/specialization/defaultimpl/validation.rs @@ -7,10 +7,10 @@ struct Z; 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 +default impl !Send for Z {} //~ ERROR `std::marker::Send` impl requires `Z: std::marker::Send` but + //~^ ERROR impls of auto traits cannot be default trait Tr {} -default impl !Tr for S {} //~ ERROR negative impls cannot be default impls +default impl !Tr for S {} //~ ERROR `Tr` impl requires `S: Tr` but fn main() {} diff --git a/src/test/ui/specialization/defaultimpl/validation.stderr b/src/test/ui/specialization/defaultimpl/validation.stderr index 2449849725f38..372660696a36e 100644 --- a/src/test/ui/specialization/defaultimpl/validation.stderr +++ b/src/test/ui/specialization/defaultimpl/validation.stderr @@ -33,18 +33,30 @@ LL | default impl !Send for Z {} | | | default because of this -error[E0750]: negative impls cannot be default impls +error[E0367]: `std::marker::Send` impl requires `Z: std::marker::Send` but the struct it is implemented for does not --> $DIR/validation.rs:10:1 | LL | default impl !Send for Z {} - | ^^^^^^^ ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/validation.rs:5:1 + | +LL | struct Z; + | ^^^^^^^^^ -error[E0750]: negative impls cannot be default impls +error[E0367]: `Tr` impl requires `S: Tr` but the struct it is implemented for does not --> $DIR/validation.rs:14:1 | LL | default impl !Tr for S {} - | ^^^^^^^ ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/validation.rs:4:1 + | +LL | struct S; + | ^^^^^^^^^ error: aborting due to 5 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0750`. +For more information about this error, try `rustc --explain E0367`. diff --git a/src/test/ui/traits/negative-impls/issue-74629.rs b/src/test/ui/traits/negative-impls/issue-74629.rs new file mode 100644 index 0000000000000..979cfb714cc70 --- /dev/null +++ b/src/test/ui/traits/negative-impls/issue-74629.rs @@ -0,0 +1,30 @@ +#![feature(negative_impls)] +#![feature(optin_builtin_traits)] +struct Nil; +struct Cons(H); +struct Test; + +trait Fold {} + +impl Fold for Cons // 0 +where + T: Fold, +{} + +impl Fold for Cons // 1 +where + T: Fold, + private::Is: private::NotNil, +{} + +impl Fold for Test {} // 2 + +mod private { + use crate::Nil; + + pub struct Is(T); + pub auto trait NotNil {} + impl !NotNil for Is {} //~ ERROR `private::NotNil` impls cannot +} + +fn main() {} diff --git a/src/test/ui/traits/negative-impls/issue-74629.stderr b/src/test/ui/traits/negative-impls/issue-74629.stderr new file mode 100644 index 0000000000000..622e1e2efb49c --- /dev/null +++ b/src/test/ui/traits/negative-impls/issue-74629.stderr @@ -0,0 +1,15 @@ +error[E0366]: `private::NotNil` impls cannot be specialized + --> $DIR/issue-74629.rs:27:5 + | +LL | impl !NotNil for Is {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: use the same sequence of generic type, lifetime and const parameters as the struct definition + --> $DIR/issue-74629.rs:25:5 + | +LL | pub struct Is(T); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0366`. diff --git a/src/test/ui/traits/negative-impls/negative-default-impls.rs b/src/test/ui/traits/negative-impls/negative-default-impls.rs index c68bca432fa86..a36b60956b140 100644 --- a/src/test/ui/traits/negative-impls/negative-default-impls.rs +++ b/src/test/ui/traits/negative-impls/negative-default-impls.rs @@ -6,6 +6,6 @@ trait MyTrait { type Foo; } -default impl !MyTrait for u32 {} //~ ERROR negative impls cannot be default impls +default impl !MyTrait for u32 {} //~ ERROR auto traits must not contain where bounds 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 index 50e74373b53bb..79874a4c82171 100644 --- a/src/test/ui/traits/negative-impls/negative-default-impls.stderr +++ b/src/test/ui/traits/negative-impls/negative-default-impls.stderr @@ -7,12 +7,11 @@ LL | #![feature(specialization)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 for more information -error[E0750]: negative impls cannot be default impls +error: auto traits must not contain where bounds --> $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/src/test/ui/traits/negative-impls/negative-impl-sized.rs b/src/test/ui/traits/negative-impls/negative-impl-sized.rs new file mode 100644 index 0000000000000..5b80e848d1230 --- /dev/null +++ b/src/test/ui/traits/negative-impls/negative-impl-sized.rs @@ -0,0 +1,9 @@ +#![feature(negative_impls)] + +// Test a negative impl for a trait requires `T: ?Sized`. + +trait MyTrait {} + +impl !MyTrait for T {} //~ ERROR auto traits must not contain where bounds + +fn main() {} diff --git a/src/test/ui/traits/negative-impls/negative-impl-sized.stderr b/src/test/ui/traits/negative-impls/negative-impl-sized.stderr new file mode 100644 index 0000000000000..3c0d559a6924a --- /dev/null +++ b/src/test/ui/traits/negative-impls/negative-impl-sized.stderr @@ -0,0 +1,8 @@ +error: auto traits must not contain where bounds + --> $DIR/negative-impl-sized.rs:7:1 + | +LL | impl !MyTrait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/traits/negative-impls/negative-specializes-negative.rs b/src/test/ui/traits/negative-impls/negative-specializes-negative.rs index 35297ab124ed0..a26b1496e1331 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-negative.rs +++ b/src/test/ui/traits/negative-impls/negative-specializes-negative.rs @@ -7,7 +7,7 @@ trait MyTrait {} -impl !MyTrait for T {} +impl !MyTrait for T {} impl !MyTrait for u32 {} fn main() {} From b718ac7884509c4b24117239fc0ee94386d3d105 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 27 Jul 2020 20:33:19 +0200 Subject: [PATCH 2/3] improve stuff --- src/librustc_typeck/check/dropck.rs | 99 ++++++++++++++++--- src/test/ui/issues/issue-29516.rs | 3 +- src/test/ui/issues/issue-29516.stderr | 2 +- src/test/ui/issues/issue-41974.rs | 3 +- src/test/ui/issues/issue-41974.stderr | 14 +-- .../negative-impls/negative-default-impls.rs | 3 +- .../negative-default-impls.stderr | 2 +- .../negative-impls/negative-impl-sized.rs | 5 +- .../negative-impls/negative-impl-sized.stderr | 2 +- 9 files changed, 94 insertions(+), 39 deletions(-) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index ca35e2a7841b6..fe1801b929c0c 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -34,10 +34,24 @@ use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorReported> { check_restricted_impl(tcx, drop_impl_did) } + pub fn check_restricted_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorReported> { let dtor_self_type = tcx.type_of(drop_impl_did); let dtor_predicates = tcx.predicates_of(drop_impl_did); - match dtor_self_type.kind { + + let check_empty_where_bounds = |s| { + if dtor_predicates.predicates.is_empty() { + Ok(()) + } else { + tcx.sess.span_err( + tcx.def_span(drop_impl_did), + &format!("negative impls on {} must not contain where bounds", s), + ); + Err(ErrorReported) + } + }; + + let kind_str = match dtor_self_type.kind { ty::Adt(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond( tcx, @@ -46,29 +60,82 @@ pub fn check_restricted_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<() adt_def.did, )?; - ensure_drop_predicates_are_implied_by_item_defn( + return ensure_drop_predicates_are_implied_by_item_defn( tcx, drop_impl_did.expect_local(), dtor_predicates, adt_def.did, self_to_impl_substs, - ) + ); } - _ => { + _ if tcx.lang_items().drop_trait() + == Some(tcx.impl_trait_ref(drop_impl_did).unwrap().def_id) => + { // Destructors only work on nominal types. This was - // already checked by coherence, for auto impls we - // simply check that there are no bounds here. - if dtor_predicates.predicates.is_empty() { - Ok(()) - } else { - tcx.sess.span_err( - tcx.def_span(drop_impl_did), - "auto traits must not contain where bounds", - ); - Err(ErrorReported) - } + // already checked by coherence, but compilation may + // not have been terminated. + tcx.sess.delay_span_bug( + tcx.def_span(drop_impl_did), + &format!("should have been rejected by coherence check: {}", dtor_self_type), + ); + return Err(ErrorReported); } - } + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => { + return check_empty_where_bounds("primitive types"); + } + ty::Foreign(_) => { + return check_empty_where_bounds("foreign types"); + } + ty::Array(..) => { + // FIXME: Support negative impls for `[T; N]` where `T: Sized` is the only predicate. + "arrays" + } + ty::Slice(..) => { + // FIXME: Support negative impls for `[T]` where `T: Sized` is the only predicate. + "slices" + } + ty::RawPtr(..) => { + return check_empty_where_bounds("raw pointers"); + } + ty::Ref(..) => { + return check_empty_where_bounds("references"); + } + ty::FnPtr(..) => { + // In case we ever get variadic functions allowing this would mean that we have + // specialized negative impls on stable. + "function pointers" + } + ty::Dynamic(..) => { + return check_empty_where_bounds("trait objects"); + } + ty::Never => { + return check_empty_where_bounds("`!`"); + } + ty::Tuple(..) => { + // In case we ever get variadic tuples allowing this would mean that we have + // specialized negative impls on stable. + "tuples" + } + ty::Projection(..) => "projections", + ty::Opaque(..) => "opaque types", + ty::Param(..) => { + return check_empty_where_bounds("type parameters"); + } + ty::Error(..) => return Ok(()), + ty::FnDef(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Infer(..) => bug!("unexpected impl self ty: {:?}", dtor_self_type), + }; + + tcx.sess.span_err( + tcx.def_span(drop_impl_did), + &format!("negative impls are not allowed for {}", kind_str), + ); + Err(ErrorReported) } fn ensure_drop_params_and_item_params_correspond<'tcx>( diff --git a/src/test/ui/issues/issue-29516.rs b/src/test/ui/issues/issue-29516.rs index b377dc4a40441..966bd21341b00 100644 --- a/src/test/ui/issues/issue-29516.rs +++ b/src/test/ui/issues/issue-29516.rs @@ -3,8 +3,7 @@ auto trait NotSame {} -impl !NotSame for (A, A) {} //~ ERROR auto traits must not contain where bounds -// FIXME: Consider allowing (A, B) with `A: Sized`. +impl !NotSame for (A, A) {} //~ ERROR negative impls are not allowed for tuples trait OneOfEach {} diff --git a/src/test/ui/issues/issue-29516.stderr b/src/test/ui/issues/issue-29516.stderr index fd6440da06af2..affa34b438e0c 100644 --- a/src/test/ui/issues/issue-29516.stderr +++ b/src/test/ui/issues/issue-29516.stderr @@ -1,4 +1,4 @@ -error: auto traits must not contain where bounds +error: negative impls are not allowed for tuples --> $DIR/issue-29516.rs:6:1 | LL | impl !NotSame for (A, A) {} diff --git a/src/test/ui/issues/issue-41974.rs b/src/test/ui/issues/issue-41974.rs index c1754a7e2ae3b..7a082bb08176a 100644 --- a/src/test/ui/issues/issue-41974.rs +++ b/src/test/ui/issues/issue-41974.rs @@ -4,8 +4,7 @@ struct Flags; trait A {} impl Drop for T where T: A { - //~^ ERROR auto traits must not contain where bounds - //~| ERROR E0119 + //~^ ERROR E0119 //~| ERROR E0120 //~| ERROR E0210 fn drop(&mut self) {} diff --git a/src/test/ui/issues/issue-41974.stderr b/src/test/ui/issues/issue-41974.stderr index 3afa1f3275ae7..accaaf1c2281f 100644 --- a/src/test/ui/issues/issue-41974.stderr +++ b/src/test/ui/issues/issue-41974.stderr @@ -15,18 +15,6 @@ error[E0120]: the `Drop` trait may only be implemented for structs, enums, and u LL | impl Drop for T where T: A { | ^ must be a struct, enum, or union -error: auto traits must not contain where bounds - --> $DIR/issue-41974.rs:6:1 - | -LL | / impl Drop for T where T: A { -LL | | -LL | | -LL | | -LL | | -LL | | fn drop(&mut self) {} -LL | | } - | |_^ - error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) --> $DIR/issue-41974.rs:6:6 | @@ -36,7 +24,7 @@ LL | impl Drop for T where T: A { = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local = note: only traits defined in the current crate can be implemented for a type parameter -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0119, E0120, E0210. For more information about an error, try `rustc --explain E0119`. diff --git a/src/test/ui/traits/negative-impls/negative-default-impls.rs b/src/test/ui/traits/negative-impls/negative-default-impls.rs index a36b60956b140..7c389a49bc6b7 100644 --- a/src/test/ui/traits/negative-impls/negative-default-impls.rs +++ b/src/test/ui/traits/negative-impls/negative-default-impls.rs @@ -6,6 +6,7 @@ trait MyTrait { type Foo; } -default impl !MyTrait for u32 {} //~ ERROR auto traits must not contain where bounds +default impl !MyTrait for u32 {} +//~^ ERROR negative impls on primitive types must not contain where bounds 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 index 79874a4c82171..178c2bae31f69 100644 --- a/src/test/ui/traits/negative-impls/negative-default-impls.stderr +++ b/src/test/ui/traits/negative-impls/negative-default-impls.stderr @@ -7,7 +7,7 @@ LL | #![feature(specialization)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 for more information -error: auto traits must not contain where bounds +error: negative impls on primitive types must not contain where bounds --> $DIR/negative-default-impls.rs:9:1 | LL | default impl !MyTrait for u32 {} diff --git a/src/test/ui/traits/negative-impls/negative-impl-sized.rs b/src/test/ui/traits/negative-impls/negative-impl-sized.rs index 5b80e848d1230..caa2477ec26be 100644 --- a/src/test/ui/traits/negative-impls/negative-impl-sized.rs +++ b/src/test/ui/traits/negative-impls/negative-impl-sized.rs @@ -1,9 +1,10 @@ #![feature(negative_impls)] -// Test a negative impl for a trait requires `T: ?Sized`. +// Test that negative impls for a trait requires `T: ?Sized`. trait MyTrait {} -impl !MyTrait for T {} //~ ERROR auto traits must not contain where bounds +impl !MyTrait for T {} +//~^ ERROR negative impls on type parameters must not contain where bounds fn main() {} diff --git a/src/test/ui/traits/negative-impls/negative-impl-sized.stderr b/src/test/ui/traits/negative-impls/negative-impl-sized.stderr index 3c0d559a6924a..f412bbff116d2 100644 --- a/src/test/ui/traits/negative-impls/negative-impl-sized.stderr +++ b/src/test/ui/traits/negative-impls/negative-impl-sized.stderr @@ -1,4 +1,4 @@ -error: auto traits must not contain where bounds +error: negative impls on type parameters must not contain where bounds --> $DIR/negative-impl-sized.rs:7:1 | LL | impl !MyTrait for T {} From e8e0601839f42f3cacded9ff2b1ceba8839b6ce5 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 27 Jul 2020 20:42:47 +0200 Subject: [PATCH 3/3] add note --- src/librustc_typeck/check/dropck.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index fe1801b929c0c..1906a9b2875b6 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -43,6 +43,10 @@ pub fn check_restricted_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<() if dtor_predicates.predicates.is_empty() { Ok(()) } else { + // FIXME(negative_impls): Improve the diagnostics for `T: Sized` here. + // + // In this case the problem is not that there are unexpected where bounds, + // but instead, that a parameter is missing `T: ?Sized`. tcx.sess.span_err( tcx.def_span(drop_impl_did), &format!("negative impls on {} must not contain where bounds", s),