mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-17 09:23:05 +00:00
Add attributes to allow specializing on traits
This commit is contained in:
parent
a62dd0e3ba
commit
c24b4bf410
@ -90,6 +90,7 @@ impl<T: ?Sized> !Send for *mut T {}
|
||||
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.
|
||||
}
|
||||
|
@ -33,11 +33,33 @@ pub struct TraitDef {
|
||||
/// 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>,
|
||||
@ -52,9 +74,18 @@ impl<'tcx> TraitDef {
|
||||
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(
|
||||
|
@ -530,6 +530,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
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:
|
||||
|
@ -651,6 +651,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||
data.paren_sugar,
|
||||
data.has_auto_impl,
|
||||
data.is_marker,
|
||||
data.specialization_kind,
|
||||
self.def_path_table.def_path_hash(item_id),
|
||||
)
|
||||
}
|
||||
@ -660,6 +661,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||
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"),
|
||||
|
@ -1114,6 +1114,7 @@ impl EncodeContext<'tcx> {
|
||||
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))
|
||||
|
@ -350,6 +350,7 @@ struct TraitData {
|
||||
paren_sugar: bool,
|
||||
has_auto_impl: bool,
|
||||
is_marker: bool,
|
||||
specialization_kind: ty::trait_def::TraitSpecializationKind,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable)]
|
||||
|
@ -453,6 +453,7 @@ symbols! {
|
||||
min_align_of,
|
||||
min_const_fn,
|
||||
min_const_unsafe_fn,
|
||||
min_specialization,
|
||||
mips_target_feature,
|
||||
mmx_target_feature,
|
||||
module,
|
||||
@ -654,6 +655,8 @@ symbols! {
|
||||
rustc_proc_macro_decls,
|
||||
rustc_promotable,
|
||||
rustc_regions,
|
||||
rustc_unsafe_specialization_marker,
|
||||
rustc_specialization_trait,
|
||||
rustc_stable,
|
||||
rustc_std_internal_symbol,
|
||||
rustc_symbol_name,
|
||||
|
@ -4,6 +4,7 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Par
|
||||
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,
|
||||
};
|
||||
@ -412,7 +413,9 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
|
||||
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,
|
||||
|
@ -76,6 +76,22 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt<'_>, impl_def_id: DefId, tra
|
||||
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() {
|
||||
|
@ -1032,8 +1032,23 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TraitDef {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_specialization_trait]
|
||||
pub trait SpecTrait {
|
||||
fn method(&self);
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
// 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() {}
|
@ -0,0 +1,10 @@
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user