ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>"
)]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
+#[cfg_attr(not(bootstrap), rustc_specialization_trait)]
pub trait Sized {
// Empty.
}
/// and thus `impl`s of it are allowed to overlap.
pub is_marker: bool,
+ /// Used to determine whether the standard library is allowed to specialize
+ /// on this trait.
+ pub specialization_kind: TraitSpecializationKind,
+
/// 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,
}
+/// Whether this trait is treated specially by the standard library
+/// specialization lint.
+#[derive(HashStable, PartialEq, Clone, Copy, RustcEncodable, RustcDecodable)]
+pub enum TraitSpecializationKind {
+ /// The default. Specializing on this trait is not allowed.
+ None,
+ /// Specializing on this trait is allowed because it doesn't have any
+ /// methods. For example `Sized` or `FusedIterator`.
+ /// Applies to traits with the `rustc_unsafe_specialization_marker`
+ /// attribute.
+ Marker,
+ /// Specializing on this trait is allowed because all of the impls of this
+ /// trait are "always applicable". Always applicable means that if
+ /// `X<'x>: T<'y>` for any lifetimes, then `for<'a, 'b> X<'a>: T<'b>`.
+ /// Applies to traits with the `rustc_specialization_trait` attribute.
+ AlwaysApplicable,
+}
+
#[derive(Default)]
pub struct TraitImpls {
blanket_impls: Vec<DefId>,
paren_sugar: bool,
has_auto_impl: bool,
is_marker: bool,
+ specialization_kind: TraitSpecializationKind,
def_path_hash: DefPathHash,
) -> TraitDef {
- TraitDef { def_id, unsafety, paren_sugar, has_auto_impl, is_marker, def_path_hash }
+ TraitDef {
+ def_id,
+ unsafety,
+ paren_sugar,
+ has_auto_impl,
+ is_marker,
+ specialization_kind,
+ def_path_hash,
+ }
}
pub fn ancestors(
rustc_test_marker, Normal, template!(Word),
"the `#[rustc_test_marker]` attribute is used internally to track tests",
),
+ rustc_attr!(
+ rustc_unsafe_specialization_marker, Normal, template!(Word),
+ "the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations"
+ ),
+ rustc_attr!(
+ rustc_specialization_trait, Normal, template!(Word),
+ "the `#[rustc_specialization_trait]` attribute is used to check specializations"
+ ),
// ==========================================================================
// Internal attributes, Testing:
data.paren_sugar,
data.has_auto_impl,
data.is_marker,
+ data.specialization_kind,
self.def_path_table.def_path_hash(item_id),
)
}
false,
false,
false,
+ ty::trait_def::TraitSpecializationKind::None,
self.def_path_table.def_path_hash(item_id),
),
_ => bug!("def-index does not refer to trait or trait alias"),
paren_sugar: trait_def.paren_sugar,
has_auto_impl: self.tcx.trait_is_auto(def_id),
is_marker: trait_def.is_marker,
+ specialization_kind: trait_def.specialization_kind,
};
EntryKind::Trait(self.lazy(data))
paren_sugar: bool,
has_auto_impl: bool,
is_marker: bool,
+ specialization_kind: ty::trait_def::TraitSpecializationKind,
}
#[derive(RustcEncodable, RustcDecodable)]
min_align_of,
min_const_fn,
min_const_unsafe_fn,
+ min_specialization,
mips_target_feature,
mmx_target_feature,
module,
rustc_proc_macro_decls,
rustc_promotable,
rustc_regions,
+ rustc_unsafe_specialization_marker,
+ rustc_specialization_trait,
rustc_stable,
rustc_std_internal_symbol,
rustc_symbol_name,
use rustc::middle::lang_items;
use rustc::session::parse::feature_err;
use rustc::ty::subst::{InternalSubsts, Subst};
+use rustc::ty::trait_def::TraitSpecializationKind;
use rustc::ty::{
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
};
let trait_def_id = tcx.hir().local_def_id(item.hir_id);
let trait_def = tcx.trait_def(trait_def_id);
- if trait_def.is_marker {
+ if trait_def.is_marker
+ || matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker)
+ {
for associated_def_id in &*tcx.associated_item_def_ids(trait_def_id) {
struct_span_err!(
tcx.sess,
return;
}
+ if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable =
+ tcx.trait_def(trait_def_id).specialization_kind
+ {
+ if !tcx.features().specialization && !tcx.features().min_specialization {
+ let span = impl_header_span(tcx, impl_def_id);
+ tcx.sess
+ .struct_span_err(
+ span,
+ "implementing `rustc_specialization_trait` traits is unstable",
+ )
+ .help("add `#![feature(min_specialization)]` to the crate attributes to enable")
+ .emit();
+ return;
+ }
+ }
+
let trait_name = if did == li.fn_trait() {
"Fn"
} else if did == li.fn_mut_trait() {
}
let is_marker = tcx.has_attr(def_id, sym::marker);
+ let spec_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
+ ty::trait_def::TraitSpecializationKind::Marker
+ } else if tcx.has_attr(def_id, sym::rustc_specialization_trait) {
+ ty::trait_def::TraitSpecializationKind::AlwaysApplicable
+ } else {
+ ty::trait_def::TraitSpecializationKind::None
+ };
let def_path_hash = tcx.def_path_hash(def_id);
- let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, is_marker, def_path_hash);
+ let def = ty::TraitDef::new(
+ def_id,
+ unsafety,
+ paren_sugar,
+ is_auto,
+ is_marker,
+ spec_kind,
+ def_path_hash,
+ );
tcx.arena.alloc(def)
}
--- /dev/null
+#![feature(rustc_attrs)]
+
+#[rustc_specialization_trait]
+pub trait SpecTrait {
+ fn method(&self);
+}
--- /dev/null
+// Check that specialization traits can't be implemented without a feature.
+
+// gate-test-min_specialization
+
+// aux-build:specialization-trait.rs
+
+extern crate specialization_trait;
+
+struct A {}
+
+impl specialization_trait::SpecTrait for A {
+ //~^ ERROR implementing `rustc_specialization_trait` traits is unstable
+ fn method(&self) {}
+}
+
+fn main() {}
--- /dev/null
+error: implementing `rustc_specialization_trait` traits is unstable
+ --> $DIR/impl_specialization_trait.rs:11:1
+ |
+LL | impl specialization_trait::SpecTrait for A {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add `#![feature(min_specialization)]` to the crate attributes to enable
+
+error: aborting due to previous error
+