Implement #[rustc_default_body_unstable]
This attribute allows to mark default body of a trait function as unstable. This means that implementing the trait without implementing the function will require enabling unstable feature. This is useful in conjunction with `#[rustc_must_implement_one_of]`, 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.
This commit is contained in:
parent
96b9bb4620
commit
177af47104
14 changed files with 206 additions and 17 deletions
|
@ -417,6 +417,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
|| attr.has_name(sym::stable)
|
|| attr.has_name(sym::stable)
|
||||||
|| attr.has_name(sym::rustc_const_unstable)
|
|| attr.has_name(sym::rustc_const_unstable)
|
||||||
|| attr.has_name(sym::rustc_const_stable)
|
|| attr.has_name(sym::rustc_const_stable)
|
||||||
|
|| attr.has_name(sym::rustc_default_body_unstable)
|
||||||
{
|
{
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
self.sess,
|
self.sess,
|
||||||
|
|
|
@ -131,6 +131,14 @@ impl ConstStability {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the `#[rustc_default_body_unstable]` attribute.
|
||||||
|
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
#[derive(HashStable_Generic)]
|
||||||
|
pub struct DefaultBodyStability {
|
||||||
|
pub level: StabilityLevel,
|
||||||
|
pub feature: Symbol,
|
||||||
|
}
|
||||||
|
|
||||||
/// The available stability levels.
|
/// The available stability levels.
|
||||||
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||||
#[derive(HashStable_Generic)]
|
#[derive(HashStable_Generic)]
|
||||||
|
@ -214,7 +222,8 @@ pub fn find_stability(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
attrs: &[Attribute],
|
attrs: &[Attribute],
|
||||||
item_sp: Span,
|
item_sp: Span,
|
||||||
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) {
|
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
|
||||||
|
{
|
||||||
find_stability_generic(sess, attrs.iter(), item_sp)
|
find_stability_generic(sess, attrs.iter(), item_sp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +231,7 @@ fn find_stability_generic<'a, I>(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
attrs_iter: I,
|
attrs_iter: I,
|
||||||
item_sp: Span,
|
item_sp: Span,
|
||||||
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>)
|
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
|
||||||
where
|
where
|
||||||
I: Iterator<Item = &'a Attribute>,
|
I: Iterator<Item = &'a Attribute>,
|
||||||
{
|
{
|
||||||
|
@ -230,6 +239,7 @@ where
|
||||||
|
|
||||||
let mut stab: Option<(Stability, Span)> = None;
|
let mut stab: Option<(Stability, Span)> = None;
|
||||||
let mut const_stab: Option<(ConstStability, Span)> = None;
|
let mut const_stab: Option<(ConstStability, Span)> = None;
|
||||||
|
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
|
||||||
let mut promotable = false;
|
let mut promotable = false;
|
||||||
let mut allowed_through_unstable_modules = false;
|
let mut allowed_through_unstable_modules = false;
|
||||||
|
|
||||||
|
@ -243,6 +253,7 @@ where
|
||||||
sym::stable,
|
sym::stable,
|
||||||
sym::rustc_promotable,
|
sym::rustc_promotable,
|
||||||
sym::rustc_allowed_through_unstable_modules,
|
sym::rustc_allowed_through_unstable_modules,
|
||||||
|
sym::rustc_default_body_unstable,
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.any(|&s| attr.has_name(s))
|
.any(|&s| attr.has_name(s))
|
||||||
|
@ -280,7 +291,7 @@ where
|
||||||
|
|
||||||
let meta_name = meta.name_or_empty();
|
let meta_name = meta.name_or_empty();
|
||||||
match meta_name {
|
match meta_name {
|
||||||
sym::rustc_const_unstable | sym::unstable => {
|
sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
|
||||||
if meta_name == sym::unstable && stab.is_some() {
|
if meta_name == sym::unstable && stab.is_some() {
|
||||||
handle_errors(
|
handle_errors(
|
||||||
&sess.parse_sess,
|
&sess.parse_sess,
|
||||||
|
@ -295,6 +306,13 @@ where
|
||||||
AttrError::MultipleStabilityLevels,
|
AttrError::MultipleStabilityLevels,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
} else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() {
|
||||||
|
handle_errors(
|
||||||
|
&sess.parse_sess,
|
||||||
|
attr.span,
|
||||||
|
AttrError::MultipleStabilityLevels,
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut feature = None;
|
let mut feature = None;
|
||||||
|
@ -405,11 +423,14 @@ where
|
||||||
};
|
};
|
||||||
if sym::unstable == meta_name {
|
if sym::unstable == meta_name {
|
||||||
stab = Some((Stability { level, feature }, attr.span));
|
stab = Some((Stability { level, feature }, attr.span));
|
||||||
} else {
|
} else if sym::rustc_const_unstable == meta_name {
|
||||||
const_stab = Some((
|
const_stab = Some((
|
||||||
ConstStability { level, feature, promotable: false },
|
ConstStability { level, feature, promotable: false },
|
||||||
attr.span,
|
attr.span,
|
||||||
));
|
));
|
||||||
|
} else {
|
||||||
|
body_stab =
|
||||||
|
Some((DefaultBodyStability { level, feature }, attr.span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, _, _) => {
|
(None, _, _) => {
|
||||||
|
@ -542,7 +563,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(stab, const_stab)
|
(stab, const_stab, body_stab)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
|
pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
|
||||||
|
|
|
@ -772,7 +772,7 @@ impl SyntaxExtension {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| (None, helper_attrs));
|
.unwrap_or_else(|| (None, helper_attrs));
|
||||||
let (stability, const_stability) = attr::find_stability(&sess, attrs, span);
|
let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span);
|
||||||
if let Some((_, sp)) = const_stability {
|
if let Some((_, sp)) = const_stability {
|
||||||
sess.parse_sess
|
sess.parse_sess
|
||||||
.span_diagnostic
|
.span_diagnostic
|
||||||
|
@ -784,6 +784,17 @@ impl SyntaxExtension {
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
if let Some((_, sp)) = body_stability {
|
||||||
|
sess.parse_sess
|
||||||
|
.span_diagnostic
|
||||||
|
.struct_span_err(sp, "macros cannot have body stability attributes")
|
||||||
|
.span_label(sp, "invalid body stability attribute")
|
||||||
|
.span_label(
|
||||||
|
sess.source_map().guess_head_span(span),
|
||||||
|
"body stability attribute affects this macro",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
SyntaxExtension {
|
SyntaxExtension {
|
||||||
kind,
|
kind,
|
||||||
|
|
|
@ -499,6 +499,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
),
|
),
|
||||||
ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
|
ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
|
||||||
ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
|
ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
|
||||||
|
ungated!(
|
||||||
|
rustc_default_body_unstable, Normal,
|
||||||
|
template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk
|
||||||
|
),
|
||||||
gated!(
|
gated!(
|
||||||
allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
|
allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
|
||||||
"allow_internal_unstable side-steps feature gating and stability checks",
|
"allow_internal_unstable side-steps feature gating and stability checks",
|
||||||
|
|
|
@ -207,6 +207,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
||||||
def_ident_span => { table }
|
def_ident_span => { table }
|
||||||
lookup_stability => { table }
|
lookup_stability => { table }
|
||||||
lookup_const_stability => { table }
|
lookup_const_stability => { table }
|
||||||
|
lookup_default_body_stability => { table }
|
||||||
lookup_deprecation_entry => { table }
|
lookup_deprecation_entry => { table }
|
||||||
visibility => { table }
|
visibility => { table }
|
||||||
unused_generic_params => { table }
|
unused_generic_params => { table }
|
||||||
|
|
|
@ -1029,6 +1029,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
if should_encode_stability(def_kind) {
|
if should_encode_stability(def_kind) {
|
||||||
self.encode_stability(def_id);
|
self.encode_stability(def_id);
|
||||||
self.encode_const_stability(def_id);
|
self.encode_const_stability(def_id);
|
||||||
|
self.encode_default_body_stability(def_id);
|
||||||
self.encode_deprecation(def_id);
|
self.encode_deprecation(def_id);
|
||||||
}
|
}
|
||||||
if should_encode_variances(def_kind) {
|
if should_encode_variances(def_kind) {
|
||||||
|
@ -1397,6 +1398,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn encode_default_body_stability(&mut self, def_id: DefId) {
|
||||||
|
debug!("EncodeContext::encode_default_body_stability({:?})", def_id);
|
||||||
|
|
||||||
|
// The query lookup can take a measurable amount of time in crates with many items. Check if
|
||||||
|
// the stability attributes are even enabled before using their queries.
|
||||||
|
if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
|
||||||
|
if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) {
|
||||||
|
record!(self.tables.lookup_default_body_stability[def_id] <- stab)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn encode_deprecation(&mut self, def_id: DefId) {
|
fn encode_deprecation(&mut self, def_id: DefId) {
|
||||||
debug!("EncodeContext::encode_deprecation({:?})", def_id);
|
debug!("EncodeContext::encode_deprecation({:?})", def_id);
|
||||||
if let Some(depr) = self.tcx.lookup_deprecation(def_id) {
|
if let Some(depr) = self.tcx.lookup_deprecation(def_id) {
|
||||||
|
|
|
@ -343,6 +343,7 @@ define_tables! {
|
||||||
def_ident_span: Table<DefIndex, LazyValue<Span>>,
|
def_ident_span: Table<DefIndex, LazyValue<Span>>,
|
||||||
lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
|
lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
|
||||||
lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
|
lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
|
||||||
|
lookup_default_body_stability: Table<DefIndex, LazyValue<attr::DefaultBodyStability>>,
|
||||||
lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
|
lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
|
||||||
// As an optimization, a missing entry indicates an empty `&[]`.
|
// As an optimization, a missing entry indicates an empty `&[]`.
|
||||||
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
|
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
|
||||||
|
|
|
@ -5,7 +5,7 @@ pub use self::StabilityLevel::*;
|
||||||
|
|
||||||
use crate::ty::{self, DefIdTree, TyCtxt};
|
use crate::ty::{self, DefIdTree, TyCtxt};
|
||||||
use rustc_ast::NodeId;
|
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_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::{Applicability, Diagnostic};
|
use rustc_errors::{Applicability, Diagnostic};
|
||||||
use rustc_feature::GateIssue;
|
use rustc_feature::GateIssue;
|
||||||
|
@ -61,6 +61,7 @@ pub struct Index {
|
||||||
/// are filled by the annotator.
|
/// are filled by the annotator.
|
||||||
pub stab_map: FxHashMap<LocalDefId, Stability>,
|
pub stab_map: FxHashMap<LocalDefId, Stability>,
|
||||||
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
|
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
|
||||||
|
pub default_body_stab_map: FxHashMap<LocalDefId, DefaultBodyStability>,
|
||||||
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
|
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
|
||||||
/// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
|
/// 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
|
/// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
|
||||||
|
@ -86,6 +87,10 @@ impl Index {
|
||||||
self.const_stab_map.get(&def_id).copied()
|
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> {
|
pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
|
||||||
self.depr_map.get(&def_id).cloned()
|
self.depr_map.get(&def_id).cloned()
|
||||||
}
|
}
|
||||||
|
@ -492,6 +497,63 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stability = self.lookup_default_body_stability(def_id);
|
||||||
|
debug!(
|
||||||
|
"body stability: inspecting def_id={def_id:?} span={span:?} of stability={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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//let suggestion = suggestion_for_allocator_api(self, def_id, span, feature);
|
||||||
|
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.
|
/// Checks if an item is stable or error out.
|
||||||
///
|
///
|
||||||
/// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
|
/// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
|
||||||
|
|
|
@ -1094,6 +1094,11 @@ rustc_queries! {
|
||||||
separate_provide_extern
|
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 {
|
query should_inherit_track_caller(def_id: DefId) -> bool {
|
||||||
desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) }
|
desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ trivially_parameterized_over_tcx! {
|
||||||
rustc_ast::Attribute,
|
rustc_ast::Attribute,
|
||||||
rustc_ast::MacArgs,
|
rustc_ast::MacArgs,
|
||||||
rustc_attr::ConstStability,
|
rustc_attr::ConstStability,
|
||||||
|
rustc_attr::DefaultBodyStability,
|
||||||
rustc_attr::Deprecation,
|
rustc_attr::Deprecation,
|
||||||
rustc_attr::Stability,
|
rustc_attr::Stability,
|
||||||
rustc_hir::Constness,
|
rustc_hir::Constness,
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
//! A pass that annotates every item and method with its stability level,
|
//! A pass that annotates every item and method with its stability level,
|
||||||
//! propagating default levels lexically from parent to children ast nodes.
|
//! propagating default levels lexically from parent to children ast nodes.
|
||||||
|
|
||||||
use attr::StabilityLevel;
|
use rustc_attr::{
|
||||||
use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason};
|
self as attr, ConstStability, DefaultBodyStability, Stability, StabilityLevel, Unstable,
|
||||||
|
UnstableReason,
|
||||||
|
};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||||
use rustc_errors::{struct_span_err, Applicability};
|
use rustc_errors::{struct_span_err, Applicability};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -89,6 +91,7 @@ struct Annotator<'a, 'tcx> {
|
||||||
index: &'a mut Index,
|
index: &'a mut Index,
|
||||||
parent_stab: Option<Stability>,
|
parent_stab: Option<Stability>,
|
||||||
parent_const_stab: Option<ConstStability>,
|
parent_const_stab: Option<ConstStability>,
|
||||||
|
parent_body_stab: Option<DefaultBodyStability>,
|
||||||
parent_depr: Option<DeprecationEntry>,
|
parent_depr: Option<DeprecationEntry>,
|
||||||
in_trait_impl: bool,
|
in_trait_impl: bool,
|
||||||
}
|
}
|
||||||
|
@ -156,12 +159,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||||
depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
|
depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
visit_children,
|
visit_children,
|
||||||
);
|
);
|
||||||
return;
|
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 mut const_span = None;
|
||||||
|
|
||||||
let const_stab = const_stab.map(|(const_stab, const_span_node)| {
|
let const_stab = const_stab.map(|(const_stab, const_span_node)| {
|
||||||
|
@ -209,6 +213,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let body_stab = body_stab.map(|(body_stab, _span)| {
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
body_stab
|
||||||
|
});
|
||||||
|
|
||||||
let stab = stab.map(|(stab, span)| {
|
let stab = stab.map(|(stab, span)| {
|
||||||
// Error if prohibited, or can't inherit anything from a container.
|
// Error if prohibited, or can't inherit anything from a container.
|
||||||
if kind == AnnotationKind::Prohibited
|
if kind == AnnotationKind::Prohibited
|
||||||
|
@ -286,6 +299,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||||
depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
|
depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
|
||||||
stab,
|
stab,
|
||||||
if inherit_const_stability.yes() { const_stab } else { None },
|
if inherit_const_stability.yes() { const_stab } else { None },
|
||||||
|
body_stab,
|
||||||
visit_children,
|
visit_children,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -295,12 +309,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||||
depr: Option<DeprecationEntry>,
|
depr: Option<DeprecationEntry>,
|
||||||
stab: Option<Stability>,
|
stab: Option<Stability>,
|
||||||
const_stab: Option<ConstStability>,
|
const_stab: Option<ConstStability>,
|
||||||
|
body_stab: Option<DefaultBodyStability>,
|
||||||
f: impl FnOnce(&mut Self),
|
f: impl FnOnce(&mut Self),
|
||||||
) {
|
) {
|
||||||
// These will be `Some` if this item changes the corresponding stability attribute.
|
// These will be `Some` if this item changes the corresponding stability attribute.
|
||||||
let mut replaced_parent_depr = None;
|
let mut replaced_parent_depr = None;
|
||||||
let mut replaced_parent_stab = None;
|
let mut replaced_parent_stab = None;
|
||||||
let mut replaced_parent_const_stab = None;
|
let mut replaced_parent_const_stab = None;
|
||||||
|
let mut replaced_parent_body_stab = None;
|
||||||
|
|
||||||
if let Some(depr) = depr {
|
if let Some(depr) = depr {
|
||||||
replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
|
replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
|
||||||
|
@ -312,6 +328,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||||
replaced_parent_const_stab =
|
replaced_parent_const_stab =
|
||||||
Some(replace(&mut self.parent_const_stab, Some(const_stab)));
|
Some(replace(&mut self.parent_const_stab, Some(const_stab)));
|
||||||
}
|
}
|
||||||
|
if let Some(body_stab) = body_stab {
|
||||||
|
replaced_parent_body_stab = Some(self.parent_body_stab.replace(body_stab));
|
||||||
|
}
|
||||||
|
|
||||||
f(self);
|
f(self);
|
||||||
|
|
||||||
|
@ -324,6 +343,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||||
if let Some(orig_parent_const_stab) = replaced_parent_const_stab {
|
if let Some(orig_parent_const_stab) = replaced_parent_const_stab {
|
||||||
self.parent_const_stab = orig_parent_const_stab;
|
self.parent_const_stab = orig_parent_const_stab;
|
||||||
}
|
}
|
||||||
|
if let Some(orig_parent_body_stab) = replaced_parent_body_stab {
|
||||||
|
self.parent_body_stab = orig_parent_body_stab;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,6 +635,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
|
||||||
let mut index = Index {
|
let mut index = Index {
|
||||||
stab_map: Default::default(),
|
stab_map: Default::default(),
|
||||||
const_stab_map: Default::default(),
|
const_stab_map: Default::default(),
|
||||||
|
default_body_stab_map: Default::default(),
|
||||||
depr_map: Default::default(),
|
depr_map: Default::default(),
|
||||||
implications: Default::default(),
|
implications: Default::default(),
|
||||||
};
|
};
|
||||||
|
@ -623,6 +646,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
|
||||||
index: &mut index,
|
index: &mut index,
|
||||||
parent_stab: None,
|
parent_stab: None,
|
||||||
parent_const_stab: None,
|
parent_const_stab: None,
|
||||||
|
parent_body_stab: None,
|
||||||
parent_depr: None,
|
parent_depr: None,
|
||||||
in_trait_impl: false,
|
in_trait_impl: false,
|
||||||
};
|
};
|
||||||
|
@ -673,6 +697,9 @@ pub(crate) fn provide(providers: &mut Providers) {
|
||||||
stability_implications: |tcx, _| tcx.stability().implications.clone(),
|
stability_implications: |tcx, _| tcx.stability().implications.clone(),
|
||||||
lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
|
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_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| {
|
lookup_deprecation_entry: |tcx, id| {
|
||||||
tcx.stability().local_deprecation_entry(id.expect_local())
|
tcx.stability().local_deprecation_entry(id.expect_local())
|
||||||
},
|
},
|
||||||
|
@ -723,7 +750,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
||||||
let features = self.tcx.features();
|
let features = self.tcx.features();
|
||||||
if features.staged_api {
|
if features.staged_api {
|
||||||
let attrs = self.tcx.hir().attrs(item.hir_id());
|
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
|
// If this impl block has an #[unstable] attribute, give an
|
||||||
// error if all involved types and traits are stable, because
|
// error if all involved types and traits are stable, because
|
||||||
|
|
|
@ -1215,6 +1215,7 @@ symbols! {
|
||||||
rustc_const_unstable,
|
rustc_const_unstable,
|
||||||
rustc_conversion_suggestion,
|
rustc_conversion_suggestion,
|
||||||
rustc_def_path,
|
rustc_def_path,
|
||||||
|
rustc_default_body_unstable,
|
||||||
rustc_diagnostic_item,
|
rustc_diagnostic_item,
|
||||||
rustc_diagnostic_macros,
|
rustc_diagnostic_macros,
|
||||||
rustc_dirty,
|
rustc_dirty,
|
||||||
|
|
|
@ -18,6 +18,7 @@ use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::Obligation;
|
use rustc_infer::traits::Obligation;
|
||||||
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
|
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
|
use rustc_middle::middle::stability::EvalResult;
|
||||||
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
||||||
use rustc_middle::ty::subst::GenericArgKind;
|
use rustc_middle::ty::subst::GenericArgKind;
|
||||||
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
||||||
|
@ -1104,12 +1105,31 @@ fn check_impl_items_against_trait<'tcx>(
|
||||||
missing_items.push(tcx.associated_item(trait_item_id));
|
missing_items.push(tcx.associated_item(trait_item_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(required_items) = &must_implement_one_of {
|
|
||||||
// true if this item is specifically implemented in this impl
|
// true if this item is specifically implemented in this impl
|
||||||
let is_implemented_here = ancestors
|
let is_implemented_here = ancestors
|
||||||
.leaf_def(tcx, trait_item_id)
|
.leaf_def(tcx, trait_item_id)
|
||||||
.map_or(false, |node_item| !node_item.defining_node.is_from_trait());
|
.map_or(false, |node_item| !node_item.defining_node.is_from_trait());
|
||||||
|
|
||||||
|
if !is_implemented_here {
|
||||||
|
match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {
|
||||||
|
EvalResult::Deny { feature, reason, issue, is_soft, .. } => {
|
||||||
|
default_body_is_unstable(
|
||||||
|
tcx,
|
||||||
|
full_impl_span,
|
||||||
|
trait_item_id,
|
||||||
|
feature,
|
||||||
|
reason,
|
||||||
|
issue,
|
||||||
|
is_soft,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarked default bodies are considered stable (at least for now).
|
||||||
|
EvalResult::Allow | EvalResult::Unmarked => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(required_items) = &must_implement_one_of {
|
||||||
if is_implemented_here {
|
if is_implemented_here {
|
||||||
let trait_item = tcx.associated_item(trait_item_id);
|
let trait_item = tcx.associated_item(trait_item_id);
|
||||||
if required_items.contains(&trait_item.ident(tcx)) {
|
if required_items.contains(&trait_item.ident(tcx)) {
|
||||||
|
|
|
@ -99,6 +99,7 @@ pub use expectation::Expectation;
|
||||||
pub use fn_ctxt::*;
|
pub use fn_ctxt::*;
|
||||||
use hir::def::CtorOf;
|
use hir::def::CtorOf;
|
||||||
pub use inherited::{Inherited, InheritedBuilder};
|
pub use inherited::{Inherited, InheritedBuilder};
|
||||||
|
use rustc_middle::middle::stability::report_unstable;
|
||||||
|
|
||||||
use crate::astconv::AstConv;
|
use crate::astconv::AstConv;
|
||||||
use crate::check::gather_locals::GatherLocalsVisitor;
|
use crate::check::gather_locals::GatherLocalsVisitor;
|
||||||
|
@ -122,13 +123,14 @@ use rustc_session::parse::feature_err;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::source_map::DUMMY_SP;
|
use rustc_span::source_map::DUMMY_SP;
|
||||||
use rustc_span::symbol::{kw, Ident};
|
use rustc_span::symbol::{kw, Ident};
|
||||||
use rustc_span::{self, BytePos, Span};
|
use rustc_span::{self, BytePos, Span, Symbol};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
|
use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
|
||||||
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
|
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
use crate::require_c_abi_if_c_variadic;
|
use crate::require_c_abi_if_c_variadic;
|
||||||
use crate::util::common::indenter;
|
use crate::util::common::indenter;
|
||||||
|
@ -662,6 +664,24 @@ fn missing_items_must_implement_one_of_err(
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_body_is_unstable(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
impl_span: Span,
|
||||||
|
_item_did: DefId,
|
||||||
|
feature: Symbol,
|
||||||
|
reason: Option<Symbol>,
|
||||||
|
issue: Option<NonZeroU32>,
|
||||||
|
is_soft: bool,
|
||||||
|
) {
|
||||||
|
let soft_handler = |lint, span, msg: &_| {
|
||||||
|
tcx.struct_span_lint_hir(lint, hir::CRATE_HIR_ID, span, |lint| {
|
||||||
|
lint.build(msg).emit();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
report_unstable(tcx.sess, feature, reason, issue, None, is_soft, impl_span, soft_handler)
|
||||||
|
}
|
||||||
|
|
||||||
/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
|
/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
|
||||||
fn bounds_from_generic_predicates<'tcx>(
|
fn bounds_from_generic_predicates<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue