Skip to content

Commit c24b4bf

Browse files
committed
Add attributes to allow specializing on traits
1 parent a62dd0e commit c24b4bf

File tree

13 files changed

+116
-3
lines changed

13 files changed

+116
-3
lines changed

src/libcore/marker.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ impl<T: ?Sized> !Send for *mut T {}
9090
ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>"
9191
)]
9292
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
93+
#[cfg_attr(not(bootstrap), rustc_specialization_trait)]
9394
pub trait Sized {
9495
// Empty.
9596
}

src/librustc/ty/trait_def.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,33 @@ pub struct TraitDef {
3333
/// and thus `impl`s of it are allowed to overlap.
3434
pub is_marker: bool,
3535

36+
/// Used to determine whether the standard library is allowed to specialize
37+
/// on this trait.
38+
pub specialization_kind: TraitSpecializationKind,
39+
3640
/// The ICH of this trait's DefPath, cached here so it doesn't have to be
3741
/// recomputed all the time.
3842
pub def_path_hash: DefPathHash,
3943
}
4044

45+
/// Whether this trait is treated specially by the standard library
46+
/// specialization lint.
47+
#[derive(HashStable, PartialEq, Clone, Copy, RustcEncodable, RustcDecodable)]
48+
pub enum TraitSpecializationKind {
49+
/// The default. Specializing on this trait is not allowed.
50+
None,
51+
/// Specializing on this trait is allowed because it doesn't have any
52+
/// methods. For example `Sized` or `FusedIterator`.
53+
/// Applies to traits with the `rustc_unsafe_specialization_marker`
54+
/// attribute.
55+
Marker,
56+
/// Specializing on this trait is allowed because all of the impls of this
57+
/// trait are "always applicable". Always applicable means that if
58+
/// `X<'x>: T<'y>` for any lifetimes, then `for<'a, 'b> X<'a>: T<'b>`.
59+
/// Applies to traits with the `rustc_specialization_trait` attribute.
60+
AlwaysApplicable,
61+
}
62+
4163
#[derive(Default)]
4264
pub struct TraitImpls {
4365
blanket_impls: Vec<DefId>,
@@ -52,9 +74,18 @@ impl<'tcx> TraitDef {
5274
paren_sugar: bool,
5375
has_auto_impl: bool,
5476
is_marker: bool,
77+
specialization_kind: TraitSpecializationKind,
5578
def_path_hash: DefPathHash,
5679
) -> TraitDef {
57-
TraitDef { def_id, unsafety, paren_sugar, has_auto_impl, is_marker, def_path_hash }
80+
TraitDef {
81+
def_id,
82+
unsafety,
83+
paren_sugar,
84+
has_auto_impl,
85+
is_marker,
86+
specialization_kind,
87+
def_path_hash,
88+
}
5889
}
5990

6091
pub fn ancestors(

src/librustc_feature/builtin_attrs.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
530530
rustc_test_marker, Normal, template!(Word),
531531
"the `#[rustc_test_marker]` attribute is used internally to track tests",
532532
),
533+
rustc_attr!(
534+
rustc_unsafe_specialization_marker, Normal, template!(Word),
535+
"the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations"
536+
),
537+
rustc_attr!(
538+
rustc_specialization_trait, Normal, template!(Word),
539+
"the `#[rustc_specialization_trait]` attribute is used to check specializations"
540+
),
533541

534542
// ==========================================================================
535543
// Internal attributes, Testing:

src/librustc_metadata/rmeta/decoder.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
651651
data.paren_sugar,
652652
data.has_auto_impl,
653653
data.is_marker,
654+
data.specialization_kind,
654655
self.def_path_table.def_path_hash(item_id),
655656
)
656657
}
@@ -660,6 +661,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
660661
false,
661662
false,
662663
false,
664+
ty::trait_def::TraitSpecializationKind::None,
663665
self.def_path_table.def_path_hash(item_id),
664666
),
665667
_ => bug!("def-index does not refer to trait or trait alias"),

src/librustc_metadata/rmeta/encoder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,7 @@ impl EncodeContext<'tcx> {
11141114
paren_sugar: trait_def.paren_sugar,
11151115
has_auto_impl: self.tcx.trait_is_auto(def_id),
11161116
is_marker: trait_def.is_marker,
1117+
specialization_kind: trait_def.specialization_kind,
11171118
};
11181119

11191120
EntryKind::Trait(self.lazy(data))

