Skip to content

Commit 646e667

Browse files
committed
add a #[rustc_coinductive] attribute
1 parent e9ab787 commit 646e667

File tree

7 files changed

+44
-33
lines changed

7 files changed

+44
-33
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -682,14 +682,17 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
682682
"language items are subject to change",
683683
),
684684
rustc_attr!(
685-
rustc_pass_by_value, Normal,
686-
template!(Word), ErrorFollowing,
685+
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
687686
"#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
688687
),
689688
rustc_attr!(
690689
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true,
691690
"#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
692691
),
692+
rustc_attr!(
693+
rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, @only_local: true,
694+
"#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver."
695+
),
693696
rustc_attr!(
694697
rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true,
695698
"#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -934,9 +934,10 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
934934
}
935935

936936
let is_marker = tcx.has_attr(def_id, sym::marker);
937+
let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
937938
let skip_array_during_method_dispatch =
938939
tcx.has_attr(def_id, sym::rustc_skip_array_during_method_dispatch);
939-
let spec_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
940+
let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
940941
ty::trait_def::TraitSpecializationKind::Marker
941942
} else if tcx.has_attr(def_id, sym::rustc_specialization_trait) {
942943
ty::trait_def::TraitSpecializationKind::AlwaysApplicable
@@ -1036,16 +1037,17 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
10361037
no_dups.then_some(list)
10371038
});
10381039

1039-
ty::TraitDef::new(
1040+
ty::TraitDef {
10401041
def_id,
10411042
unsafety,
10421043
paren_sugar,
1043-
is_auto,
1044+
has_auto_impl: is_auto,
10441045
is_marker,
1046+
is_coinductive: rustc_coinductive || is_auto,
10451047
skip_array_during_method_dispatch,
1046-
spec_kind,
1048+
specialization_kind,
10471049
must_implement_one_of,
1048-
)
1050+
}
10491051
}
10501052

10511053
fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2388,15 +2388,17 @@ impl<'tcx> TyCtxt<'tcx> {
23882388
self.trait_def(trait_def_id).has_auto_impl
23892389
}
23902390

2391+
/// Returns `true` if this is coinductive, either because it is
2392+
/// an auto trait or because it has the `#[rustc_coinductive]` attribute.
2393+
pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
2394+
self.trait_def(trait_def_id).is_coinductive
2395+
}
2396+
23912397
/// Returns `true` if this is a trait alias.
23922398
pub fn trait_is_alias(self, trait_def_id: DefId) -> bool {
23932399
self.def_kind(trait_def_id) == DefKind::TraitAlias
23942400
}
23952401

2396-
pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
2397-
self.trait_is_auto(trait_def_id) || self.lang_items().sized_trait() == Some(trait_def_id)
2398-
}
2399-
24002402
/// Returns layout of a generator. Layout might be unavailable if the
24012403
/// generator is tainted by errors.
24022404
pub fn generator_layout(self, def_id: DefId) -> Option<&'tcx GeneratorLayout<'tcx>> {

compiler/rustc_middle/src/ty/trait_def.rs

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ pub struct TraitDef {
3131
/// and thus `impl`s of it are allowed to overlap.
3232
pub is_marker: bool,
3333

34+
/// If `true`, then this trait has to `#[rustc_coinductive]` attribute or
35+
/// is an auto trait. This indicates that trait solver cycles involving an
36+
/// `X: ThisTrait` goal are accepted.
37+
///
38+
/// In the future all traits should be coinductive, but we need a better
39+
/// formal understanding of what exactly that means and should probably
40+
/// also have already switched to the new trait solver.
41+
pub is_coinductive: bool,
42+
3443
/// If `true`, then this trait has the `#[rustc_skip_array_during_method_dispatch]`
3544
/// attribute, indicating that editions before 2021 should not consider this trait
3645
/// during method dispatch if the receiver is an array.
@@ -81,28 +90,6 @@ impl TraitImpls {
8190
}
8291

8392
impl<'tcx> TraitDef {
84-
pub fn new(
85-
def_id: DefId,
86-
unsafety: hir::Unsafety,
87-
paren_sugar: bool,
88-
has_auto_impl: bool,
89-
is_marker: bool,
90-
skip_array_during_method_dispatch: bool,
91-
specialization_kind: TraitSpecializationKind,
92-
must_implement_one_of: Option<Box<[Ident]>>,
93-
) -> TraitDef {
94-
TraitDef {
95-
def_id,
96-
unsafety,
97-
paren_sugar,
98-
has_auto_impl,
99-
is_marker,
100-
skip_array_during_method_dispatch,
101-
specialization_kind,
102-
must_implement_one_of,
103-
}
104-
}
105-
10693
pub fn ancestors(
10794
&self,
10895
tcx: TyCtxt<'tcx>,

compiler/rustc_passes/src/check_attr.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ impl CheckAttrVisitor<'_> {
156156
| sym::rustc_dirty
157157
| sym::rustc_if_this_changed
158158
| sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr),
159+
sym::rustc_coinductive => self.check_rustc_coinductive(&attr, span, target),
159160
sym::cmse_nonsecure_entry => {
160161
self.check_cmse_nonsecure_entry(hir_id, attr, span, target)
161162
}
@@ -1608,6 +1609,20 @@ impl CheckAttrVisitor<'_> {
16081609
}
16091610
}
16101611

1612+
/// Checks if the `#[rustc_coinductive]` attribute is applied to a trait.
1613+
fn check_rustc_coinductive(&self, attr: &Attribute, span: Span, target: Target) -> bool {
1614+
match target {
1615+
Target::Trait => true,
1616+
_ => {
1617+
self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait {
1618+
attr_span: attr.span,
1619+
defn_span: span,
1620+
});
1621+
false
1622+
}
1623+
}
1624+
}
1625+
16111626
/// Checks if `#[link_section]` is applied to a function or static.
16121627
fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
16131628
match target {

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,7 @@ symbols! {
12241224
rustc_capture_analysis,
12251225
rustc_clean,
12261226
rustc_coherence_is_core,
1227+
rustc_coinductive,
12271228
rustc_const_stable,
12281229
rustc_const_unstable,
12291230
rustc_conversion_suggestion,

library/core/src/marker.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ unsafe impl<T: Sync + ?Sized> Send for &T {}
9797
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
9898
#[rustc_specialization_trait]
9999
#[rustc_deny_explicit_impl]
100+
#[cfg_attr(not(bootstrap), rustc_coinductive)]
100101
pub trait Sized {
101102
// Empty.
102103
}

0 commit comments

Comments
 (0)