From c199d253867085dae44f6946d7085a991abe17c8 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Thu, 6 Apr 2017 21:59:08 +0200 Subject: [PATCH 01/12] rephrased std::hash::BuildHasherDefault docs Part of #29357. * split summary and explanation more clearly * added link to nomicon for "zero-sized" * "does not need construction" -> say how it can be created, and that it doesn't need to be done with `HashMap` or `HashSet` --- src/libcore/hash/mod.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 756d472eca8d4..0d34aeb7cb731 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -285,11 +285,17 @@ pub trait BuildHasher { fn build_hasher(&self) -> Self::Hasher; } -/// The `BuildHasherDefault` structure is used in scenarios where one has a -/// type that implements [`Hasher`] and [`Default`], but needs that type to -/// implement [`BuildHasher`]. +/// Used to create a default [`BuildHasher`] instance for types that implement +/// [`Hasher`] and [`Default`]. /// -/// This structure is zero-sized and does not need construction. +/// `BuildHasherDefault` can be used when a type `H` implements [`Hasher`] and +/// [`Default`], and you need a corresponding [`BuildHasher`] instance, but none is +/// defined. +/// +/// Any `BuildHasherDefault` is [zero-sized]. It can be created with +/// [`default`][method.Default]. When using `BuildHasherDefault` with [`HashMap`] or +/// [`HashSet`], this doesn't need to be done, since they implement appropriate +/// [`Default`] instances themselves. /// /// # Examples /// @@ -322,8 +328,11 @@ pub trait BuildHasher { /// /// [`BuildHasher`]: trait.BuildHasher.html /// [`Default`]: ../default/trait.Default.html +/// [method.default]: #method.default /// [`Hasher`]: trait.Hasher.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html +/// [`HashSet`]: ../../std/collections/struct.HashSet.html +/// [zero-sized]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts #[stable(since = "1.7.0", feature = "build_hasher")] pub struct BuildHasherDefault(marker::PhantomData); From e88a511fd50276b2d88edf9a7a7bbf6a89ca9f68 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Thu, 6 Apr 2017 22:32:51 +0200 Subject: [PATCH 02/12] improved std::hash::BuildHasher docs Part of #29357. * split summary and explanation more clearly, while expanding the explanation to make the reason for `BuildHasher` existing more clear * added an example illustrating that `Hasher`s created by one `BuildHasher` should be identical * added links * repeated the fact that hashers produced should be identical in `build_hasher`s method docs --- src/libcore/hash/mod.rs | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 0d34aeb7cb731..b24938b908a6f 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -258,12 +258,35 @@ pub trait Hasher { } } -/// A `BuildHasher` is typically used as a factory for instances of `Hasher` -/// which a `HashMap` can then use to hash keys independently. +/// A trait for creating instances of [`Hasher`]. /// -/// Note that for each instance of `BuildHasher`, the created hashers should be -/// identical. That is, if the same stream of bytes is fed into each hasher, the -/// same output will also be generated. +/// A `BuildHasher` is typically used (e.g. by [`HashMap`]) to create +/// [`Hasher`]s for each key such that they are hashed independently of one +/// another, since [`Hasher`]s contain state. +/// +/// For each instance of `BuildHasher`, the [`Hasher`]s created by +/// [`build_hasher`] should be identical. That is, if the same stream of bytes +/// is fed into each hasher, the same output will also be generated. +/// +/// # Examples +/// +/// ``` +/// use std::collections::hash_map::RandomState; +/// use std::hash::{BuildHasher, Hasher}; +/// +/// let s = RandomState::new(); +/// let mut hasher_1 = s.build_hasher(); +/// let mut hasher_2 = s.build_hasher(); +/// +/// hasher_1.write_u32(8128); +/// hasher_2.write_u32(8128); +/// +/// assert_eq!(hasher_1.finish(), hasher_2.finish()); +/// ``` +/// +/// [`build_hasher`]: #method.build_hasher +/// [`Hasher`]: trait.Hasher.html +/// [`HashMap`]: ../../std/collections/struct.HashMap.html #[stable(since = "1.7.0", feature = "build_hasher")] pub trait BuildHasher { /// Type of the hasher that will be created. @@ -272,6 +295,9 @@ pub trait BuildHasher { /// Creates a new hasher. /// + /// Each call to `build_hasher` on the same instance should produce identical + /// [`Hasher`]s. + /// /// # Examples /// /// ``` @@ -281,6 +307,8 @@ pub trait BuildHasher { /// let s = RandomState::new(); /// let new_s = s.build_hasher(); /// ``` + /// + /// [`Hasher`]: trait.Hasher.html #[stable(since = "1.7.0", feature = "build_hasher")] fn build_hasher(&self) -> Self::Hasher; } From 37275b6fc3635291d19331974e361c1ccd02a467 Mon Sep 17 00:00:00 2001 From: lukaramu Date: Thu, 6 Apr 2017 23:39:32 +0200 Subject: [PATCH 03/12] improved std::hash::Hash docs Part of #29357. * merged "Derivable" and "How can I implement `Hash`?" sections into one "Implementing `Hash`" section to aid coherency * added an example for `#[derive(Hash)]` * moved part about relation between `Hash` and `Eq` into a new "`Hash` and `Eq`" section; changed wording to be more consistent with `HashMap` and `HashSet`'s * explicitly mentioned `#[derive(PartialEq, Eq, Hash)]` in the new section * changed method summaries for consistency, adding links and examples --- src/libcore/hash/mod.rs | 83 ++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 22 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index b24938b908a6f..130a75a7027ac 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -107,29 +107,25 @@ mod sip; /// A hashable type. /// -/// The `H` type parameter is an abstract hash state that is used by the `Hash` -/// to compute the hash. +/// Types implementing `Hash` are able to be [`hash`]ed with an instance of +/// [`Hasher`]. /// -/// If you are also implementing [`Eq`], there is an additional property that -/// is important: +/// ## Implementing `Hash` /// -/// ```text -/// k1 == k2 -> hash(k1) == hash(k2) -/// ``` -/// -/// In other words, if two keys are equal, their hashes should also be equal. -/// [`HashMap`] and [`HashSet`] both rely on this behavior. +/// You can derive `Hash` with `#[derive(Hash)]` if all fields implement `Hash`. +/// The resulting hash will be the combination of the values from calling +/// [`hash`] on each field. /// -/// ## Derivable -/// -/// This trait can be used with `#[derive]` if all fields implement `Hash`. -/// When `derive`d, the resulting hash will be the combination of the values -/// from calling [`.hash`] on each field. -/// -/// ## How can I implement `Hash`? +/// ``` +/// #[derive(Hash)] +/// struct Rustacean { +/// name: String, +/// country: String, +/// } +/// ``` /// -/// If you need more control over how a value is hashed, you need to implement -/// the `Hash` trait: +/// If you need more control over how a value is hash, you can of course +/// implement the `Hash` trait yourself: /// /// ``` /// use std::hash::{Hash, Hasher}; @@ -148,17 +144,60 @@ mod sip; /// } /// ``` /// +/// ## `Hash` and `Eq` +/// +/// When implementing both `Hash` and [`Eq`], it is important that the following +/// property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must also be equal. +/// [`HashMap`] and [`HashSet`] both rely on this behavior. +/// +/// Thankfully, you won't need to worry about upholding this property when +/// deriving both [`Eq`] and `Hash` with `#[derive(PartialEq, Eq, Hash)]`. +/// /// [`Eq`]: ../../std/cmp/trait.Eq.html +/// [`Hasher`]: trait.Hasher.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`HashSet`]: ../../std/collections/struct.HashSet.html -/// [`.hash`]: #tymethod.hash +/// [`hash`]: #tymethod.hash #[stable(feature = "rust1", since = "1.0.0")] pub trait Hash { - /// Feeds this value into the state given, updating the hasher as necessary. + /// Feeds this value into the given [`Hasher`]. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::{Hash, Hasher}; + /// + /// let mut hasher = DefaultHasher::new(); + /// 7920.hash(&mut hasher); + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` + /// + /// [`Hasher`]: trait.Hasher.html #[stable(feature = "rust1", since = "1.0.0")] fn hash(&self, state: &mut H); - /// Feeds a slice of this type into the state provided. + /// Feeds a slice of this type into the given [`Hasher`]. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::{Hash, Hasher}; + /// + /// let mut hasher = DefaultHasher::new(); + /// let numbers = [6, 28, 496, 8128]; + /// Hash::hash_slice(&numbers, &mut hasher); + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` + /// + /// [`Hasher`]: trait.Hasher.html #[stable(feature = "hash_slice", since = "1.3.0")] fn hash_slice(data: &[Self], state: &mut H) where Self: Sized From 0dce5862fcb8677f416e0bf1eb75b8e53108c70c Mon Sep 17 00:00:00 2001 From: lukaramu Date: Fri, 7 Apr 2017 00:39:27 +0200 Subject: [PATCH 04/12] improved std::hash::Hasher docs Part of #29357. * rephrased summary sentences to be less redundant * expanded top-level docs, adding a usage example and links to relevant methods (`finish`, `write` etc) as well as `Hash` * added examples to the `finish` and `write` methods --- src/libcore/hash/mod.rs | 59 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 130a75a7027ac..4ebec401669c5 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -208,18 +208,73 @@ pub trait Hash { } } -/// A trait which represents the ability to hash an arbitrary stream of bytes. +/// A trait for hashing an arbitrary stream of bytes. +/// +/// Instances of `Hasher` usually represent state that is changed while hashing +/// data. +/// +/// `Hasher` provides a fairly basic interface for retrieving the generated hash +/// (with [`finish`]), and writing integers as well as slices of bytes into an +/// instance (with [`write`] and [`write_u8`] etc.). Most of the time, `Hasher` +/// instances are used in conjunction with the [`Hash`] trait. +/// +/// # Examples +/// +/// ``` +/// use std::collections::hash_map::DefaultHasher; +/// use std::hash::Hasher; +/// +/// let mut hasher = DefaultHasher::new(); +/// +/// hasher.write_u32(1989); +/// hasher.write_u8(11); +/// hasher.write_u8(9); +/// hasher.write(b"Huh?"); +/// +/// println!("Hash is {:x}!", hasher.finish()); +/// ``` +/// +/// [`Hash`]: trait.Hash.html +/// [`finish`]: #tymethod.finish +/// [`write`]: #tymethod.write +/// [`write_u8`]: #method.write_u8 #[stable(feature = "rust1", since = "1.0.0")] pub trait Hasher { /// Completes a round of hashing, producing the output hash generated. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::Hasher; + /// + /// let mut hasher = DefaultHasher::new(); + /// hasher.write(b"Cool!"); + /// + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn finish(&self) -> u64; /// Writes some data into this `Hasher`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::Hasher; + /// + /// let mut hasher = DefaultHasher::new(); + /// let data = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; + /// + /// hasher.write(&data); + /// + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write(&mut self, bytes: &[u8]); - /// Write a single `u8` into this hasher. + /// Writes a single `u8` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u8(&mut self, i: u8) { From 12d7c3d9d8e6694b693e9ee30402063b6cef18ab Mon Sep 17 00:00:00 2001 From: lukaramu Date: Mon, 10 Apr 2017 17:50:54 +0200 Subject: [PATCH 05/12] Fixed indent, grammar, and link in std::hash docs --- src/libcore/hash/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 4ebec401669c5..f68361e852277 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -119,12 +119,12 @@ mod sip; /// ``` /// #[derive(Hash)] /// struct Rustacean { -/// name: String, -/// country: String, +/// name: String, +/// country: String, /// } /// ``` /// -/// If you need more control over how a value is hash, you can of course +/// If you need more control over how a value is hashed, you can of course /// implement the `Hash` trait yourself: /// /// ``` @@ -378,7 +378,7 @@ pub trait Hasher { /// assert_eq!(hasher_1.finish(), hasher_2.finish()); /// ``` /// -/// [`build_hasher`]: #method.build_hasher +/// [`build_hasher`]: #tymethod.build_hasher /// [`Hasher`]: trait.Hasher.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html #[stable(since = "1.7.0", feature = "build_hasher")] From 4aca54001865435c799757c6fcb8595c23ff6c77 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Sat, 25 Feb 2017 16:16:27 -0500 Subject: [PATCH 06/12] Implement RFC 1268 This patch allows overlap to occur between any two impls of a trait for traits which have no associated items. Several compile-fail tests around coherence had to be changed to add at least one item to the trait they test against. Ref #29864 --- src/librustc/traits/specialize/mod.rs | 5 ++++ .../traits/specialize/specialization_graph.rs | 5 ++++ src/librustc/ty/mod.rs | 10 ++++++++ src/test/compile-fail/E0120.rs | 2 +- ...herence-conflicting-negative-trait-impl.rs | 2 +- .../coherence-default-trait-impl.rs | 2 +- src/test/compile-fail/coherence-impls-send.rs | 1 - .../coherence-no-direct-lifetime-dispatch.rs | 2 +- .../coherence-overlap-all-t-and-tuple.rs | 1 + .../coherence-overlap-messages.rs | 8 +++---- .../coherence-projection-conflict-orphan.rs | 2 +- .../coherence-projection-conflict-ty-param.rs | 2 +- .../coherence-projection-conflict.rs | 2 +- ...erence_copy_like_err_fundamental_struct.rs | 2 +- ...ce_copy_like_err_fundamental_struct_ref.rs | 2 +- ..._copy_like_err_fundamental_struct_tuple.rs | 2 +- .../coherence_copy_like_err_struct.rs | 2 +- .../coherence_copy_like_err_tuple.rs | 2 +- .../specialization/specialization-overlap.rs | 8 +++---- .../overlap-permitted-for-marker-traits.rs | 23 +++++++++++++++++++ 20 files changed, 64 insertions(+), 21 deletions(-) create mode 100644 src/test/run-pass/overlap-permitted-for-marker-traits.rs diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 50a4d982832ac..6455de48a299d 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -155,6 +155,11 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return r; } + if tcx.impl_always_allowed_to_overlap(impl1_def_id) + && tcx.impl_always_allowed_to_overlap(impl2_def_id) { + return true; + } + // The feature gate should prevent introducing new specializations, but not // taking advantage of upstream ones. if !tcx.sess.features.borrow().specialization && diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 40eb69395678f..87abe681d3938 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -113,6 +113,11 @@ impl<'a, 'gcx, 'tcx> Children { possible_sibling, impl_def_id); if let Some(impl_header) = overlap { + if tcx.impl_always_allowed_to_overlap(impl_def_id) + && tcx.impl_always_allowed_to_overlap(possible_sibling) { + return Ok((true, true)); + } + let le = specializes(tcx, impl_def_id, possible_sibling); let ge = specializes(tcx, possible_sibling, impl_def_id); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8ff91583d0822..9fdabd38d4ab4 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2227,6 +2227,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { queries::impl_trait_ref::get(self, DUMMY_SP, id) } + /// Returns true if the impl is positive and is for a triat which contains + /// no items + pub fn impl_always_allowed_to_overlap(self, def_id: DefId) -> bool { + self.trait_impl_polarity(def_id) == hir::ImplPolarity::Positive + && self.impl_trait_ref(def_id) + .map_or(false, |trait_ref| { + self.associated_item_def_ids(trait_ref.def_id).is_empty() + }) + } + // Returns `ty::VariantDef` if `def` refers to a struct, // or variant or their constructors, panics otherwise. pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef { diff --git a/src/test/compile-fail/E0120.rs b/src/test/compile-fail/E0120.rs index 3fdeb75317540..80cc0d2680f7c 100644 --- a/src/test/compile-fail/E0120.rs +++ b/src/test/compile-fail/E0120.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait MyTrait {} +trait MyTrait { fn foo() {} } impl Drop for MyTrait { //~^ ERROR E0120 diff --git a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs index 7fd1b17f2966c..d841e8c41d984 100644 --- a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs +++ b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs @@ -20,8 +20,8 @@ impl !Send for TestType {} //~^ ERROR conflicting implementations of trait `std::marker::Send` unsafe impl Send for TestType {} -//~^ ERROR conflicting implementations of trait `std::marker::Send` impl !Send for TestType {} +//~^ ERROR conflicting implementations of trait `std::marker::Send` fn main() {} diff --git a/src/test/compile-fail/coherence-default-trait-impl.rs b/src/test/compile-fail/coherence-default-trait-impl.rs index 15a80c64f8b06..e6bf068156c2b 100644 --- a/src/test/compile-fail/coherence-default-trait-impl.rs +++ b/src/test/compile-fail/coherence-default-trait-impl.rs @@ -10,7 +10,7 @@ #![feature(optin_builtin_traits)] -trait MyTrait {} +trait MyTrait { fn foo() {} } impl MyTrait for .. {} //~^ ERROR redundant default implementations of trait `MyTrait` diff --git a/src/test/compile-fail/coherence-impls-send.rs b/src/test/compile-fail/coherence-impls-send.rs index f130a9353516f..d0e6bc6a1c699 100644 --- a/src/test/compile-fail/coherence-impls-send.rs +++ b/src/test/compile-fail/coherence-impls-send.rs @@ -34,7 +34,6 @@ unsafe impl Send for [MyType] {} unsafe impl Send for &'static [NotSync] {} //~^ ERROR E0117 -//~| ERROR E0119 fn main() { } diff --git a/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs b/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs index 6de338f1db0fa..47026cd32d411 100644 --- a/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs +++ b/src/test/compile-fail/coherence-no-direct-lifetime-dispatch.rs @@ -10,7 +10,7 @@ // Test that you cannot *directly* dispatch on lifetime requirements -trait MyTrait {} +trait MyTrait { fn foo() {} } impl MyTrait for T {} impl MyTrait for T {} //~ ERROR E0119 diff --git a/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs b/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs index 928ba7a36db26..1fad608db6c3b 100644 --- a/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs +++ b/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs @@ -17,6 +17,7 @@ // Seems pretty basic, but then there was issue #24241. :) trait From { + fn foo() {} } impl From for T { diff --git a/src/test/compile-fail/coherence-overlap-messages.rs b/src/test/compile-fail/coherence-overlap-messages.rs index 0ae8135221c21..a10deeafbe67e 100644 --- a/src/test/compile-fail/coherence-overlap-messages.rs +++ b/src/test/compile-fail/coherence-overlap-messages.rs @@ -8,22 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Foo {} +trait Foo { fn foo() {} } impl Foo for T {} impl Foo for U {} //~ ERROR conflicting implementations of trait `Foo`: -trait Bar {} +trait Bar { fn bar() {} } impl Bar for (T, u8) {} impl Bar for (u8, T) {} //~ ERROR conflicting implementations of trait `Bar` for type `(u8, u8)`: -trait Baz {} +trait Baz { fn baz() {} } impl Baz for T {} impl Baz for u8 {} //~ ERROR conflicting implementations of trait `Baz` for type `u8`: -trait Quux {} +trait Quux { fn quux() {} } impl Quux for T {} impl Quux for T {} //~ ERROR conflicting implementations of trait `Quux<_, _>`: diff --git a/src/test/compile-fail/coherence-projection-conflict-orphan.rs b/src/test/compile-fail/coherence-projection-conflict-orphan.rs index 3ed3549de89aa..784ff0cd5e0aa 100644 --- a/src/test/compile-fail/coherence-projection-conflict-orphan.rs +++ b/src/test/compile-fail/coherence-projection-conflict-orphan.rs @@ -15,7 +15,7 @@ // due to the orphan rules. Therefore, `A::Item` may yet turn out to // be `i32`. -pub trait Foo

