Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1dc4858

Browse files
authoredAug 9, 2022
Rollup merge of #96478 - WaffleLapkin:rustc_default_body_unstable, r=Aaron1011
Implement `#[rustc_default_body_unstable]` This PR implements a new stability attribute — `#[rustc_default_body_unstable]`. `#[rustc_default_body_unstable]` controls the stability of default bodies in traits. For example: ```rust pub trait Trait { #[rustc_default_body_unstable(feature = "feat", isssue = "none")] fn item() {} } ``` In order to implement `Trait` user needs to either - implement `item` (even though it has a default implementation) - enable `#![feature(feat)]` This is useful in conjunction with [`#[rustc_must_implement_one_of]`](#92164), we may want to relax requirements for a trait, for example allowing implementing either of `PartialEq::{eq, ne}`, but do so in a safe way — making implementation of only `PartialEq::ne` unstable. r? `@Aaron1011` cc `@nrc` (iirc you were interested in this wrt `read_buf`), `@danielhenrymantilla` (you were interested in the related `#[rustc_must_implement_one_of]`) P.S. This is my first time working with stability attributes, so I'm not sure if I did everything right 😅
2 parents 5af97e8 + 95bf0fb commit 1dc4858

File tree

22 files changed

+348
-28
lines changed

22 files changed

+348
-28
lines changed
 

‎Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4626,6 +4626,7 @@ dependencies = [
46264626
"rustc_attr",
46274627
"rustc_data_structures",
46284628
"rustc_errors",
4629+
"rustc_feature",
46294630
"rustc_graphviz",
46304631
"rustc_hir",
46314632
"rustc_hir_pretty",

‎compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
417417
|| attr.has_name(sym::stable)
418418
|| attr.has_name(sym::rustc_const_unstable)
419419
|| attr.has_name(sym::rustc_const_stable)
420+
|| attr.has_name(sym::rustc_default_body_unstable)
420421
{
421422
struct_span_err!(
422423
self.sess,

‎compiler/rustc_attr/src/builtin.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ impl ConstStability {
131131
}
132132
}
133133

134+
/// Represents the `#[rustc_default_body_unstable]` attribute.
135+
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
136+
#[derive(HashStable_Generic)]
137+
pub struct DefaultBodyStability {
138+
pub level: StabilityLevel,
139+
pub feature: Symbol,
140+
}
141+
134142
/// The available stability levels.
135143
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
136144
#[derive(HashStable_Generic)]
@@ -214,22 +222,24 @@ pub fn find_stability(
214222
sess: &Session,
215223
attrs: &[Attribute],
216224
item_sp: Span,
217-
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) {
225+
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
226+
{
218227
find_stability_generic(sess, attrs.iter(), item_sp)
219228
}
220229

221230
fn find_stability_generic<'a, I>(
222231
sess: &Session,
223232
attrs_iter: I,
224233
item_sp: Span,
225-
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>)
234+
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
226235
where
227236
I: Iterator<Item = &'a Attribute>,
228237
{
229238
use StabilityLevel::*;
230239

231240
let mut stab: Option<(Stability, Span)> = None;
232241
let mut const_stab: Option<(ConstStability, Span)> = None;
242+
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
233243
let mut promotable = false;
234244
let mut allowed_through_unstable_modules = false;
235245

@@ -243,6 +253,7 @@ where
243253
sym::stable,
244254
sym::rustc_promotable,
245255
sym::rustc_allowed_through_unstable_modules,
256+
sym::rustc_default_body_unstable,
246257
]
247258
.iter()
248259
.any(|&s| attr.has_name(s))
@@ -280,7 +291,7 @@ where
280291

281292
let meta_name = meta.name_or_empty();
282293
match meta_name {
283-
sym::rustc_const_unstable | sym::unstable => {
294+
sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
284295
if meta_name == sym::unstable && stab.is_some() {
285296
handle_errors(
286297
&sess.parse_sess,
@@ -295,6 +306,13 @@ where
295306
AttrError::MultipleStabilityLevels,
296307
);
297308
break;
309+
} else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() {
310+
handle_errors(
311+
&sess.parse_sess,
312+
attr.span,
313+
AttrError::MultipleStabilityLevels,
314+
);
315+
break;
298316
}
299317

300318
let mut feature = None;
@@ -405,11 +423,16 @@ where
405423
};
406424
if sym::unstable == meta_name {
407425
stab = Some((Stability { level, feature }, attr.span));
408-
} else {
426+
} else if sym::rustc_const_unstable == meta_name {
409427
const_stab = Some((
410428
ConstStability { level, feature, promotable: false },
411429
attr.span,
412430
));
431+
} else if sym::rustc_default_body_unstable == meta_name {
432+
body_stab =
433+
Some((DefaultBodyStability { level, feature }, attr.span));
434+
} else {
435+
unreachable!("Unknown stability attribute {meta_name}");
413436
}
414437
}
415438
(None, _, _) => {
@@ -542,7 +565,7 @@ where
542565
}
543566
}
544567

545-
(stab, const_stab)
568+
(stab, const_stab, body_stab)
546569
}
547570

548571
pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {

‎compiler/rustc_expand/src/base.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,7 @@ impl SyntaxExtension {
772772
)
773773
})
774774
.unwrap_or_else(|| (None, helper_attrs));
775-
let (stability, const_stability) = attr::find_stability(&sess, attrs, span);
775+
let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span);
776776
if let Some((_, sp)) = const_stability {
777777
sess.parse_sess
778778
.span_diagnostic
@@ -784,6 +784,17 @@ impl SyntaxExtension {
784784
)
785785
.emit();
786786
}
787+
if let Some((_, sp)) = body_stability {
788+
sess.parse_sess
789+
.span_diagnostic
790+
.struct_span_err(sp, "macros cannot have body stability attributes")
791+
.span_label(sp, "invalid body stability attribute")
792+
.span_label(
793+
sess.source_map().guess_head_span(span),
794+
"body stability attribute affects this macro",
795+
)
796+
.emit();
797+
}
787798

