diff --git a/src/doc/unstable-book/src/language-features/marker-trait-attr.md b/src/doc/unstable-book/src/language-features/marker-trait-attr.md new file mode 100644 index 0000000000000..9dd7b6fae9bc6 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/marker-trait-attr.md @@ -0,0 +1,33 @@ +# `marker_trait_attr` + +The tracking issue for this feature is: [#29864] + +[#29864]: https://github.com/rust-lang/rust/issues/29864 + +------------------------ + +Normally, Rust keeps you from adding trait implementations that could +overlap with each other, as it would be ambiguous which to use. This +feature, however, carves out an exception to that rule: a trait can +opt-in to having overlapping implementations, at the cost that those +implementations are not allowed to override anything (and thus the +trait itself cannot have any associated items, as they're pointless +when they'd need to do the same thing for every type anyway). + +```rust +#![feature(marker_trait_attr)] + +use std::fmt::{Debug, Display}; + +#[marker] trait MyMarker {} + +impl MyMarker for T {} +impl MyMarker for T {} + +fn foo(t: T) -> T { + t +} +``` + +This is expected to replace the unstable `overlapping_marker_traits` +feature, which applied to all empty traits (without needing an opt-in). diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 298ef67923a9c..b23a50ef1a402 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -32,6 +32,7 @@ enum Target { Statement, Closure, Static, + Trait, Other, } @@ -45,6 +46,7 @@ impl Target { hir::ItemKind::Const(..) => Target::Const, hir::ItemKind::ForeignMod(..) => Target::ForeignMod, hir::ItemKind::Static(..) => Target::Static, + hir::ItemKind::Trait(..) => Target::Trait, _ => Target::Other, } } @@ -70,6 +72,8 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { self.check_inline(attr, &item.span, target) } else if attr.check_name("non_exhaustive") { self.check_non_exhaustive(attr, item, target) + } else if attr.check_name("marker") { + self.check_marker(attr, item, target) } } @@ -114,6 +118,26 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } } + /// Check if the `#[marker]` attribute on an `item` is valid. + fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) { + match target { + Target::Trait => { /* Valid */ }, + _ => { + self.tcx.sess + .struct_span_err(attr.span, "attribute can only be applied to a trait") + .span_label(item.span, "not a trait") + .emit(); + return; + } + } + + if !attr.is_word() { + self.tcx.sess + .struct_span_err(attr.span, "attribute should be empty") + .emit(); + } + } + /// Check if the `#[repr]` attributes on `item` are valid. fn check_repr(&self, item: &hir::Item, target: Target) { // Extract the names of all repr hints, e.g., [foo, bar, align] for: diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 2bf1c79c8a436..78caa45187cc6 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1033,6 +1033,7 @@ impl_stable_hash_for!(struct ty::TraitDef { unsafety, paren_sugar, has_auto_impl, + is_marker, def_path_hash, }); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d9e3bdaf266a9..4ecd504b31d52 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2652,23 +2652,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { as Box + 'a> } - /// Returns true if the impls are the same polarity and are implementing - /// a trait which contains no items + /// Returns true if the impls are the same polarity and the trait either + /// has no items or is annotated #[marker] and prevents item overrides. pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { - if !self.features().overlapping_marker_traits { - return false; + 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() + }); + 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.impl_polarity(def_id1) == self.impl_polarity(def_id2) + && trait1_is_empty + && trait2_is_empty + } else if self.features().marker_trait_attr { + 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) + } else { + 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() - }); - 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.impl_polarity(def_id1) == self.impl_polarity(def_id2) - && trait1_is_empty - && trait2_is_empty } // Returns `ty::VariantDef` if `def` refers to a struct, diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 6332080a1836c..7c75215fb8808 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -36,6 +36,11 @@ pub struct TraitDef { pub has_auto_impl: bool, + /// If `true`, then this trait has the `#[marker]` attribute, indicating + /// that all its associated items have defaults that cannot be overridden, + /// and thus `impl`s of it are allowed to overlap. + pub is_marker: bool, + /// The ICH of this trait's DefPath, cached here so it doesn't have to be /// recomputed all the time. pub def_path_hash: DefPathHash, @@ -53,13 +58,15 @@ impl<'a, 'gcx, 'tcx> TraitDef { unsafety: hir::Unsafety, paren_sugar: bool, has_auto_impl: bool, + is_marker: bool, def_path_hash: DefPathHash) -> TraitDef { TraitDef { def_id, - paren_sugar, unsafety, + paren_sugar, has_auto_impl, + is_marker, def_path_hash, } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 9907df7ed0240..e0f435f5ea5c9 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -539,6 +539,7 @@ impl<'a, 'tcx> CrateMetadata { data.unsafety, data.paren_sugar, data.has_auto_impl, + data.is_marker, self.def_path_table.def_path_hash(item_id)) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 56b38cfbc872a..c36ae02ab54e0 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1152,6 +1152,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { unsafety: trait_def.unsafety, paren_sugar: trait_def.paren_sugar, has_auto_impl: tcx.trait_is_auto(def_id), + is_marker: trait_def.is_marker, super_predicates: self.lazy(&tcx.super_predicates_of(def_id)), }; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index ab22a8e4db919..da2a8ae714b5a 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -472,6 +472,7 @@ pub struct TraitData<'tcx> { pub unsafety: hir::Unsafety, pub paren_sugar: bool, pub has_auto_impl: bool, + pub is_marker: bool, pub super_predicates: Lazy>, } @@ -479,6 +480,7 @@ impl_stable_hash_for!(struct TraitData<'tcx> { unsafety, paren_sugar, has_auto_impl, + is_marker, super_predicates }); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9e09f2cd1851e..a355bc99fd8e8 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -304,6 +304,19 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { let trait_def_id = tcx.hir.local_def_id(item.id); + + let trait_def = tcx.trait_def(trait_def_id); + if trait_def.is_marker { + for associated_def_id in &*tcx.associated_item_def_ids(trait_def_id) { + struct_span_err!( + tcx.sess, + tcx.def_span(*associated_def_id), + E0714, + "marker traits cannot have associated items", + ).emit(); + } + } + for_item(tcx, item).with_fcx(|fcx, _| { check_where_clauses(tcx, fcx, item.span, trait_def_id, None); vec![] diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 168cf47fb5266..ecb7a8ea8b62e 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -46,6 +46,7 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { } enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id); + enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id); } } @@ -99,6 +100,25 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d .emit(); } +/// We allow impls of marker traits to overlap, so they can't override impls +/// as that could make it ambiguous which associated item to use. +fn enforce_empty_impls_for_marker_traits(tcx: TyCtxt, impl_def_id: DefId, trait_def_id: DefId) { + if !tcx.trait_def(trait_def_id).is_marker { + return; + } + + if tcx.associated_item_def_ids(trait_def_id).is_empty() { + return; + } + + let span = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap()); + struct_span_err!(tcx.sess, + span, + E0715, + "impls for marker traits cannot contain items") + .emit(); +} + pub fn provide(providers: &mut Providers) { use self::builtin::coerce_unsized_info; use self::inherent_impls::{crate_inherent_impls, inherent_impls}; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 5309be21768f1..507ed5947895d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -735,8 +735,9 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty:: err.emit(); } + let is_marker = tcx.has_attr(def_id, "marker"); let def_path_hash = tcx.def_path_hash(def_id); - let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, def_path_hash); + let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, is_marker, def_path_hash); tcx.alloc_trait_def(def) } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 80c1ca944bb9e..f57d050fa2d77 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4750,6 +4750,22 @@ ambiguity for some types, we disallow calling methods on raw pointers when the type is unknown. "##, +E0714: r##" +A `#[marker]` trait contained an associated item. + +The items of marker traits cannot be overridden, so there's no need to have them +when they cannot be changed per-type anyway. If you wanted them for ergonomic +reasons, consider making an extension trait instead. +"##, + +E0715: r##" +An `impl` for a `#[marker]` trait tried to override an associated item. + +Because marker traits are allowed to have multiple implementations for the same +type, it's not allowed to override anything in those implementations, as it +would be ambiguous which override should actually be used. +"##, + } register_diagnostics! { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7266d807d3ba8..8f7f9cac4475b 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -355,6 +355,9 @@ declare_features! ( // Allows overlapping impls of marker traits (active, overlapping_marker_traits, "1.18.0", Some(29864), None), + // Trait attribute to allow overlapping impls + (active, marker_trait_attr, "1.30.0", Some(29864), None), + // rustc internal (active, abi_thiscall, "1.19.0", None, None), @@ -805,6 +808,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "non exhaustive is an experimental feature", cfg_fn!(non_exhaustive))), + // RFC #1268 + ("marker", Normal, Gated(Stability::Unstable, + "marker_trait_attr", + "marker traits is an experimental feature", + cfg_fn!(marker_trait_attr))), + ("plugin", CrateLevel, Gated(Stability::Unstable, "plugin", "compiler plugins are experimental \ diff --git a/src/test/run-pass/overlap-permitted-for-annotated-marker-traits.rs b/src/test/run-pass/overlap-permitted-for-annotated-marker-traits.rs new file mode 100644 index 0000000000000..e1081032c059a --- /dev/null +++ b/src/test/run-pass/overlap-permitted-for-annotated-marker-traits.rs @@ -0,0 +1,35 @@ +// 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. + +// Tests for RFC 1268: we allow overlapping impls of marker traits, +// that is, traits with #[marker]. In this case, a type `T` is +// `MyMarker` if it is either `Debug` or `Display`. + +#![feature(marker_trait_attr)] + +use std::fmt::{Debug, Display}; + +#[marker] trait MyMarker {} + +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])); +} diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs new file mode 100644 index 0000000000000..508ffe3845bbd --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs @@ -0,0 +1,19 @@ +// 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. + +use std::fmt::{Debug, Display}; + +#[marker] trait ExplicitMarker {} +//~^ ERROR marker traits is an experimental feature (see issue #29864) + +impl ExplicitMarker for T {} +impl ExplicitMarker for T {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr new file mode 100644 index 0000000000000..4023a04000a03 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr @@ -0,0 +1,11 @@ +error[E0658]: marker traits is an experimental feature (see issue #29864) + --> $DIR/feature-gate-marker_trait_attr.rs:13:1 + | +LL | #[marker] trait ExplicitMarker {} + | ^^^^^^^^^ + | + = help: add #![feature(marker_trait_attr)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.rs b/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.rs new file mode 100644 index 0000000000000..4c8003ce3d808 --- /dev/null +++ b/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.rs @@ -0,0 +1,33 @@ +// Copyright 2018 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(marker_trait_attr)] + +#[marker] //~ ERROR attribute can only be applied to a trait +struct Struct {} + +#[marker] //~ ERROR attribute can only be applied to a trait +impl Struct {} + +#[marker] //~ ERROR attribute can only be applied to a trait +union Union { + x: i32, +} + +#[marker] //~ ERROR attribute can only be applied to a trait +const CONST: usize = 10; + +#[marker] //~ ERROR attribute can only be applied to a trait +fn function() {} + +#[marker] //~ ERROR attribute can only be applied to a trait +type Type = (); + +fn main() {} diff --git a/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr b/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr new file mode 100644 index 0000000000000..0e2586b9799d9 --- /dev/null +++ b/src/test/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr @@ -0,0 +1,52 @@ +error: attribute can only be applied to a trait + --> $DIR/marker-attribute-on-non-trait.rs:13:1 + | +LL | #[marker] //~ ERROR attribute can only be applied to a trait + | ^^^^^^^^^ +LL | struct Struct {} + | ---------------- not a trait + +error: attribute can only be applied to a trait + --> $DIR/marker-attribute-on-non-trait.rs:16:1 + | +LL | #[marker] //~ ERROR attribute can only be applied to a trait + | ^^^^^^^^^ +LL | impl Struct {} + | -------------- not a trait + +error: attribute can only be applied to a trait + --> $DIR/marker-attribute-on-non-trait.rs:19:1 + | +LL | #[marker] //~ ERROR attribute can only be applied to a trait + | ^^^^^^^^^ +LL | / union Union { +LL | | x: i32, +LL | | } + | |_- not a trait + +error: attribute can only be applied to a trait + --> $DIR/marker-attribute-on-non-trait.rs:24:1 + | +LL | #[marker] //~ ERROR attribute can only be applied to a trait + | ^^^^^^^^^ +LL | const CONST: usize = 10; + | ------------------------ not a trait + +error: attribute can only be applied to a trait + --> $DIR/marker-attribute-on-non-trait.rs:27:1 + | +LL | #[marker] //~ ERROR attribute can only be applied to a trait + | ^^^^^^^^^ +LL | fn function() {} + | ---------------- not a trait + +error: attribute can only be applied to a trait + --> $DIR/marker-attribute-on-non-trait.rs:30:1 + | +LL | #[marker] //~ ERROR attribute can only be applied to a trait + | ^^^^^^^^^ +LL | type Type = (); + | --------------- not a trait + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/marker_trait_attr/marker-attribute-with-values.rs b/src/test/ui/marker_trait_attr/marker-attribute-with-values.rs new file mode 100644 index 0000000000000..6290481d60f75 --- /dev/null +++ b/src/test/ui/marker_trait_attr/marker-attribute-with-values.rs @@ -0,0 +1,26 @@ +// Copyright 2018 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(marker_trait_attr)] +#![feature(unrestricted_attribute_tokens)] + +#[marker(always)] +trait Marker1 {} +//~^^ ERROR attribute should be empty + +#[marker("never")] +trait Marker2 {} +//~^^ ERROR attribute should be empty + +#[marker(key = value)] +trait Marker3 {} +//~^^ ERROR attribute should be empty + +fn main() {} diff --git a/src/test/ui/marker_trait_attr/marker-attribute-with-values.stderr b/src/test/ui/marker_trait_attr/marker-attribute-with-values.stderr new file mode 100644 index 0000000000000..66bf2d1c502fb --- /dev/null +++ b/src/test/ui/marker_trait_attr/marker-attribute-with-values.stderr @@ -0,0 +1,20 @@ +error: attribute should be empty + --> $DIR/marker-attribute-with-values.rs:14:1 + | +LL | #[marker(always)] + | ^^^^^^^^^^^^^^^^^ + +error: attribute should be empty + --> $DIR/marker-attribute-with-values.rs:18:1 + | +LL | #[marker("never")] + | ^^^^^^^^^^^^^^^^^^ + +error: attribute should be empty + --> $DIR/marker-attribute-with-values.rs:22:1 + | +LL | #[marker(key = value)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.rs b/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.rs new file mode 100644 index 0000000000000..b4677b6844361 --- /dev/null +++ b/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.rs @@ -0,0 +1,50 @@ +// Copyright 2018 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(marker_trait_attr)] +#![feature(associated_type_defaults)] + +#[marker] +trait MarkerConst { + const N: usize; + //~^ ERROR marker traits cannot have associated items +} + +#[marker] +trait MarkerType { + type Output; + //~^ ERROR marker traits cannot have associated items +} + +#[marker] +trait MarkerFn { + fn foo(); + //~^ ERROR marker traits cannot have associated items +} + +#[marker] +trait MarkerConstWithDefault { + const N: usize = 43; + //~^ ERROR marker traits cannot have associated items +} + +#[marker] +trait MarkerTypeWithDefault { + type Output = (); + //~^ ERROR marker traits cannot have associated items +} + +#[marker] +trait MarkerFnWithDefault { + fn foo() {} + //~^ ERROR marker traits cannot have associated items +} + +fn main() {} diff --git a/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.stderr b/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.stderr new file mode 100644 index 0000000000000..dadf1f02b9a8f --- /dev/null +++ b/src/test/ui/marker_trait_attr/marker-trait-with-associated-items.stderr @@ -0,0 +1,39 @@ +error[E0714]: marker traits cannot have associated items + --> $DIR/marker-trait-with-associated-items.rs:16:5 + | +LL | const N: usize; + | ^^^^^^^^^^^^^^^ + +error[E0714]: marker traits cannot have associated items + --> $DIR/marker-trait-with-associated-items.rs:22:5 + | +LL | type Output; + | ^^^^^^^^^^^^ + +error[E0714]: marker traits cannot have associated items + --> $DIR/marker-trait-with-associated-items.rs:28:5 + | +LL | fn foo(); + | ^^^^^^^^^ + +error[E0714]: marker traits cannot have associated items + --> $DIR/marker-trait-with-associated-items.rs:34:5 + | +LL | const N: usize = 43; + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0714]: marker traits cannot have associated items + --> $DIR/marker-trait-with-associated-items.rs:40:5 + | +LL | type Output = (); + | ^^^^^^^^^^^^^^^^^ + +error[E0714]: marker traits cannot have associated items + --> $DIR/marker-trait-with-associated-items.rs:46:5 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/marker_trait_attr/overlap-marker-trait.rs b/src/test/ui/marker_trait_attr/overlap-marker-trait.rs new file mode 100644 index 0000000000000..a3b4fd6aebacf --- /dev/null +++ b/src/test/ui/marker_trait_attr/overlap-marker-trait.rs @@ -0,0 +1,38 @@ +// Copyright 2018 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 with #[marker]. 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`. + +#![feature(marker_trait_attr)] + +use std::fmt::{Debug, Display}; + +#[marker] 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/ui/marker_trait_attr/overlap-marker-trait.stderr b/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr new file mode 100644 index 0000000000000..a4c4f0629ddd0 --- /dev/null +++ b/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `NotDebugOrDisplay: Marker` is not satisfied + --> $DIR/overlap-marker-trait.rs:37:5 + | +LL | is_marker::(); //~ ERROR + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Marker` is not implemented for `NotDebugOrDisplay` + | +note: required by `is_marker` + --> $DIR/overlap-marker-trait.rs:25:1 + | +LL | fn is_marker() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/marker_trait_attr/override-item-on-marker-trait.rs b/src/test/ui/marker_trait_attr/override-item-on-marker-trait.rs new file mode 100644 index 0000000000000..4a9252b38f27e --- /dev/null +++ b/src/test/ui/marker_trait_attr/override-item-on-marker-trait.rs @@ -0,0 +1,33 @@ +// Copyright 2018 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(marker_trait_attr)] + +#[marker] +trait Marker { + const N: usize = 0; + fn do_something() {} +} + +struct OverrideConst; +impl Marker for OverrideConst { +//~^ ERROR impls for marker traits cannot contain items + const N: usize = 1; +} + +struct OverrideFn; +impl Marker for OverrideFn { +//~^ ERROR impls for marker traits cannot contain items + fn do_something() { + println!("Hello world!"); + } +} + +fn main() {} diff --git a/src/test/ui/marker_trait_attr/override-item-on-marker-trait.stderr b/src/test/ui/marker_trait_attr/override-item-on-marker-trait.stderr new file mode 100644 index 0000000000000..43af997511eea --- /dev/null +++ b/src/test/ui/marker_trait_attr/override-item-on-marker-trait.stderr @@ -0,0 +1,15 @@ +error[E0715]: impls for marker traits cannot contain items + --> $DIR/override-item-on-marker-trait.rs:20:1 + | +LL | impl Marker for OverrideConst { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0715]: impls for marker traits cannot contain items + --> $DIR/override-item-on-marker-trait.rs:26:1 + | +LL | impl Marker for OverrideFn { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0715`.