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]`](https://github.com/rust-lang/rust/pull/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 😅
This commit is contained in:
Dylan DPC 2022-08-09 17:34:50 +05:30 committed by GitHub
commit 1dc4858914
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 348 additions and 28 deletions

View file

@ -29,11 +29,16 @@ impl<'tcx> LibFeatureCollector<'tcx> {
}
fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
let stab_attrs =
[sym::stable, sym::unstable, sym::rustc_const_stable, sym::rustc_const_unstable];
let stab_attrs = [
sym::stable,
sym::unstable,
sym::rustc_const_stable,
sym::rustc_const_unstable,
sym::rustc_default_body_unstable,
];
// Find a stability attribute: one of #[stable(…)], #[unstable(…)],
// #[rustc_const_stable(…)], or #[rustc_const_unstable(…)].
// #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable].
if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
let meta_kind = attr.meta_kind();
if let Some(MetaItemKind::List(ref metas)) = meta_kind {
@ -53,8 +58,12 @@ impl<'tcx> LibFeatureCollector<'tcx> {
// This additional check for stability is to make sure we
// don't emit additional, irrelevant errors for malformed
// attributes.
let is_unstable =
matches!(*stab_attr, sym::unstable | sym::rustc_const_unstable);
let is_unstable = matches!(
*stab_attr,
sym::unstable
| sym::rustc_const_unstable
| sym::rustc_default_body_unstable
);
if since.is_some() || is_unstable {
return Some((feature, since, attr.span));
}

View file

@ -1,8 +1,9 @@
//! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes.
use attr::StabilityLevel;
use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason};
use rustc_attr::{
self as attr, ConstStability, Stability, StabilityLevel, Unstable, UnstableReason,
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
@ -161,7 +162,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
return;
}
let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
let mut const_span = None;
let const_stab = const_stab.map(|(const_stab, const_span_node)| {
@ -209,6 +210,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
}
}
if let Some((body_stab, _span)) = body_stab {
// FIXME: check that this item can have body stability
self.index.default_body_stab_map.insert(def_id, body_stab);
debug!(?self.index.default_body_stab_map);
}
let stab = stab.map(|(stab, span)| {
// Error if prohibited, or can't inherit anything from a container.
if kind == AnnotationKind::Prohibited
@ -613,6 +621,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
let mut index = Index {
stab_map: Default::default(),
const_stab_map: Default::default(),
default_body_stab_map: Default::default(),
depr_map: Default::default(),
implications: Default::default(),
};
@ -673,6 +682,9 @@ pub(crate) fn provide(providers: &mut Providers) {
stability_implications: |tcx, _| tcx.stability().implications.clone(),
lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
lookup_default_body_stability: |tcx, id| {
tcx.stability().local_default_body_stability(id.expect_local())
},
lookup_deprecation_entry: |tcx, id| {
tcx.stability().local_deprecation_entry(id.expect_local())
},
@ -723,7 +735,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
let features = self.tcx.features();
if features.staged_api {
let attrs = self.tcx.hir().attrs(item.hir_id());
let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span);
let (stab, const_stab, _) =
attr::find_stability(&self.tcx.sess, attrs, item.span);
// If this impl block has an #[unstable] attribute, give an
// error if all involved types and traits are stable, because