788799
SyntaxExtension {
789800
kind,

‎compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
499499
),
500500
ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
501501
ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
502+
ungated!(
503+
rustc_default_body_unstable, Normal,
504+
template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk
505+
),
502506
gated!(
503507
allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
504508
"allow_internal_unstable side-steps feature gating and stability checks",

‎compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
207207
def_ident_span => { table }
208208
lookup_stability => { table }
209209
lookup_const_stability => { table }
210+
lookup_default_body_stability => { table }
210211
lookup_deprecation_entry => { table }
211212
visibility => { table }
212213
unused_generic_params => { table }

‎compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
10291029
if should_encode_stability(def_kind) {
10301030
self.encode_stability(def_id);
10311031
self.encode_const_stability(def_id);
1032+
self.encode_default_body_stability(def_id);
10321033
self.encode_deprecation(def_id);
10331034
}
10341035
if should_encode_variances(def_kind) {
@@ -1385,6 +1386,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
13851386
}
13861387
}
13871388

1389+
fn encode_default_body_stability(&mut self, def_id: DefId) {
1390+
debug!("EncodeContext::encode_default_body_stability({:?})", def_id);
1391+
1392+
// The query lookup can take a measurable amount of time in crates with many items. Check if
1393+
// the stability attributes are even enabled before using their queries.
1394+
if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
1395+
if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) {
1396+
record!(self.tables.lookup_default_body_stability[def_id] <- stab)
1397+
}
1398+
}
1399+
}
1400+
13881401
fn encode_deprecation(&mut self, def_id: DefId) {
13891402
debug!("EncodeContext::encode_deprecation({:?})", def_id);
13901403
if let Some(depr) = self.tcx.lookup_deprecation(def_id) {

‎compiler/rustc_metadata/src/rmeta/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ define_tables! {
343343
def_ident_span: Table<DefIndex, LazyValue<Span>>,
344344
lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
345345
lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
346+
lookup_default_body_stability: Table<DefIndex, LazyValue<attr::DefaultBodyStability>>,
346347
lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
347348
// As an optimization, a missing entry indicates an empty `&[]`.
348349
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,

‎compiler/rustc_middle/src/middle/stability.rs

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub use self::StabilityLevel::*;
55

66
use crate::ty::{self, DefIdTree, TyCtxt};
77
use rustc_ast::NodeId;
8-
use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
8+
use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability};
99
use rustc_data_structures::fx::FxHashMap;
1010
use rustc_errors::{Applicability, Diagnostic};
1111
use rustc_feature::GateIssue;
@@ -61,6 +61,7 @@ pub struct Index {
6161
/// are filled by the annotator.
6262
pub stab_map: FxHashMap<LocalDefId, Stability>,
6363
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
64+
pub default_body_stab_map: FxHashMap<LocalDefId, DefaultBodyStability>,
6465
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
6566
/// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
6667
/// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
@@ -86,6 +87,10 @@ impl Index {
8687
self.const_stab_map.get(&def_id).copied()
8788
}
8889

90+
pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option<DefaultBodyStability> {
91+
self.default_body_stab_map.get(&def_id).copied()
92+
}
93+
8994
pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
9095
self.depr_map.get(&def_id).cloned()
9196
}
@@ -416,19 +421,19 @@ impl<'tcx> TyCtxt<'tcx> {
416421
return EvalResult::Allow;
417422
}
418423

424+
// Only the cross-crate scenario matters when checking unstable APIs
425+
let cross_crate = !def_id.is_local();
426+
if !cross_crate {
427+
return EvalResult::Allow;
428+
}
429+
419430
let stability = self.lookup_stability(def_id);
420431
debug!(
421432
"stability: \
422433
inspecting def_id={:?} span={:?} of stability={:?}",
423434
def_id, span, stability
424435
);
425436

426-
// Only the cross-crate scenario matters when checking unstable APIs
427-
let cross_crate = !def_id.is_local();
428-
if !cross_crate {
429-
return EvalResult::Allow;
430-
}
431-
432437
// Issue #38412: private items lack stability markers.
433438
if skip_stability_check_due_to_privacy(self, def_id) {
434439
return EvalResult::Allow;
@@ -492,6 +497,62 @@ impl<'tcx> TyCtxt<'tcx> {
492497
}
493498
}
494499

500+
/// Evaluates the default-impl stability of an item.
501+
///
502+
/// Returns `EvalResult::Allow` if the item's default implementation is stable, or unstable but the corresponding
503+
/// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
504+
/// unstable feature otherwise.
505+
pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResult {
506+
let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
507+
if !is_staged_api {
508+
return EvalResult::Allow;
509+
}
510+
511+
// Only the cross-crate scenario matters when checking unstable APIs
512+
let cross_crate = !def_id.is_local();
513+
if !cross_crate {
514+
return EvalResult::Allow;
515+
}
516+
517+
let stability = self.lookup_default_body_stability(def_id);
518+
debug!(
519+
"body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}"
520+
);
521+
522+
// Issue #38412: private items lack stability markers.
523+
if skip_stability_check_due_to_privacy(self, def_id) {
524+
return EvalResult::Allow;
525+
}
526+
527+
match stability {
528+
Some(DefaultBodyStability {
529+
level: attr::Unstable { reason, issue, is_soft, .. },
530+
feature,
531+
}) => {
532+
if span.allows_unstable(feature) {
533+
debug!("body stability: skipping span={:?} since it is internal", span);
534+
return EvalResult::Allow;
535+
}
536+
if self.features().active(feature) {
537+
return EvalResult::Allow;
538+
}
539+
540+
EvalResult::Deny {
541+
feature,
542+
reason: reason.to_opt_reason(),
543+
issue,
544+
suggestion: None,
545+
is_soft,
546+
}
547+
}
548+
Some(_) => {
549+
// Stable APIs are always ok to call
550+
EvalResult::Allow
551+
}
552+
None => EvalResult::Unmarked,
553+
}
554+
}
555+
495556
/// Checks if an item is stable or error out.
496557
///
497558
/// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not

‎compiler/rustc_middle/src/query/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,11 @@ rustc_queries! {
10941094
separate_provide_extern
10951095
}
10961096

1097+
query lookup_default_body_stability(def_id: DefId) -> Option<attr::DefaultBodyStability> {
1098+
desc { |tcx| "looking up default body stability of `{}`", tcx.def_path_str(def_id) }
1099+
separate_provide_extern
1100+
}
1101+
10971102
query should_inherit_track_caller(def_id: DefId) -> bool {
10981103
desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) }
10991104
}

‎compiler/rustc_middle/src/ty/parameterized.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ trivially_parameterized_over_tcx! {
6464
rustc_ast::Attribute,
6565
rustc_ast::MacArgs,
6666
rustc_attr::ConstStability,
67+
rustc_attr::DefaultBodyStability,
6768
rustc_attr::Deprecation,
6869
rustc_attr::Stability,
6970
rustc_hir::Constness,

‎compiler/rustc_passes/src/lib_features.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,16 @@ impl<'tcx> LibFeatureCollector<'tcx> {
2929
}
3030

3131
fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
32-
let stab_attrs =
33-
[sym::stable, sym::unstable, sym::rustc_const_stable, sym::rustc_const_unstable];
32+
let stab_attrs = [
33+
sym::stable,
34+
sym::unstable,
35+
sym::rustc_const_stable,
36+
sym::rustc_const_unstable,
37+
sym::rustc_default_body_unstable,
38+
];
3439

3540
// Find a stability attribute: one of #[stable(…)], #[unstable(…)],
36-
// #[rustc_const_stable(…)], or #[rustc_const_unstable(…)].
41+
// #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable].
3742
if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
3843
let meta_kind = attr.meta_kind();
3944
if let Some(MetaItemKind::List(ref metas)) = meta_kind {
@@ -53,8 +58,12 @@ impl<'tcx> LibFeatureCollector<'tcx> {
5358
// This additional check for stability is to make sure we
5459
// don't emit additional, irrelevant errors for malformed
5560
// attributes.
56-
let is_unstable =
57-
matches!(*stab_attr, sym::unstable | sym::rustc_const_unstable);
61+
let is_unstable = matches!(
62+
*stab_attr,
63+
sym::unstable
64+
| sym::rustc_const_unstable
65+
| sym::rustc_default_body_unstable
66+
);
5867
if since.is_some() || is_unstable {
5968
return Some((feature, since, attr.span));
6069
}

‎compiler/rustc_passes/src/stability.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//! A pass that annotates every item and method with its stability level,
22
//! propagating default levels lexically from parent to children ast nodes.
33
4-
use attr::StabilityLevel;
5-
use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason};
4+
use rustc_attr::{
5+
self as attr, ConstStability, Stability, StabilityLevel, Unstable, UnstableReason,
6+
};
67
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
78
use rustc_errors::{struct_span_err, Applicability};
89
use rustc_hir as hir;
@@ -161,7 +162,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
161162
return;
162163
}
163164

164-
let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
165+
let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
165166
let mut const_span = None;
166167

167168
let const_stab = const_stab.map(|(const_stab, const_span_node)| {
@@ -209,6 +210,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
209210
}
210211
}
211212

213+
if let Some((body_stab, _span)) = body_stab {
214+
// FIXME: check that this item can have body stability
215+
216+
self.index.default_body_stab_map.insert(def_id, body_stab);
217+
debug!(?self.index.default_body_stab_map);
218+
}
219+
212220
let stab = stab.map(|(stab, span)| {
213221
// Error if prohibited, or can't inherit anything from a container.
214222
if kind == AnnotationKind::Prohibited
@@ -613,6 +621,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
613621
let mut index = Index {
614622
stab_map: Default::default(),
615623
const_stab_map: Default::default(),
624+
default_body_stab_map: Default::default(),
616625
depr_map: Default::default(),
617626
implications: Default::default(),
618627
};
@@ -673,6 +682,9 @@ pub(crate) fn provide(providers: &mut Providers) {
673682
stability_implications: |tcx, _| tcx.stability().implications.clone(),
674683
lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
675684
lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
685+
lookup_default_body_stability: |tcx, id| {
686+
tcx.stability().local_default_body_stability(id.expect_local())
687+
},
676688
lookup_deprecation_entry: |tcx, id| {
677689
tcx.stability().local_deprecation_entry(id.expect_local())
678690
},
@@ -723,7 +735,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
723735
let features = self.tcx.features();
724736
if features.staged_api {
725737
let attrs = self.tcx.hir().attrs(item.hir_id());
726-
let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span);
738+
let (stab, const_stab, _) =
739+
attr::find_stability(&self.tcx.sess, attrs, item.span);
727740

728741
// If this impl block has an #[unstable] attribute, give an
729742
// error if all involved types and traits are stable, because

‎compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,7 @@ symbols! {
12181218
rustc_conversion_suggestion,
12191219
rustc_deallocator,
12201220
rustc_def_path,
1221+
rustc_default_body_unstable,
12211222
rustc_diagnostic_item,
12221223
rustc_diagnostic_macros,
12231224
rustc_dirty,

‎compiler/rustc_typeck/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" }
3030
rustc_lint = { path = "../rustc_lint" }
3131
rustc_serialize = { path = "../rustc_serialize" }
3232
rustc_type_ir = { path = "../rustc_type_ir" }
33+
rustc_feature = { path = "../rustc_feature" }

‎compiler/rustc_typeck/src/check/check.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
1818
use rustc_infer::traits::Obligation;
1919
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
2020
use rustc_middle::hir::nested_filter;
21+
use rustc_middle::middle::stability::EvalResult;
2122
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
2223
use rustc_middle::ty::subst::GenericArgKind;
2324
use rustc_middle::ty::util::{Discr, IntTypeExt};
@@ -1103,12 +1104,28 @@ fn check_impl_items_against_trait<'tcx>(
11031104
missing_items.push(tcx.associated_item(trait_item_id));
11041105
}
11051106

1106-
if let Some(required_items) = &must_implement_one_of {
1107-
// true if this item is specifically implemented in this impl
1108-
let is_implemented_here = ancestors
1109-
.leaf_def(tcx, trait_item_id)
1110-
.map_or(false, |node_item| !node_item.defining_node.is_from_trait());
1107+
// true if this item is specifically implemented in this impl
1108+
let is_implemented_here = ancestors
1109+
.leaf_def(tcx, trait_item_id)
1110+
.map_or(false, |node_item| !node_item.defining_node.is_from_trait());
1111+
1112+
if !is_implemented_here {
1113+
match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {
1114+
EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable(
1115+
tcx,
1116+
full_impl_span,
1117+
trait_item_id,
1118+
feature,
1119+
reason,
1120+
issue,
1121+
),
11111122

1123+
// Unmarked default bodies are considered stable (at least for now).
1124+
EvalResult::Allow | EvalResult::Unmarked => {}
1125+
}
1126+
}
1127+
1128+
if let Some(required_items) = &must_implement_one_of {
11121129
if is_implemented_here {
11131130
let trait_item = tcx.associated_item(trait_item_id);
11141131
if required_items.contains(&trait_item.ident(tcx)) {

‎compiler/rustc_typeck/src/check/mod.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,14 @@ use rustc_session::parse::feature_err;
121121
use rustc_session::Session;
122122
use rustc_span::source_map::DUMMY_SP;
123123
use rustc_span::symbol::{kw, Ident};
124-
use rustc_span::{self, BytePos, Span};
124+
use rustc_span::{self, BytePos, Span, Symbol};
125125
use rustc_target::abi::VariantIdx;
126126
use rustc_target::spec::abi::Abi;
127127
use rustc_trait_selection::traits;
128128
use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
129129
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
130130
use std::cell::RefCell;
131+
use std::num::NonZeroU32;
131132

132133
use crate::require_c_abi_if_c_variadic;
133134
use crate::util::common::indenter;
@@ -661,6 +662,37 @@ fn missing_items_must_implement_one_of_err(
661662
err.emit();
662663
}
663664

665+
fn default_body_is_unstable(
666+
tcx: TyCtxt<'_>,
667+
impl_span: Span,
668+
item_did: DefId,
669+
feature: Symbol,
670+
reason: Option<Symbol>,
671+
issue: Option<NonZeroU32>,
672+
) {
673+
let missing_item_name = &tcx.associated_item(item_did).name;
674+
let use_of_unstable_library_feature_note = match reason {
675+
Some(r) => format!("use of unstable library feature '{feature}': {r}"),
676+
None => format!("use of unstable library feature '{feature}'"),
677+
};
678+
679+
let mut err = struct_span_err!(
680+
tcx.sess,
681+
impl_span,
682+
E0046,
683+
"not all trait items implemented, missing: `{missing_item_name}`",
684+
);
685+
err.note(format!("default implementation of `{missing_item_name}` is unstable"));
686+
err.note(use_of_unstable_library_feature_note);
687+
rustc_session::parse::add_feature_diagnostics_for_issue(
688+
&mut err,
689+
&tcx.sess.parse_sess,
690+
feature,
691+
rustc_feature::GateIssue::Library(issue),
692+
);
693+
err.emit();
694+
}
695+
664696
/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
665697
fn bounds_from_generic_predicates<'tcx>(
666698
tcx: TyCtxt<'tcx>,
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#![crate_type = "lib"]
2+
#![feature(staged_api, rustc_attrs)]
3+
#![stable(feature = "stable_feature", since = "1.0.0")]
4+
5+
#[stable(feature = "stable_feature", since = "1.0.0")]
6+
pub trait JustTrait {
7+
#[stable(feature = "stable_feature", since = "1.0.0")]
8+
#[rustc_default_body_unstable(feature = "constant_default_body", issue = "none")]
9+
const CONSTANT: usize = 0;
10+
11+
#[rustc_default_body_unstable(feature = "fun_default_body", issue = "none")]
12+
#[stable(feature = "stable_feature", since = "1.0.0")]
13+
fn fun() {}
14+
}
15+
16+
#[rustc_must_implement_one_of(eq, neq)]
17+
#[stable(feature = "stable_feature", since = "1.0.0")]
18+
pub trait Equal {
19+
#[rustc_default_body_unstable(feature = "eq_default_body", issue = "none")]
20+
#[stable(feature = "stable_feature", since = "1.0.0")]
21+
fn eq(&self, other: &Self) -> bool {
22+
!self.neq(other)
23+
}
24+
25+
#[stable(feature = "stable_feature", since = "1.0.0")]
26+
fn neq(&self, other: &Self) -> bool {
27+
!self.eq(other)
28+
}
29+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// aux-build:default_body.rs
2+
#![crate_type = "lib"]
3+
4+
extern crate default_body;
5+
6+
use default_body::{Equal, JustTrait};
7+
8+
struct Type;
9+
10+
impl JustTrait for Type {}
11+
//~^ ERROR not all trait items implemented, missing: `CONSTANT` [E0046]
12+
//~| ERROR not all trait items implemented, missing: `fun` [E0046]
13+
14+
impl Equal for Type {
15+
//~^ ERROR not all trait items implemented, missing: `eq` [E0046]
16+
fn neq(&self, other: &Self) -> bool {
17+
false
18+
}
19+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error[E0046]: not all trait items implemented, missing: `CONSTANT`
2+
--> $DIR/default-body-stability-err.rs:10:1
3+
|
4+
LL | impl JustTrait for Type {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: default implementation of `CONSTANT` is unstable
8+
= note: use of unstable library feature 'constant_default_body'
9+
= help: add `#![feature(constant_default_body)]` to the crate attributes to enable
10+
11+
error[E0046]: not all trait items implemented, missing: `fun`
12+
--> $DIR/default-body-stability-err.rs:10:1
13+
|
14+
LL | impl JustTrait for Type {}
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
|
17+
= note: default implementation of `fun` is unstable
18+
= note: use of unstable library feature 'fun_default_body'
19+
= help: add `#![feature(fun_default_body)]` to the crate attributes to enable
20+
21+
error[E0046]: not all trait items implemented, missing: `eq`
22+
--> $DIR/default-body-stability-err.rs:14:1
23+
|
24+
LL | / impl Equal for Type {
25+
LL | |
26+
LL | | fn neq(&self, other: &Self) -> bool {
27+
LL | | false
28+
LL | | }
29+
LL | | }
30+
| |_^
31+
|
32+
= note: default implementation of `eq` is unstable
33+
= note: use of unstable library feature 'eq_default_body'
34+
= help: add `#![feature(eq_default_body)]` to the crate attributes to enable
35+
36+
error: aborting due to 3 previous errors
37+
38+
For more information about this error, try `rustc --explain E0046`.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// check-pass
2+
// aux-build:default_body.rs
3+
#![crate_type = "lib"]
4+
#![feature(fun_default_body, eq_default_body, constant_default_body)]
5+
6+
extern crate default_body;
7+
8+
use default_body::{Equal, JustTrait};
9+
10+
struct Type;
11+
12+
impl JustTrait for Type {}
13+
14+
impl Equal for Type {
15+
fn neq(&self, other: &Self) -> bool {
16+
false
17+
}
18+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// check-pass
2+
// aux-build:default_body.rs
3+
#![crate_type = "lib"]
4+
5+
extern crate default_body;
6+
7+
use default_body::{Equal, JustTrait};
8+
9+
struct Type;
10+
11+
impl JustTrait for Type {
12+
const CONSTANT: usize = 1;
13+
14+
fn fun() {}
15+
}
16+
17+
impl Equal for Type {
18+
fn eq(&self, other: &Self) -> bool {
19+
false
20+
}
21+
}

0 commit comments

Comments
 (0)
Please sign in to comment.