From 5560b8c3e3f56f563fef9ed447b875e039f857ad Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 13 Jul 2019 18:02:00 +0300 Subject: [PATCH 1/7] reserve `impl From for T` this is necessary for never-type stabilization --- src/libcore/convert.rs | 6 +++++ src/librustc/traits/select.rs | 21 ++++++++++++---- src/librustc/ty/mod.rs | 28 ++++++++++++++-------- src/librustc_typeck/check/wfcheck.rs | 29 +++++++++++++---------- src/libsyntax/feature_gate.rs | 5 ++++ src/libsyntax_pos/symbol.rs | 1 + src/test/ui/never-impl-is-reserved.rs | 10 ++++++++ src/test/ui/never-impl-is-reserved.stderr | 17 +++++++++++++ 8 files changed, 91 insertions(+), 26 deletions(-) create mode 100644 src/test/ui/never-impl-is-reserved.rs create mode 100644 src/test/ui/never-impl-is-reserved.stderr diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 624b13d96472c..8d6055013ab79 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -551,6 +551,12 @@ impl From for T { fn from(t: T) -> T { t } } +#[stable(feature = "convert_infallible", since = "1.34.0")] +#[cfg(not(bootstrap))] +#[rustc_reservation_impl] +impl From for T { + fn from(t: !) -> T { t } +} // TryFrom implies TryInto #[stable(feature = "try_from", since = "1.34.0")] diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 2486f29ab0f22..2f99739d3c0cb 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -50,6 +50,8 @@ use std::iter; use std::rc::Rc; use crate::util::nodemap::{FxHashMap, FxHashSet}; +use syntax::symbol::sym; + pub struct SelectionContext<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, @@ -1325,8 +1327,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (result, dep_node) } - // Treat negative impls as unimplemented - fn filter_negative_impls( + // Treat negative impls as unimplemented, and reservation impls as Ok(None) + fn filter_negative_and_reservation_impls( &self, candidate: SelectionCandidate<'tcx>, ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { @@ -1336,6 +1338,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { return Err(Unimplemented); } + + if self.tcx().has_attr(def_id, sym::rustc_reservation_impl) { + return Ok(None); + } } Ok(Some(candidate)) } @@ -1452,7 +1458,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Instead, we select the right impl now but report `Bar does // not implement Clone`. if candidates.len() == 1 { - return self.filter_negative_impls(candidates.pop().unwrap()); + return self.filter_negative_and_reservation_impls(candidates.pop().unwrap()); } // Winnow, but record the exact outcome of evaluation, which @@ -1527,7 +1533,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // Just one candidate left. - self.filter_negative_impls(candidates.pop().unwrap().candidate) + self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate) } fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option { @@ -3727,6 +3733,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } + if self.intercrate.is_none() && + self.tcx().has_attr(impl_def_id, sym::rustc_reservation_impl) + { + debug!("match_impl: reservation impls only apply in intercrate mode"); + return Err(()); + } + debug!("match_impl: success impl_substs={:?}", impl_substs); Ok(Normalized { value: impl_substs, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8e170578227c0..c7cb58f144041 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2892,7 +2892,13 @@ impl<'tcx> TyCtxt<'tcx> { pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> Option { - let is_legit = if self.features().overlapping_marker_traits { + if self.impl_polarity(def_id1) != self.impl_polarity(def_id2) { + debug!("impls_are_allowed_to_overlap({:?}, {:?}) - different polarities, None", + def_id1, def_id2); + return None; + } + + let is_marker_overlap = if self.features().overlapping_marker_traits { let trait1_is_empty = self.impl_trait_ref(def_id1) .map_or(false, |trait_ref| { self.associated_item_def_ids(trait_ref.def_id).is_empty() @@ -2901,22 +2907,24 @@ impl<'tcx> TyCtxt<'tcx> { .map_or(false, |trait_ref| { self.associated_item_def_ids(trait_ref.def_id).is_empty() }); - self.impl_polarity(def_id1) == self.impl_polarity(def_id2) - && trait1_is_empty - && trait2_is_empty + trait1_is_empty && trait2_is_empty } else { let is_marker_impl = |def_id: DefId| -> bool { let trait_ref = self.impl_trait_ref(def_id); trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker) }; - self.impl_polarity(def_id1) == self.impl_polarity(def_id2) - && is_marker_impl(def_id1) - && is_marker_impl(def_id2) + is_marker_impl(def_id1) && is_marker_impl(def_id2) }; - if is_legit { - debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted)", - def_id1, def_id2); + // `#[rustc_reservation_impl]` impls don't overlap with anything + let is_reserve_overlap = { + self.has_attr(def_id1, sym::rustc_reservation_impl) || + self.has_attr(def_id2, sym::rustc_reservation_impl) + }; + + if is_marker_overlap || is_reserve_overlap { + debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) ({:?}/{:?})", + def_id1, def_id2, is_marker_overlap, is_reserve_overlap); Some(ImplOverlapKind::Permitted) } else { if let Some(self_ty1) = self.issue33140_self_ty(def_id1) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index c1d8fde3be15b..da0688ac28916 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -399,18 +399,23 @@ fn check_impl<'tcx>( match *ast_trait_ref { Some(ref ast_trait_ref) => { - let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap(); - let trait_ref = - fcx.normalize_associated_types_in( - ast_trait_ref.path.span, &trait_ref); - let obligations = - ty::wf::trait_obligations(fcx, - fcx.param_env, - fcx.body_id, - &trait_ref, - ast_trait_ref.path.span); - for obligation in obligations { - fcx.register_predicate(obligation); + // `#[rustc_reservation_impl]` impls are not real impls and + // therefore don't need to be WF (the trait's `Self: Trait` predicate + // won't hold). + if !fcx.tcx.has_attr(item_def_id, sym::rustc_reservation_impl) { + let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap(); + let trait_ref = + fcx.normalize_associated_types_in( + ast_trait_ref.path.span, &trait_ref); + let obligations = + ty::wf::trait_obligations(fcx, + fcx.param_env, + fcx.body_id, + &trait_ref, + ast_trait_ref.path.span); + for obligation in obligations { + fcx.register_predicate(obligation); + } } } None => { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 33d10b269e1e3..68c2749a73b24 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1276,6 +1276,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ attribute is just used for rustc unit \ tests and will never be stable", cfg_fn!(rustc_attrs))), + (sym::rustc_reservation_impl, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, + "internal rustc attributes \ + will never be stable", + cfg_fn!(rustc_attrs))), (sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable, sym::rustc_attrs, "the `#[rustc_test_marker]` attribute \ diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 12c4ba059feb6..6c74aca0e2a53 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -602,6 +602,7 @@ symbols! { rustc_std_internal_symbol, rustc_symbol_name, rustc_synthetic, + rustc_reservation_impl, rustc_test_marker, rustc_then_this_would_need, rustc_variance, diff --git a/src/test/ui/never-impl-is-reserved.rs b/src/test/ui/never-impl-is-reserved.rs new file mode 100644 index 0000000000000..0df0843a88d0d --- /dev/null +++ b/src/test/ui/never-impl-is-reserved.rs @@ -0,0 +1,10 @@ +// check that the `for T: From` impl is reserved + +#![feature(never_type)] + +pub struct MyFoo; +pub trait MyTrait {} + +impl MyTrait for MyFoo {} +// This will conflict with the first impl if we impl `for T: From`. +impl MyTrait for T where T: From {} //~ ERROR conflicting implementation diff --git a/src/test/ui/never-impl-is-reserved.stderr b/src/test/ui/never-impl-is-reserved.stderr new file mode 100644 index 0000000000000..c2a1c60b09416 --- /dev/null +++ b/src/test/ui/never-impl-is-reserved.stderr @@ -0,0 +1,17 @@ +error[E0601]: `main` function not found in crate `never_impl_is_reserved` + | + = note: consider adding a `main` function to `$DIR/never-impl-is-reserved.rs` + +error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo`: + --> $DIR/never-impl-is-reserved.rs:10:1 + | +LL | impl MyTrait for MyFoo {} + | ---------------------- first implementation here +LL | // This will conflict with the first impl if we impl `for T: From`. +LL | impl MyTrait for T where T: From {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0119, E0601. +For more information about an error, try `rustc --explain E0119`. From f358152d88823b438cac41001ffe56077deba36f Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 13 Jul 2019 22:52:57 +0300 Subject: [PATCH 2/7] improve and add tests --- ...rved.rs => never-from-impl-is-reserved.rs} | 2 ++ ...err => never-from-impl-is-reserved.stderr} | 11 ++------ .../reservation-impl-coherence-conflict.rs | 16 +++++++++++ ...reservation-impl-coherence-conflict.stderr | 11 ++++++++ .../reservation-impl-no-use.rs | 14 ++++++++++ .../reservation-impl-no-use.stderr | 17 +++++++++++ .../reservation-impls/reservation-impl-ok.rs | 28 +++++++++++++++++++ 7 files changed, 91 insertions(+), 8 deletions(-) rename src/test/ui/{never-impl-is-reserved.rs => never-from-impl-is-reserved.rs} (95%) rename src/test/ui/{never-impl-is-reserved.stderr => never-from-impl-is-reserved.stderr} (51%) create mode 100644 src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs create mode 100644 src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.stderr create mode 100644 src/test/ui/traits/reservation-impls/reservation-impl-no-use.rs create mode 100644 src/test/ui/traits/reservation-impls/reservation-impl-no-use.stderr create mode 100644 src/test/ui/traits/reservation-impls/reservation-impl-ok.rs diff --git a/src/test/ui/never-impl-is-reserved.rs b/src/test/ui/never-from-impl-is-reserved.rs similarity index 95% rename from src/test/ui/never-impl-is-reserved.rs rename to src/test/ui/never-from-impl-is-reserved.rs index 0df0843a88d0d..9d16015bdc129 100644 --- a/src/test/ui/never-impl-is-reserved.rs +++ b/src/test/ui/never-from-impl-is-reserved.rs @@ -8,3 +8,5 @@ pub trait MyTrait {} impl MyTrait for MyFoo {} // This will conflict with the first impl if we impl `for T: From`. impl MyTrait for T where T: From {} //~ ERROR conflicting implementation + +fn main() {} diff --git a/src/test/ui/never-impl-is-reserved.stderr b/src/test/ui/never-from-impl-is-reserved.stderr similarity index 51% rename from src/test/ui/never-impl-is-reserved.stderr rename to src/test/ui/never-from-impl-is-reserved.stderr index c2a1c60b09416..7e9b21a542933 100644 --- a/src/test/ui/never-impl-is-reserved.stderr +++ b/src/test/ui/never-from-impl-is-reserved.stderr @@ -1,9 +1,5 @@ -error[E0601]: `main` function not found in crate `never_impl_is_reserved` - | - = note: consider adding a `main` function to `$DIR/never-impl-is-reserved.rs` - error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo`: - --> $DIR/never-impl-is-reserved.rs:10:1 + --> $DIR/never-from-impl-is-reserved.rs:10:1 | LL | impl MyTrait for MyFoo {} | ---------------------- first implementation here @@ -11,7 +7,6 @@ LL | // This will conflict with the first impl if we impl `for T: From`. LL | impl MyTrait for T where T: From {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo` -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0119, E0601. -For more information about an error, try `rustc --explain E0119`. +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs b/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs new file mode 100644 index 0000000000000..1a5266f5583d6 --- /dev/null +++ b/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs @@ -0,0 +1,16 @@ +// compile-fail + +// check that reservation impls are accounted for in negative reasoning. + +#![feature(rustc_attrs)] + +trait MyTrait {} +#[rustc_reservation_impl] +impl MyTrait for () {} + +trait OtherTrait {} +impl OtherTrait for () {} +impl OtherTrait for T {} +//~^ ERROR conflicting implementations + +fn main() {} diff --git a/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.stderr b/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.stderr new file mode 100644 index 0000000000000..7b88d2b42db1b --- /dev/null +++ b/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `OtherTrait` for type `()`: + --> $DIR/reservation-impl-coherence-conflict.rs:13:1 + | +LL | impl OtherTrait for () {} + | ---------------------- first implementation here +LL | impl OtherTrait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/traits/reservation-impls/reservation-impl-no-use.rs b/src/test/ui/traits/reservation-impls/reservation-impl-no-use.rs new file mode 100644 index 0000000000000..f08338bdc1c91 --- /dev/null +++ b/src/test/ui/traits/reservation-impls/reservation-impl-no-use.rs @@ -0,0 +1,14 @@ +// compile-fail + +// check that reservation impls can't be used as normal impls in positive reasoning. + +#![feature(rustc_attrs)] + +trait MyTrait { fn foo(&self); } +#[rustc_reservation_impl] +impl MyTrait for () { fn foo(&self) {} } + +fn main() { + <() as MyTrait>::foo(&()); + //~^ ERROR the trait bound `(): MyTrait` is not satisfied +} diff --git a/src/test/ui/traits/reservation-impls/reservation-impl-no-use.stderr b/src/test/ui/traits/reservation-impls/reservation-impl-no-use.stderr new file mode 100644 index 0000000000000..8ac4eece62e4d --- /dev/null +++ b/src/test/ui/traits/reservation-impls/reservation-impl-no-use.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `(): MyTrait` is not satisfied + --> $DIR/reservation-impl-no-use.rs:12:5 + | +LL | <() as MyTrait>::foo(&()); + | ^^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `()` + | + = help: the following implementations were found: + <() as MyTrait> +note: required by `MyTrait::foo` + --> $DIR/reservation-impl-no-use.rs:7:17 + | +LL | trait MyTrait { fn foo(&self); } + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/reservation-impls/reservation-impl-ok.rs b/src/test/ui/traits/reservation-impls/reservation-impl-ok.rs new file mode 100644 index 0000000000000..febd14b792297 --- /dev/null +++ b/src/test/ui/traits/reservation-impls/reservation-impl-ok.rs @@ -0,0 +1,28 @@ +// run-pass + +// rpass test for reservation impls. Not 100% required because `From` uses them, +// but still. + +#![feature(rustc_attrs)] + +use std::mem; + +trait MyTrait { + fn foo(&self, s: S) -> usize; +} + +#[rustc_reservation_impl] +impl MyTrait for T { + fn foo(&self, _x: u64) -> usize { 0 } +} + +// reservation impls don't create coherence conflicts, even with +// non-chain overlap. +impl MyTrait for u32 { + fn foo(&self, _x: S) -> usize { mem::size_of::() } +} + +fn main() { + // ...and the non-reservation impl gets picked.XS + assert_eq!(0u32.foo(0u64), mem::size_of::()); +} From ed6db362bffc46f0032266dda684afa15e39e07b Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 14 Jul 2019 00:09:46 +0300 Subject: [PATCH 3/7] resolve the rustc_reservation_impl attribute in 1 place --- src/librustc/query/mod.rs | 2 +- src/librustc/traits/auto_trait.rs | 2 +- src/librustc/traits/select.rs | 24 ++++++------- src/librustc/ty/mod.rs | 46 ++++++++++++++++-------- src/librustc_metadata/decoder.rs | 2 +- src/librustc_metadata/encoder.rs | 3 +- src/librustc_metadata/schema.rs | 2 +- src/librustc_traits/lowering/mod.rs | 5 +-- src/librustc_typeck/check/wfcheck.rs | 53 +++++++++++++++------------- src/librustc_typeck/collect.rs | 26 ++++++++++++-- src/librustdoc/clean/mod.rs | 13 ++++--- 11 files changed, 112 insertions(+), 66 deletions(-) diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 67fc3520745dd..544750b6f4bbe 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -273,7 +273,7 @@ rustc_queries! { query associated_item(_: DefId) -> ty::AssocItem {} query impl_trait_ref(_: DefId) -> Option> {} - query impl_polarity(_: DefId) -> hir::ImplPolarity {} + query impl_polarity(_: DefId) -> ty::ImplPolarity {} query issue33140_self_ty(_: DefId) -> Option> {} } diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index d89cf8eb3e843..c481943e25e37 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -321,7 +321,7 @@ impl AutoTraitFinder<'tcx> { match vtable { Vtable::VtableImpl(VtableImplData { impl_def_id, .. }) => { // Blame tidy for the weird bracket placement - if infcx.tcx.impl_polarity(*impl_def_id) == hir::ImplPolarity::Negative + if infcx.tcx.impl_polarity(*impl_def_id) == ty::ImplPolarity::Negative { debug!("evaluate_nested_obligations: Found explicit negative impl\ {:?}, bailing out", impl_def_id); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 2f99739d3c0cb..96222e00cc948 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -50,8 +50,6 @@ use std::iter; use std::rc::Rc; use crate::util::nodemap::{FxHashMap, FxHashSet}; -use syntax::symbol::sym; - pub struct SelectionContext<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, @@ -1333,15 +1331,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate: SelectionCandidate<'tcx>, ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { if let ImplCandidate(def_id) = candidate { - if !self.allow_negative_impls - && self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative - { - return Err(Unimplemented); - } - - if self.tcx().has_attr(def_id, sym::rustc_reservation_impl) { - return Ok(None); - } + match self.tcx().impl_polarity(def_id) { + ty::ImplPolarity::Negative if !self.allow_negative_impls => { + return Err(Unimplemented); + } + ty::ImplPolarity::Reservation => { + return Ok(None); + } + _ => {} + }; } Ok(Some(candidate)) } @@ -3733,8 +3731,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - if self.intercrate.is_none() && - self.tcx().has_attr(impl_def_id, sym::rustc_reservation_impl) + if self.intercrate.is_none() + && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation { debug!("match_impl: reservation impls only apply in intercrate mode"); return Err(()); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c7cb58f144041..19498e02a4239 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -166,6 +166,16 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec>, } +#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] +pub enum ImplPolarity { + /// `impl Trait for Type` + Positive, + /// `impl !Trait for Type` + Negative, + /// `#[rustc_reservation_impl] impl Trait for Type` + Reservation, +} + #[derive(Copy, Clone, Debug, PartialEq, HashStable)] pub struct AssocItem { pub def_id: DefId, @@ -2892,11 +2902,24 @@ impl<'tcx> TyCtxt<'tcx> { pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> Option { - if self.impl_polarity(def_id1) != self.impl_polarity(def_id2) { - debug!("impls_are_allowed_to_overlap({:?}, {:?}) - different polarities, None", - def_id1, def_id2); - return None; - } + match (self.impl_polarity(def_id1), self.impl_polarity(def_id2)) { + (ImplPolarity::Reservation, _) | + (_, ImplPolarity::Reservation) => { + // `#[rustc_reservation_impl]` impls don't overlap with anything + debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (reservations)", + def_id1, def_id2); + return Some(ImplOverlapKind::Permitted); + } + (ImplPolarity::Positive, ImplPolarity::Negative) | + (ImplPolarity::Negative, ImplPolarity::Positive) => { + // FIXME: when can this happen? + debug!("impls_are_allowed_to_overlap({:?}, {:?}) - None (differing polarities)", + def_id1, def_id2); + return None; + } + (ImplPolarity::Positive, ImplPolarity::Positive) | + (ImplPolarity::Negative, ImplPolarity::Negative) => {} + }; let is_marker_overlap = if self.features().overlapping_marker_traits { let trait1_is_empty = self.impl_trait_ref(def_id1) @@ -2916,15 +2939,10 @@ impl<'tcx> TyCtxt<'tcx> { is_marker_impl(def_id1) && is_marker_impl(def_id2) }; - // `#[rustc_reservation_impl]` impls don't overlap with anything - let is_reserve_overlap = { - self.has_attr(def_id1, sym::rustc_reservation_impl) || - self.has_attr(def_id2, sym::rustc_reservation_impl) - }; - if is_marker_overlap || is_reserve_overlap { - debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) ({:?}/{:?})", - def_id1, def_id2, is_marker_overlap, is_reserve_overlap); + if is_marker_overlap { + debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) (marker overlap)", + def_id1, def_id2); Some(ImplOverlapKind::Permitted) } else { if let Some(self_ty1) = self.issue33140_self_ty(def_id1) { @@ -3306,7 +3324,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref); let is_marker_like = - tcx.impl_polarity(def_id) == hir::ImplPolarity::Positive && + tcx.impl_polarity(def_id) == ty::ImplPolarity::Positive && tcx.associated_item_def_ids(trait_ref.def_id).is_empty(); // Check whether these impls would be ok for a marker trait. diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 335ce86889413..2d4bce5e1d77d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -686,7 +686,7 @@ impl<'a, 'tcx> CrateMetadata { self.get_impl_data(id).parent_impl } - pub fn get_impl_polarity(&self, id: DefIndex) -> hir::ImplPolarity { + pub fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity { self.get_impl_data(id).polarity } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 28252117dd294..3d5dbb9b7e161 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1126,8 +1126,9 @@ impl EncodeContext<'tcx> { ctor_sig: None, }), repr_options) } - hir::ItemKind::Impl(_, polarity, defaultness, ..) => { + hir::ItemKind::Impl(_, _, defaultness, ..) => { let trait_ref = tcx.impl_trait_ref(def_id); + let polarity = tcx.impl_polarity(def_id); let parent = if let Some(trait_ref) = trait_ref { let trait_def = tcx.trait_def(trait_ref.def_id); trait_def.ancestors(tcx, def_id).nth(1).and_then(|node| { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index c0ac69159330e..841891ad05a6c 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -317,7 +317,7 @@ pub struct TraitAliasData<'tcx> { #[derive(RustcEncodable, RustcDecodable)] pub struct ImplData<'tcx> { - pub polarity: hir::ImplPolarity, + pub polarity: ty::ImplPolarity, pub defaultness: hir::Defaultness, pub parent_impl: Option, diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index 1558ce1bced52..51d49f0d59ae7 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -4,7 +4,7 @@ use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::map::definitions::DefPathData; -use rustc::hir::{self, ImplPolarity}; +use rustc::hir; use rustc::traits::{ Clause, Clauses, @@ -295,7 +295,8 @@ fn program_clauses_for_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> { } fn program_clauses_for_impl(tcx: TyCtxt<'tcx>, def_id: DefId) -> Clauses<'tcx> { - if let ImplPolarity::Negative = tcx.impl_polarity(def_id) { + // FIXME: implement reservation impls. + if let ty::ImplPolarity::Negative = tcx.impl_polarity(def_id) { return List::empty(); } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index da0688ac28916..8fdd9ea967db4 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -94,20 +94,27 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: DefId) { // // won't be allowed unless there's an *explicit* implementation of `Send` // for `T` - hir::ItemKind::Impl(_, polarity, defaultness, _, ref trait_ref, ref self_ty, _) => { + hir::ItemKind::Impl(_, _, defaultness, _, ref trait_ref, ref self_ty, _) => { let is_auto = tcx.impl_trait_ref(tcx.hir().local_def_id(item.hir_id)) - .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id)); + .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id)); + let polarity = tcx.impl_polarity(def_id); if let (hir::Defaultness::Default { .. }, true) = (defaultness, is_auto) { tcx.sess.span_err(item.span, "impls of auto traits cannot be default"); } - if polarity == hir::ImplPolarity::Positive { - check_impl(tcx, item, self_ty, trait_ref); - } else { - // FIXME(#27579): what amount of WF checking do we need for neg impls? - if trait_ref.is_some() && !is_auto { - span_err!(tcx.sess, item.span, E0192, - "negative impls are only allowed for \ - auto traits (e.g., `Send` and `Sync`)") + match polarity { + ty::ImplPolarity::Positive => { + check_impl(tcx, item, self_ty, trait_ref); + } + ty::ImplPolarity::Negative => { + // FIXME(#27579): what amount of WF checking do we need for neg impls? + if trait_ref.is_some() && !is_auto { + span_err!(tcx.sess, item.span, E0192, + "negative impls are only allowed for \ + auto traits (e.g., `Send` and `Sync`)") + } + } + ty::ImplPolarity::Reservation => { + // FIXME: what amount of WF checking do we need for reservation impls? } } } @@ -402,20 +409,18 @@ fn check_impl<'tcx>( // `#[rustc_reservation_impl]` impls are not real impls and // therefore don't need to be WF (the trait's `Self: Trait` predicate // won't hold). - if !fcx.tcx.has_attr(item_def_id, sym::rustc_reservation_impl) { - let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap(); - let trait_ref = - fcx.normalize_associated_types_in( - ast_trait_ref.path.span, &trait_ref); - let obligations = - ty::wf::trait_obligations(fcx, - fcx.param_env, - fcx.body_id, - &trait_ref, - ast_trait_ref.path.span); - for obligation in obligations { - fcx.register_predicate(obligation); - } + let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap(); + let trait_ref = + fcx.normalize_associated_types_in( + ast_trait_ref.path.span, &trait_ref); + let obligations = + ty::wf::trait_obligations(fcx, + fcx.param_env, + fcx.body_id, + &trait_ref, + ast_trait_ref.path.span); + for obligation in obligations { + fcx.register_predicate(obligation); } } None => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 15687eaa943e1..58a56a4ea6154 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1863,10 +1863,30 @@ fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { } } -fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> hir::ImplPolarity { +fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - match tcx.hir().expect_item(hir_id).node { - hir::ItemKind::Impl(_, polarity, ..) => polarity, + let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl); + let item = tcx.hir().expect_item(hir_id); + match &item.node { + hir::ItemKind::Impl(_, hir::ImplPolarity::Negative, ..) => { + if is_rustc_reservation { + tcx.sess.span_err(item.span, "reservation impls can't be negative"); + } + ty::ImplPolarity::Negative + } + hir::ItemKind::Impl(_, hir::ImplPolarity::Positive, _, _, None, _, _) => { + if is_rustc_reservation { + tcx.sess.span_err(item.span, "reservation impls can't be inherent"); + } + ty::ImplPolarity::Positive + } + hir::ItemKind::Impl(_, hir::ImplPolarity::Positive, _, _, Some(_tr), _, _) => { + if is_rustc_reservation { + ty::ImplPolarity::Reservation + } else { + ty::ImplPolarity::Positive + } + } ref item => bug!("impl_polarity: {:?} not an impl", item), } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a41b12e29b055..9af3c705b1ddb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3768,11 +3768,13 @@ pub enum ImplPolarity { Negative, } -impl Clean for hir::ImplPolarity { +impl Clean for ty::ImplPolarity { fn clean(&self, _: &DocContext<'_>) -> ImplPolarity { match self { - &hir::ImplPolarity::Positive => ImplPolarity::Positive, - &hir::ImplPolarity::Negative => ImplPolarity::Negative, + &ty::ImplPolarity::Positive | + // FIXME: do we want to do something else here? + &ty::ImplPolarity::Reservation => ImplPolarity::Positive, + &ty::ImplPolarity::Negative => ImplPolarity::Negative, } } } @@ -3804,6 +3806,7 @@ impl Clean> for doctree::Impl<'_> { let mut ret = Vec::new(); let trait_ = self.trait_.clean(cx); let items = self.items.iter().map(|ii| ii.clean(cx)).collect::>(); + let def_id = cx.tcx.hir().local_def_id(self.id); // If this impl block is an implementation of the Deref trait, then we // need to try inlining the target's inherent impl blocks as well. @@ -3822,7 +3825,7 @@ impl Clean> for doctree::Impl<'_> { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id), + def_id, visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), @@ -3833,7 +3836,7 @@ impl Clean> for doctree::Impl<'_> { trait_, for_: self.for_.clean(cx), items, - polarity: Some(self.polarity.clean(cx)), + polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)), synthetic: false, blanket_impl: None, }) From 49cf2a298d80f11f606f69afead74a8fe006e91d Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 27 Jul 2019 20:40:44 +0300 Subject: [PATCH 4/7] [for crater run] make core::convert::Infallible be ! --- src/libcore/convert.rs | 115 ++--------------------------------------- src/libcore/num/mod.rs | 9 +--- src/libstd/error.rs | 7 --- 3 files changed, 4 insertions(+), 127 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 8d6055013ab79..4c51b558a325b 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -40,8 +40,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::fmt; - /// An identity function. /// /// Two things are important to note about this function: @@ -426,9 +424,7 @@ pub trait TryInto: Sized { /// - `TryFrom for U` implies [`TryInto`]` for T` /// - [`try_from`] is reflexive, which means that `TryFrom for T` /// is implemented and cannot fail -- the associated `Error` type for -/// calling `T::try_from()` on a value of type `T` is [`Infallible`]. -/// When the [`!`] type is stabilized [`Infallible`] and [`!`] will be -/// equivalent. +/// calling `T::try_from()` on a value of type `T` is [`!`]. /// /// `TryFrom` can be implemented as follows: /// @@ -477,7 +473,6 @@ pub trait TryInto: Sized { /// [`TryInto`]: trait.TryInto.html /// [`i32::MAX`]: ../../std/i32/constant.MAX.html /// [`!`]: ../../std/primitive.never.html -/// [`Infallible`]: enum.Infallible.html #[stable(feature = "try_from", since = "1.34.0")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. @@ -610,110 +605,6 @@ impl AsRef for str { // THE NO-ERROR ERROR TYPE //////////////////////////////////////////////////////////////////////////////// -/// The error type for errors that can never happen. -/// -/// Since this enum has no variant, a value of this type can never actually exist. -/// This can be useful for generic APIs that use [`Result`] and parameterize the error type, -/// to indicate that the result is always [`Ok`]. -/// -/// For example, the [`TryFrom`] trait (conversion that returns a [`Result`]) -/// has a blanket implementation for all types where a reverse [`Into`] implementation exists. -/// -/// ```ignore (illustrates std code, duplicating the impl in a doctest would be an error) -/// impl TryFrom for T where U: Into { -/// type Error = Infallible; -/// -/// fn try_from(value: U) -> Result { -/// Ok(U::into(value)) // Never returns `Err` -/// } -/// } -/// ``` -/// -/// # Future compatibility -/// -/// This enum has the same role as [the `!` “never” type][never], -/// which is unstable in this version of Rust. -/// When `!` is stabilized, we plan to make `Infallible` a type alias to it: -/// -/// ```ignore (illustrates future std change) -/// pub type Infallible = !; -/// ``` -/// -/// … and eventually deprecate `Infallible`. -/// -/// -/// However there is one case where `!` syntax can be used -/// before `!` is stabilized as a full-fleged type: in the position of a function’s return type. -/// Specifically, it is possible implementations for two different function pointer types: -/// -/// ``` -/// trait MyTrait {} -/// impl MyTrait for fn() -> ! {} -/// impl MyTrait for fn() -> std::convert::Infallible {} -/// ``` -/// -/// With `Infallible` being an enum, this code is valid. -/// However when `Infallible` becomes an alias for the never type, -/// the two `impl`s will start to overlap -/// and therefore will be disallowed by the language’s trait coherence rules. -/// -/// [`Ok`]: ../result/enum.Result.html#variant.Ok -/// [`Result`]: ../result/enum.Result.html -/// [`TryFrom`]: trait.TryFrom.html -/// [`Into`]: trait.Into.html -/// [never]: ../../std/primitive.never.html -#[stable(feature = "convert_infallible", since = "1.34.0")] -#[derive(Copy)] -pub enum Infallible {} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl Clone for Infallible { - fn clone(&self) -> Infallible { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl fmt::Debug for Infallible { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl fmt::Display for Infallible { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl PartialEq for Infallible { - fn eq(&self, _: &Infallible) -> bool { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl Eq for Infallible {} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl PartialOrd for Infallible { - fn partial_cmp(&self, _other: &Self) -> Option { - match *self {} - } -} - +/// Blah Blah Blah #[stable(feature = "convert_infallible", since = "1.34.0")] -impl Ord for Infallible { - fn cmp(&self, _other: &Self) -> crate::cmp::Ordering { - match *self {} - } -} - -#[stable(feature = "convert_infallible", since = "1.34.0")] -impl From for Infallible { - fn from(x: !) -> Self { - x - } -} +pub type Infallible = !; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 67e30e7ffcb24..eb048dd002837 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4,7 +4,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::convert::{TryFrom, Infallible}; +use crate::convert::{TryFrom}; use crate::fmt; use crate::intrinsics; use crate::mem; @@ -4674,13 +4674,6 @@ impl fmt::Display for TryFromIntError { } } -#[stable(feature = "try_from", since = "1.34.0")] -impl From for TryFromIntError { - fn from(x: Infallible) -> TryFromIntError { - match x {} - } -} - #[unstable(feature = "never_type", issue = "35121")] impl From for TryFromIntError { fn from(never: !) -> TryFromIntError { diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 117a430eec6b9..16f5f117cb3aa 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -536,13 +536,6 @@ impl Error for string::FromUtf16Error { } } -#[stable(feature = "str_parse_error2", since = "1.8.0")] -impl Error for string::ParseError { - fn description(&self) -> &str { - match *self {} - } -} - #[stable(feature = "decode_utf16", since = "1.9.0")] impl Error for char::DecodeUtf16Error { fn description(&self) -> &str { From 2686a9014aa1ac018d3ab8a09c4505296bafbe98 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 27 Jul 2019 20:44:14 +0300 Subject: [PATCH 5/7] improve comments --- src/librustc/traits/select.rs | 2 +- src/librustc/ty/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 96222e00cc948..7cc8f1b2b414b 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1325,7 +1325,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { (result, dep_node) } - // Treat negative impls as unimplemented, and reservation impls as Ok(None) + // Treat negative impls as unimplemented, and reservation impls as ambiguity. fn filter_negative_and_reservation_impls( &self, candidate: SelectionCandidate<'tcx>, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 19498e02a4239..6b81916158fd3 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2912,7 +2912,7 @@ impl<'tcx> TyCtxt<'tcx> { } (ImplPolarity::Positive, ImplPolarity::Negative) | (ImplPolarity::Negative, ImplPolarity::Positive) => { - // FIXME: when can this happen? + // `impl AutoTrait for Type` + `impl !AutoTrait for Type` debug!("impls_are_allowed_to_overlap({:?}, {:?}) - None (differing polarities)", def_id1, def_id2); return None; From 595c2e63487520a794b8ebcafbe2b6ee99005762 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 27 Jul 2019 22:18:34 +0300 Subject: [PATCH 6/7] add error message for case --- src/libcore/convert.rs | 7 ++++- src/librustc/traits/select.rs | 31 +++++++++++++++++-- src/libsyntax/feature_gate.rs | 11 ++++--- .../ui/never-from-impl-is-reserved.stderr | 2 ++ .../reservation-impl-coherence-conflict.rs | 2 +- ...reservation-impl-coherence-conflict.stderr | 2 ++ .../reservation-impl-no-use.rs | 2 +- .../reservation-impls/reservation-impl-ok.rs | 2 +- 8 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 4c51b558a325b..20da15ea12e31 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -548,7 +548,12 @@ impl From for T { #[stable(feature = "convert_infallible", since = "1.34.0")] #[cfg(not(bootstrap))] -#[rustc_reservation_impl] +#[rustc_reservation_impl="a future version of Rust might implement `From` for \ + all types. \ + However, it is OK to implement `From` for types you own - \ + when the blanket impl will be added, coherence will be changed \ + to make these impls not be an error." +] impl From for T { fn from(t: !) -> T { t } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 7cc8f1b2b414b..1067343b46a09 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -43,6 +43,8 @@ use crate::hir; use rustc_data_structures::bit_set::GrowableBitSet; use rustc_data_structures::sync::Lock; use rustc_target::spec::abi::Abi; +use syntax::attr; +use syntax::symbol::sym; use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt::{self, Display}; @@ -99,6 +101,9 @@ pub enum IntercrateAmbiguityCause { trait_desc: String, self_desc: Option, }, + ReservationImpl { + message: String + }, } impl IntercrateAmbiguityCause { @@ -139,6 +144,11 @@ impl IntercrateAmbiguityCause { trait_desc, self_desc ) } + &IntercrateAmbiguityCause::ReservationImpl { + ref message + } => { + message.clone() + } } } } @@ -1327,15 +1337,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Treat negative impls as unimplemented, and reservation impls as ambiguity. fn filter_negative_and_reservation_impls( - &self, + &mut self, candidate: SelectionCandidate<'tcx>, ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { if let ImplCandidate(def_id) = candidate { - match self.tcx().impl_polarity(def_id) { + let tcx = self.tcx(); + match tcx.impl_polarity(def_id) { ty::ImplPolarity::Negative if !self.allow_negative_impls => { return Err(Unimplemented); } ty::ImplPolarity::Reservation => { + if let Some(intercrate_ambiguity_clauses) + = &mut self.intercrate_ambiguity_causes + { + let attrs = tcx.get_attrs(def_id); + let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl); + let value = attr.and_then(|a| a.value_str()); + if let Some(value) = value { + debug!("filter_negative_and_reservation_impls: \ + reservation impl ambiguity on {:?}", def_id); + intercrate_ambiguity_clauses.push( + IntercrateAmbiguityCause::ReservationImpl { + message: value.to_string() + } + ); + } + } return Ok(None); } _ => {} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 68c2749a73b24..6412b6af84b12 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1276,11 +1276,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ attribute is just used for rustc unit \ tests and will never be stable", cfg_fn!(rustc_attrs))), - (sym::rustc_reservation_impl, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal rustc attributes \ - will never be stable", - cfg_fn!(rustc_attrs))), + (sym::rustc_reservation_impl, Normal, template!(NameValueStr: "reservation message"), + Gated(Stability::Unstable, + sym::rustc_attrs, + "internal rustc attributes \ + will never be stable", + cfg_fn!(rustc_attrs))), (sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable, sym::rustc_attrs, "the `#[rustc_test_marker]` attribute \ diff --git a/src/test/ui/never-from-impl-is-reserved.stderr b/src/test/ui/never-from-impl-is-reserved.stderr index 7e9b21a542933..352fed7ca4515 100644 --- a/src/test/ui/never-from-impl-is-reserved.stderr +++ b/src/test/ui/never-from-impl-is-reserved.stderr @@ -6,6 +6,8 @@ LL | impl MyTrait for MyFoo {} LL | // This will conflict with the first impl if we impl `for T: From`. LL | impl MyTrait for T where T: From {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo` + | + = note: a future version of Rust might implement `From` for all types. However, it is OK to implement `From` for types you own - when the blanket impl will be added, coherence will be changed to make these impls not be an error. error: aborting due to previous error diff --git a/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs b/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs index 1a5266f5583d6..775278c30cd4c 100644 --- a/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs +++ b/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] trait MyTrait {} -#[rustc_reservation_impl] +#[rustc_reservation_impl="this impl is reserved"] impl MyTrait for () {} trait OtherTrait {} diff --git a/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.stderr b/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.stderr index 7b88d2b42db1b..47e141bd048eb 100644 --- a/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.stderr +++ b/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.stderr @@ -5,6 +5,8 @@ LL | impl OtherTrait for () {} | ---------------------- first implementation here LL | impl OtherTrait for T {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + | + = note: this impl is reserved error: aborting due to previous error diff --git a/src/test/ui/traits/reservation-impls/reservation-impl-no-use.rs b/src/test/ui/traits/reservation-impls/reservation-impl-no-use.rs index f08338bdc1c91..3391daaabe975 100644 --- a/src/test/ui/traits/reservation-impls/reservation-impl-no-use.rs +++ b/src/test/ui/traits/reservation-impls/reservation-impl-no-use.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] trait MyTrait { fn foo(&self); } -#[rustc_reservation_impl] +#[rustc_reservation_impl = "foo"] impl MyTrait for () { fn foo(&self) {} } fn main() { diff --git a/src/test/ui/traits/reservation-impls/reservation-impl-ok.rs b/src/test/ui/traits/reservation-impls/reservation-impl-ok.rs index febd14b792297..611c8d8841323 100644 --- a/src/test/ui/traits/reservation-impls/reservation-impl-ok.rs +++ b/src/test/ui/traits/reservation-impls/reservation-impl-ok.rs @@ -11,7 +11,7 @@ trait MyTrait { fn foo(&self, s: S) -> usize; } -#[rustc_reservation_impl] +#[rustc_reservation_impl = "foo"] impl MyTrait for T { fn foo(&self, _x: u64) -> usize { 0 } } From 4e437d636b1cc5af27a9e6488ac9ec5c78c9c096 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 30 Jul 2019 21:16:08 +0300 Subject: [PATCH 7/7] fix to bypass #62696 I think that PR is a problem (#63145), but this makes the tests green for now. --- src/librustc/traits/specialize/mod.rs | 2 ++ .../reservation-impls/reservation-impl-coherence-conflict.rs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 8a84fca143809..7e3b00f66e98c 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -310,6 +310,8 @@ pub(super) fn specialization_graph_provider( }; if let Some(overlap) = overlap { + debug!("found conflicting implementations {:?}", overlap); + let msg = format!("conflicting implementations of trait `{}`{}:{}", overlap.trait_desc, overlap.self_desc.clone().map_or( diff --git a/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs b/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs index 775278c30cd4c..538a9e8ce035b 100644 --- a/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs +++ b/src/test/ui/traits/reservation-impls/reservation-impl-coherence-conflict.rs @@ -4,11 +4,11 @@ #![feature(rustc_attrs)] -trait MyTrait {} +pub trait MyTrait {} #[rustc_reservation_impl="this impl is reserved"] impl MyTrait for () {} -trait OtherTrait {} +pub trait OtherTrait {} impl OtherTrait for () {} impl OtherTrait for T {} //~^ ERROR conflicting implementations