src/librustc_metadata/rmeta/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ struct TraitData {
350350
paren_sugar: bool,
351351
has_auto_impl: bool,
352352
is_marker: bool,
353+
specialization_kind: ty::trait_def::TraitSpecializationKind,
353354
}
354355

355356
#[derive(RustcEncodable, RustcDecodable)]

src/librustc_span/symbol.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ symbols! {
453453
min_align_of,
454454
min_const_fn,
455455
min_const_unsafe_fn,
456+
min_specialization,
456457
mips_target_feature,
457458
mmx_target_feature,
458459
module,
@@ -654,6 +655,8 @@ symbols! {
654655
rustc_proc_macro_decls,
655656
rustc_promotable,
656657
rustc_regions,
658+
rustc_unsafe_specialization_marker,
659+
rustc_specialization_trait,
657660
rustc_stable,
658661
rustc_std_internal_symbol,
659662
rustc_symbol_name,

src/librustc_typeck/check/wfcheck.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Par
44
use rustc::middle::lang_items;
55
use rustc::session::parse::feature_err;
66
use rustc::ty::subst::{InternalSubsts, Subst};
7+
use rustc::ty::trait_def::TraitSpecializationKind;
78
use rustc::ty::{
89
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
910
};
@@ -412,7 +413,9 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
412413
let trait_def_id = tcx.hir().local_def_id(item.hir_id);
413414

414415
let trait_def = tcx.trait_def(trait_def_id);
415-
if trait_def.is_marker {
416+
if trait_def.is_marker
417+
|| matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker)
418+
{
416419
for associated_def_id in &*tcx.associated_item_def_ids(trait_def_id) {
417420
struct_span_err!(
418421
tcx.sess,

src/librustc_typeck/coherence/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,22 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt<'_>, impl_def_id: DefId, tra
7676
return;
7777
}
7878

79+
if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable =
80+
tcx.trait_def(trait_def_id).specialization_kind
81+
{
82+
if !tcx.features().specialization && !tcx.features().min_specialization {
83+
let span = impl_header_span(tcx, impl_def_id);
84+
tcx.sess
85+
.struct_span_err(
86+
span,
87+
"implementing `rustc_specialization_trait` traits is unstable",
88+
)
89+
.help("add `#![feature(min_specialization)]` to the crate attributes to enable")
90+
.emit();
91+
return;
92+
}
93+
}
94+
7995
let trait_name = if did == li.fn_trait() {
8096
"Fn"
8197
} else if did == li.fn_mut_trait() {

src/librustc_typeck/collect.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1032,8 +1032,23 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TraitDef {
10321032
}
10331033

10341034
let is_marker = tcx.has_attr(def_id, sym::marker);
1035+
let spec_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
1036+
ty::trait_def::TraitSpecializationKind::Marker
1037+
} else if tcx.has_attr(def_id, sym::rustc_specialization_trait) {
1038+
ty::trait_def::TraitSpecializationKind::AlwaysApplicable
1039+
} else {
1040+
ty::trait_def::TraitSpecializationKind::None
1041+
};
10351042
let def_path_hash = tcx.def_path_hash(def_id);
1036-
let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, is_marker, def_path_hash);
1043+
let def = ty::TraitDef::new(
1044+
def_id,
1045+
unsafety,
1046+
paren_sugar,
1047+
is_auto,
1048+
is_marker,
1049+
spec_kind,
1050+
def_path_hash,
1051+
);
10371052
tcx.arena.alloc(def)
10381053
}
10391054

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#![feature(rustc_attrs)]
2+
3+
#[rustc_specialization_trait]
4+
pub trait SpecTrait {
5+
fn method(&self);
6+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Check that specialization traits can't be implemented without a feature.
2+
3+
// gate-test-min_specialization
4+
5+
// aux-build:specialization-trait.rs
6+
7+
extern crate specialization_trait;
8+
9+
struct A {}
10+
11+
impl specialization_trait::SpecTrait for A {
12+
//~^ ERROR implementing `rustc_specialization_trait` traits is unstable
13+
fn method(&self) {}
14+
}
15+
16+
fn main() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: implementing `rustc_specialization_trait` traits is unstable
2+
--> $DIR/impl_specialization_trait.rs:11:1
3+
|
4+
LL | impl specialization_trait::SpecTrait for A {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= help: add `#![feature(min_specialization)]` to the crate attributes to enable
8+
9+
error: aborting due to previous error
10+

0 commit comments

Comments
 (0)