{} +pub trait Foo

{ fn foo() {} } pub trait Bar { type Output: 'static; diff --git a/src/test/compile-fail/coherence-projection-conflict-ty-param.rs b/src/test/compile-fail/coherence-projection-conflict-ty-param.rs index f04902a70f68c..120d9046389a1 100644 --- a/src/test/compile-fail/coherence-projection-conflict-ty-param.rs +++ b/src/test/compile-fail/coherence-projection-conflict-ty-param.rs @@ -13,7 +13,7 @@ use std::marker::PhantomData; -pub trait Foo

{} +pub trait Foo

{ fn foo() {} } impl > Foo

for Option {} diff --git a/src/test/compile-fail/coherence-projection-conflict.rs b/src/test/compile-fail/coherence-projection-conflict.rs index 6d3ab32f06f43..3c32ab38b93dc 100644 --- a/src/test/compile-fail/coherence-projection-conflict.rs +++ b/src/test/compile-fail/coherence-projection-conflict.rs @@ -10,7 +10,7 @@ use std::marker::PhantomData; -pub trait Foo

{} +pub trait Foo

{ fn foo() {} } pub trait Bar { type Output: 'static; diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs index fcd6e5c495207..9fbb7aa4cb1a7 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs @@ -20,7 +20,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // `MyFundamentalStruct` is declared fundamental, so we can test that diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs index b5c0a7fb5f564..2f6dca4f3c271 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs @@ -20,7 +20,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // `MyFundamentalStruct` is declared fundamental, so we can test that diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs index 8e3e3f31cb5f1..f424e8872010f 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs @@ -19,7 +19,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } diff --git a/src/test/compile-fail/coherence_copy_like_err_struct.rs b/src/test/compile-fail/coherence_copy_like_err_struct.rs index 35bc17b8e8870..04262e65c5a2a 100644 --- a/src/test/compile-fail/coherence_copy_like_err_struct.rs +++ b/src/test/compile-fail/coherence_copy_like_err_struct.rs @@ -17,7 +17,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // `MyStruct` is not declared fundamental, therefore this would diff --git a/src/test/compile-fail/coherence_copy_like_err_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_tuple.rs index a70cc92955fb0..378a70864f0ee 100644 --- a/src/test/compile-fail/coherence_copy_like_err_tuple.rs +++ b/src/test/compile-fail/coherence_copy_like_err_tuple.rs @@ -17,7 +17,7 @@ extern crate coherence_copy_like_lib as lib; struct MyType { x: i32 } -trait MyTrait { } +trait MyTrait { fn foo() {} } impl MyTrait for T { } // Tuples are not fundamental, therefore this would require that diff --git a/src/test/compile-fail/specialization/specialization-overlap.rs b/src/test/compile-fail/specialization/specialization-overlap.rs index f579817100107..ff12a82db5b7d 100644 --- a/src/test/compile-fail/specialization/specialization-overlap.rs +++ b/src/test/compile-fail/specialization/specialization-overlap.rs @@ -10,19 +10,19 @@ #![feature(specialization)] -trait Foo {} +trait Foo { fn foo() {} } impl Foo for T {} impl Foo for Vec {} //~ ERROR E0119 -trait Bar {} +trait Bar { fn bar() {} } impl Bar for (T, u8) {} impl Bar for (u8, T) {} //~ ERROR E0119 -trait Baz {} +trait Baz { fn baz() {} } impl Baz for u8 {} impl Baz for T {} //~ ERROR E0119 -trait Qux {} +trait Qux { fn qux() {} } impl Qux for T {} impl Qux for T {} //~ ERROR E0119 diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits.rs b/src/test/run-pass/overlap-permitted-for-marker-traits.rs new file mode 100644 index 0000000000000..66c45e6718331 --- /dev/null +++ b/src/test/run-pass/overlap-permitted-for-marker-traits.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait MyMarker {} + +impl MyMarker for T {} +impl MyMarker for T {} + +fn foo(t: T) -> T { + t +} + +fn main() { + assert_eq!(1, foo(1)); + assert_eq!(vec![1], foo(vec![1])); +} From ddcca79d25fffd6604fba593b1ca642a9dfa5727 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 3 Mar 2017 09:09:09 -0500 Subject: [PATCH 07/12] Update with response to feedback --- src/librustc/ty/mod.rs | 2 +- src/test/run-pass/overlap-permitted-for-marker-traits.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9fdabd38d4ab4..e9bcb80cff25e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2227,7 +2227,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { queries::impl_trait_ref::get(self, DUMMY_SP, id) } - /// Returns true if the impl is positive and is for a triat which contains + /// Returns true if the impl is positive and is for a trait which contains /// no items pub fn impl_always_allowed_to_overlap(self, def_id: DefId) -> bool { self.trait_impl_polarity(def_id) == hir::ImplPolarity::Positive diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits.rs b/src/test/run-pass/overlap-permitted-for-marker-traits.rs index 66c45e6718331..b0b1930d274d6 100644 --- a/src/test/run-pass/overlap-permitted-for-marker-traits.rs +++ b/src/test/run-pass/overlap-permitted-for-marker-traits.rs @@ -19,5 +19,6 @@ fn foo(t: T) -> T { fn main() { assert_eq!(1, foo(1)); + assert_eq!(2.0, foo(2.0)); assert_eq!(vec![1], foo(vec![1])); } From c81c958e984b92222909e2ba5c74a2260a44bdae Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 17 Mar 2017 12:43:15 -0400 Subject: [PATCH 08/12] Further update with response to feedback --- src/librustc/traits/select.rs | 3 ++- src/librustc/traits/specialize/mod.rs | 5 ----- .../traits/specialize/specialization_graph.rs | 5 ++--- src/librustc/ty/mod.rs | 22 ++++++++++++------- .../auxiliary/trait_impl_conflict.rs | 1 + 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 67d50210ba39a..410eb2b84849e 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1736,7 +1736,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if other.evaluation == EvaluatedToOk { if let ImplCandidate(victim_def) = victim.candidate { let tcx = self.tcx().global_tcx(); - return traits::specializes(tcx, other_def, victim_def); + return traits::specializes(tcx, other_def, victim_def) || + tcx.impls_are_allowed_to_overlap(other_def, victim_def); } } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 6455de48a299d..50a4d982832ac 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -155,11 +155,6 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return r; } - if tcx.impl_always_allowed_to_overlap(impl1_def_id) - && tcx.impl_always_allowed_to_overlap(impl2_def_id) { - return true; - } - // The feature gate should prevent introducing new specializations, but not // taking advantage of upstream ones. if !tcx.sess.features.borrow().specialization && diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 87abe681d3938..6e2c16c82aeb4 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -113,9 +113,8 @@ impl<'a, 'gcx, 'tcx> Children { possible_sibling, impl_def_id); if let Some(impl_header) = overlap { - if tcx.impl_always_allowed_to_overlap(impl_def_id) - && tcx.impl_always_allowed_to_overlap(possible_sibling) { - return Ok((true, true)); + if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) { + return Ok((false, false)); } let le = specializes(tcx, impl_def_id, possible_sibling); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e9bcb80cff25e..2ae77046a90ed 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2227,14 +2227,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { queries::impl_trait_ref::get(self, DUMMY_SP, id) } - /// Returns true if the impl is positive and is for a trait which contains - /// no items - pub fn impl_always_allowed_to_overlap(self, def_id: DefId) -> bool { - self.trait_impl_polarity(def_id) == hir::ImplPolarity::Positive - && self.impl_trait_ref(def_id) - .map_or(false, |trait_ref| { - self.associated_item_def_ids(trait_ref.def_id).is_empty() - }) + /// Returns true if the impls are the same polarity and are implementing + /// a trait which contains no items + pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { + 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() + }); + let trait2_is_empty = self.impl_trait_ref(def_id2) + .map_or(false, |trait_ref| { + self.associated_item_def_ids(trait_ref.def_id).is_empty() + }); + self.trait_impl_polarity(def_id1) == self.trait_impl_polarity(def_id2) + && trait1_is_empty + && trait2_is_empty } // Returns `ty::VariantDef` if `def` refers to a struct, diff --git a/src/test/compile-fail/auxiliary/trait_impl_conflict.rs b/src/test/compile-fail/auxiliary/trait_impl_conflict.rs index c3ecbb014dc6b..3190ce430ad67 100644 --- a/src/test/compile-fail/auxiliary/trait_impl_conflict.rs +++ b/src/test/compile-fail/auxiliary/trait_impl_conflict.rs @@ -9,6 +9,7 @@ // except according to those terms. pub trait Foo { + fn foo() {} } impl Foo for isize { From adcdd605be9cbdb338d4ecc2410cde87272f2191 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 17 Mar 2017 14:16:29 -0400 Subject: [PATCH 09/12] Put overlapping impls behind feature gate, add tests I've added some explicit tests that negative impls are allowed to overlap, and also to make sure that the feature doesn't interfere with specialization. I've not added an explicit test for positive overlapping with negative, as that's already tested elsewhere. --- src/librustc/ty/mod.rs | 3 +++ src/libsyntax/feature_gate.rs | 3 +++ ...herence-conflicting-negative-trait-impl.rs | 1 + src/test/compile-fail/coherence-impls-send.rs | 1 + ...overlapping-impls-requires-feature-gate.rs | 17 ++++++++++++ ...lap-doesnt-conflict-with-specialization.rs | 27 +++++++++++++++++++ .../overlap-permitted-for-marker-traits.rs | 7 +++++ 7 files changed, 59 insertions(+) create mode 100644 src/test/compile-fail/overlapping-impls-requires-feature-gate.rs create mode 100644 src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2ae77046a90ed..3da9383762bc6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2230,6 +2230,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns true if the impls are the same polarity and are implementing /// a trait which contains no items pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { + if !self.sess.features.borrow().overlapping_marker_traits { + return false; + } 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() diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 8b62416dcbdbd..6e455234196d4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -349,6 +349,9 @@ declare_features! ( // Allows module-level inline assembly by way of global_asm!() (active, global_asm, "1.18.0", Some(35119)), + + // Allows overlapping impls of marker traits + (active, overlapping_marker_traits, "1.18.0", Some(29864)), ); declare_features! ( diff --git a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs index d841e8c41d984..8e9d1eff34580 100644 --- a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs +++ b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(optin_builtin_traits)] +#![feature(overlapping_marker_traits)] trait MyTrait {} diff --git a/src/test/compile-fail/coherence-impls-send.rs b/src/test/compile-fail/coherence-impls-send.rs index d0e6bc6a1c699..9caaee41aeb1d 100644 --- a/src/test/compile-fail/coherence-impls-send.rs +++ b/src/test/compile-fail/coherence-impls-send.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(optin_builtin_traits)] +#![feature(overlapping_marker_traits)] use std::marker::Copy; diff --git a/src/test/compile-fail/overlapping-impls-requires-feature-gate.rs b/src/test/compile-fail/overlapping-impls-requires-feature-gate.rs new file mode 100644 index 0000000000000..bf2b06dd8ba0c --- /dev/null +++ b/src/test/compile-fail/overlapping-impls-requires-feature-gate.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait MyMarker {} + +impl MyMarker for T {} +impl MyMarker for Vec {} +//~^ ERROR E0119 + +fn main() {} diff --git a/src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs b/src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs new file mode 100644 index 0000000000000..ed45d81c0d6a1 --- /dev/null +++ b/src/test/run-pass/overlap-doesnt-conflict-with-specialization.rs @@ -0,0 +1,27 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(overlapping_marker_traits)] +#![feature(specialization)] + +trait MyMarker {} + +impl MyMarker for T {} +impl MyMarker for Vec {} + +fn foo(t: T) -> T { + t +} + +fn main() { + assert_eq!(1, foo(1)); + assert_eq!(2.0, foo(2.0)); + assert_eq!(vec![1], foo(vec![1])); +} diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits.rs b/src/test/run-pass/overlap-permitted-for-marker-traits.rs index b0b1930d274d6..45085c093fc98 100644 --- a/src/test/run-pass/overlap-permitted-for-marker-traits.rs +++ b/src/test/run-pass/overlap-permitted-for-marker-traits.rs @@ -8,11 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(overlapping_marker_traits)] +#![feature(optin_builtin_traits)] + trait MyMarker {} impl MyMarker for T {} impl MyMarker for T {} +struct MyStruct; +impl !Send for MyStruct {} +impl !Send for MyStruct {} + fn foo(t: T) -> T { t } From 5a9c25b91e3ccefbeb52b1bd0a79ed48d9efae85 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 17 Mar 2017 19:20:18 -0400 Subject: [PATCH 10/12] Name files what tidy wants them to be namd --- ...-feature-gate.rs => feature-gate-overlapping_marker_traits.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/compile-fail/{overlapping-impls-requires-feature-gate.rs => feature-gate-overlapping_marker_traits.rs} (100%) diff --git a/src/test/compile-fail/overlapping-impls-requires-feature-gate.rs b/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs similarity index 100% rename from src/test/compile-fail/overlapping-impls-requires-feature-gate.rs rename to src/test/compile-fail/feature-gate-overlapping_marker_traits.rs From 805704c3469853b923c61744eed64a79c7879170 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 30 Mar 2017 08:54:28 -0400 Subject: [PATCH 11/12] update tests slightly --- .../feature-gate-overlapping_marker_traits.rs | 6 ++- src/test/compile-fail/overlap-marker-trait.rs | 41 +++++++++++++++++++ ...overlap-permitted-for-marker-traits-neg.rs | 20 +++++++++ .../overlap-permitted-for-marker-traits.rs | 17 +++++--- 4 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 src/test/compile-fail/overlap-marker-trait.rs create mode 100644 src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs diff --git a/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs b/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs index bf2b06dd8ba0c..d2aa4e59b5ba9 100644 --- a/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs +++ b/src/test/compile-fail/feature-gate-overlapping_marker_traits.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::fmt::{Debug, Display}; + trait MyMarker {} -impl MyMarker for T {} -impl MyMarker for Vec {} +impl MyMarker for T {} +impl MyMarker for T {} //~^ ERROR E0119 fn main() {} diff --git a/src/test/compile-fail/overlap-marker-trait.rs b/src/test/compile-fail/overlap-marker-trait.rs new file mode 100644 index 0000000000000..a649ae25f34ea --- /dev/null +++ b/src/test/compile-fail/overlap-marker-trait.rs @@ -0,0 +1,41 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test for RFC 1268: we allow overlapping impls of marker traits, +// that is, traits without items. In this case, a type `T` is +// `MyMarker` if it is either `Debug` or `Display`. This test just +// checks that we don't consider **all** types to be `MyMarker`. See +// also the companion test in +// `run-pass/overlap-permitted-for-marker-traits.rs`. + +#![feature(overlapping_marker_traits)] +#![feature(optin_builtin_traits)] + +use std::fmt::{Debug, Display}; + +trait Marker {} + +impl Marker for T {} +impl Marker for T {} + +fn is_marker() { } + +struct NotDebugOrDisplay; + +fn main() { + // Debug && Display: + is_marker::(); + + // Debug && !Display: + is_marker::>(); + + // !Debug && !Display + is_marker::(); //~ ERROR +} diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs b/src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs new file mode 100644 index 0000000000000..740d5d22ab507 --- /dev/null +++ b/src/test/run-pass/overlap-permitted-for-marker-traits-neg.rs @@ -0,0 +1,20 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(overlapping_marker_traits)] +#![feature(optin_builtin_traits)] + +// Overlapping negative impls for `MyStruct` are permitted: +struct MyStruct; +impl !Send for MyStruct {} +impl !Send for MyStruct {} + +fn main() { +} diff --git a/src/test/run-pass/overlap-permitted-for-marker-traits.rs b/src/test/run-pass/overlap-permitted-for-marker-traits.rs index 45085c093fc98..11a46299d8c83 100644 --- a/src/test/run-pass/overlap-permitted-for-marker-traits.rs +++ b/src/test/run-pass/overlap-permitted-for-marker-traits.rs @@ -8,24 +8,29 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests for RFC 1268: we allow overlapping impls of marker traits, +// that is, traits without items. In this case, a type `T` is +// `MyMarker` if it is either `Debug` or `Display`. + #![feature(overlapping_marker_traits)] #![feature(optin_builtin_traits)] -trait MyMarker {} +use std::fmt::{Debug, Display}; -impl MyMarker for T {} -impl MyMarker for T {} +trait MyMarker {} -struct MyStruct; -impl !Send for MyStruct {} -impl !Send for MyStruct {} +impl MyMarker for T {} +impl MyMarker for T {} fn foo(t: T) -> T { t } fn main() { + // Debug && Display: assert_eq!(1, foo(1)); assert_eq!(2.0, foo(2.0)); + + // Debug && !Display: assert_eq!(vec![1], foo(vec![1])); } From ae9f571cd11d0b822827547ca6fe192cabb55d0d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 14 Apr 2017 20:38:10 -0400 Subject: [PATCH 12/12] Add Unstable Book entry for 'overlapping-marker-traits'. --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/overlapping-marker-traits.md | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 src/doc/unstable-book/src/overlapping-marker-traits.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index a5599395f7965..a9796fdf01e0d 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -136,6 +136,7 @@ - [optin_builtin_traits](optin-builtin-traits.md) - [option_entry](option-entry.md) - [osstring_shrink_to_fit](osstring-shrink-to-fit.md) +- [overlapping_marker_traits](overlapping-marker-traits.md) - [panic_abort](panic-abort.md) - [panic_runtime](panic-runtime.md) - [panic_unwind](panic-unwind.md) diff --git a/src/doc/unstable-book/src/overlapping-marker-traits.md b/src/doc/unstable-book/src/overlapping-marker-traits.md new file mode 100644 index 0000000000000..a4920839c6ca9 --- /dev/null +++ b/src/doc/unstable-book/src/overlapping-marker-traits.md @@ -0,0 +1,7 @@ +# `overlapping_marker_traits` + +The tracking issue for this feature is: [#29864] + +[#29864]: https://github.com/rust-lang/rust/issues/29864 + +------------------------