1
Fork 0

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

@ -5,7 +5,7 @@ pub use self::StabilityLevel::*;
use crate::ty::{self, DefIdTree, TyCtxt};
use rustc_ast::NodeId;
use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diagnostic};
use rustc_feature::GateIssue;
@ -61,6 +61,7 @@ pub struct Index {
/// are filled by the annotator.
pub stab_map: FxHashMap<LocalDefId, Stability>,
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
pub default_body_stab_map: FxHashMap<LocalDefId, DefaultBodyStability>,
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
/// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
/// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
@ -86,6 +87,10 @@ impl Index {
self.const_stab_map.get(&def_id).copied()
}
pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option<DefaultBodyStability> {
self.default_body_stab_map.get(&def_id).copied()
}
pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
self.depr_map.get(&def_id).cloned()
}
@ -416,6 +421,12 @@ impl<'tcx> TyCtxt<'tcx> {
return EvalResult::Allow;
}
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
return EvalResult::Allow;
}
let stability = self.lookup_stability(def_id);
debug!(
"stability: \
@ -423,12 +434,6 @@ impl<'tcx> TyCtxt<'tcx> {
def_id, span, stability
);
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
return EvalResult::Allow;
}
// Issue #38412: private items lack stability markers.
if skip_stability_check_due_to_privacy(self, def_id) {
return EvalResult::Allow;
@ -492,6 +497,62 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
/// Evaluates the default-impl stability of an item.
///
/// Returns `EvalResult::Allow` if the item's default implementation is stable, or unstable but the corresponding
/// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
/// unstable feature otherwise.
pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResult {
let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
if !is_staged_api {
return EvalResult::Allow;
}
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
return EvalResult::Allow;
}
let stability = self.lookup_default_body_stability(def_id);
debug!(
"body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}"
);
// Issue #38412: private items lack stability markers.
if skip_stability_check_due_to_privacy(self, def_id) {
return EvalResult::Allow;
}
match stability {
Some(DefaultBodyStability {
level: attr::Unstable { reason, issue, is_soft, .. },
feature,
}) => {
if span.allows_unstable(feature) {
debug!("body stability: skipping span={:?} since it is internal", span);
return EvalResult::Allow;
}
if self.features().active(feature) {
return EvalResult::Allow;
}
EvalResult::Deny {
feature,
reason: reason.to_opt_reason(),
issue,
suggestion: None,
is_soft,
}
}
Some(_) => {
// Stable APIs are always ok to call
EvalResult::Allow
}
None => EvalResult::Unmarked,
}
}
/// Checks if an item is stable or error out.
///
/// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not

View file

@ -1094,6 +1094,11 @@ rustc_queries! {
separate_provide_extern
}
query lookup_default_body_stability(def_id: DefId) -> Option<attr::DefaultBodyStability> {
desc { |tcx| "looking up default body stability of `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}
query should_inherit_track_caller(def_id: DefId) -> bool {
desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) }
}

View file

@ -64,6 +64,7 @@ trivially_parameterized_over_tcx! {
rustc_ast::Attribute,
rustc_ast::MacArgs,
rustc_attr::ConstStability,
rustc_attr::DefaultBodyStability,
rustc_attr::Deprecation,
rustc_attr::Stability,
rustc_hir::Constness,