Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-12 00:23:11 +00:00
|
|
|
//! A pass that annotates every item and method with its stability level,
|
|
|
|
//! propagating default levels lexically from parent to children ast nodes.
|
|
|
|
|
2024-07-28 22:13:50 +00:00
|
|
|
use std::mem::replace;
|
|
|
|
use std::num::NonZero;
|
|
|
|
|
2025-02-05 19:18:18 +00:00
|
|
|
use rustc_ast_lowering::stability::extern_abi_stability;
|
2024-12-13 13:47:11 +00:00
|
|
|
use rustc_attr_parsing::{
|
2025-02-09 21:49:33 +00:00
|
|
|
self as attr, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability, Stability,
|
|
|
|
StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr,
|
2022-04-27 14:14:19 +00:00
|
|
|
};
|
2023-12-21 09:52:27 +00:00
|
|
|
use rustc_data_structures::fx::FxIndexMap;
|
|
|
|
use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
|
2024-10-24 15:53:08 +00:00
|
|
|
use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature};
|
2020-01-05 01:37:57 +00:00
|
|
|
use rustc_hir::def::{DefKind, Res};
|
2024-09-22 23:05:04 +00:00
|
|
|
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
|
2021-08-26 16:42:08 +00:00
|
|
|
use rustc_hir::hir_id::CRATE_HIR_ID;
|
2025-01-11 19:12:36 +00:00
|
|
|
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
|
|
|
|
use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
|
2021-11-03 23:03:12 +00:00
|
|
|
use rustc_middle::hir::nested_filter;
|
2023-09-23 05:38:49 +00:00
|
|
|
use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
|
2022-09-22 13:19:53 +00:00
|
|
|
use rustc_middle::middle::privacy::EffectiveVisibilities;
|
2025-01-01 18:09:01 +00:00
|
|
|
use rustc_middle::middle::stability::{
|
|
|
|
AllowUnstable, Deprecated, DeprecationEntry, EvalResult, Index,
|
|
|
|
};
|
2023-05-15 04:24:45 +00:00
|
|
|
use rustc_middle::query::Providers;
|
|
|
|
use rustc_middle::ty::TyCtxt;
|
2025-01-01 18:09:01 +00:00
|
|
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
2020-03-11 11:49:08 +00:00
|
|
|
use rustc_session::lint;
|
2025-01-01 18:09:01 +00:00
|
|
|
use rustc_session::lint::builtin::{
|
|
|
|
DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED,
|
|
|
|
};
|
2024-12-12 23:29:23 +00:00
|
|
|
use rustc_span::{Span, Symbol, sym};
|
2024-05-22 03:47:35 +00:00
|
|
|
use tracing::{debug, info};
|
2014-09-12 10:10:30 +00:00
|
|
|
|
2024-07-28 22:13:50 +00:00
|
|
|
use crate::errors;
|
|
|
|
|
2015-11-16 16:53:41 +00:00
|
|
|
#[derive(PartialEq)]
|
|
|
|
enum AnnotationKind {
|
2022-07-13 09:09:37 +00:00
|
|
|
/// Annotation is required if not inherited from unstable parents.
|
2015-11-16 18:01:06 +00:00
|
|
|
Required,
|
2022-07-13 09:09:37 +00:00
|
|
|
/// Annotation is useless, reject it.
|
2015-11-16 18:01:06 +00:00
|
|
|
Prohibited,
|
2022-07-13 09:09:37 +00:00
|
|
|
/// Deprecation annotation is useless, reject it. (Stability attribute is still required.)
|
2020-10-31 14:34:10 +00:00
|
|
|
DeprecationProhibited,
|
2022-07-13 09:09:37 +00:00
|
|
|
/// Annotation itself is useless, but it can be propagated to children.
|
2015-11-16 18:01:06 +00:00
|
|
|
Container,
|
2015-11-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
2020-07-08 19:31:48 +00:00
|
|
|
/// Whether to inherit deprecation flags for nested items. In most cases, we do want to inherit
|
|
|
|
/// deprecation, because nested items rarely have individual deprecation attributes, and so
|
|
|
|
/// should be treated as deprecated if their parent is. However, default generic parameters
|
|
|
|
/// have separate deprecation attributes from their parents, so we do not wish to inherit
|
|
|
|
/// deprecation in this case. For example, inheriting deprecation for `T` in `Foo<T>`
|
|
|
|
/// would cause a duplicate warning arising from both `Foo` and `T` being deprecated.
|
2020-09-23 02:54:52 +00:00
|
|
|
#[derive(Clone)]
|
2020-07-05 23:02:30 +00:00
|
|
|
enum InheritDeprecation {
|
|
|
|
Yes,
|
|
|
|
No,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InheritDeprecation {
|
|
|
|
fn yes(&self) -> bool {
|
2020-07-08 19:51:31 +00:00
|
|
|
matches!(self, InheritDeprecation::Yes)
|
2020-07-05 23:02:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-16 19:59:21 +00:00
|
|
|
/// Whether to inherit const stability flags for nested items. In most cases, we do not want to
|
|
|
|
/// inherit const stability: just because an enclosing `fn` is const-stable does not mean
|
|
|
|
/// all `extern` imports declared in it should be const-stable! However, trait methods
|
|
|
|
/// inherit const stability attributes from their parent and do not have their own.
|
|
|
|
enum InheritConstStability {
|
|
|
|
Yes,
|
|
|
|
No,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InheritConstStability {
|
|
|
|
fn yes(&self) -> bool {
|
|
|
|
matches!(self, InheritConstStability::Yes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-23 18:15:04 +00:00
|
|
|
enum InheritStability {
|
|
|
|
Yes,
|
|
|
|
No,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InheritStability {
|
|
|
|
fn yes(&self) -> bool {
|
|
|
|
matches!(self, InheritStability::Yes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-13 09:09:37 +00:00
|
|
|
/// A private tree-walker for producing an `Index`.
|
2019-06-14 16:39:39 +00:00
|
|
|
struct Annotator<'a, 'tcx> {
|
2019-06-13 21:48:52 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2022-02-19 14:36:11 +00:00
|
|
|
index: &'a mut Index,
|
|
|
|
parent_stab: Option<Stability>,
|
|
|
|
parent_const_stab: Option<ConstStability>,
|
2016-08-04 13:18:36 +00:00
|
|
|
parent_depr: Option<DeprecationEntry>,
|
2015-11-16 16:53:41 +00:00
|
|
|
in_trait_impl: bool,
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-12 00:23:11 +00:00
|
|
|
}
|
|
|
|
|
2019-06-14 16:39:39 +00:00
|
|
|
impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
2022-07-13 09:09:37 +00:00
|
|
|
/// Determine the stability for a node based on its attributes and inherited stability. The
|
|
|
|
/// stability is recorded in the index and used as the parent. If the node is a function,
|
|
|
|
/// `fn_sig` is its signature.
|
2019-12-22 22:42:04 +00:00
|
|
|
fn annotate<F>(
|
|
|
|
&mut self,
|
2021-07-28 15:23:40 +00:00
|
|
|
def_id: LocalDefId,
|
2019-12-22 22:42:04 +00:00
|
|
|
item_sp: Span,
|
2021-07-03 10:07:06 +00:00
|
|
|
fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
|
2019-12-22 22:42:04 +00:00
|
|
|
kind: AnnotationKind,
|
2020-07-05 23:02:30 +00:00
|
|
|
inherit_deprecation: InheritDeprecation,
|
2021-01-16 19:59:21 +00:00
|
|
|
inherit_const_stability: InheritConstStability,
|
2020-04-23 18:15:04 +00:00
|
|
|
inherit_from_parent: InheritStability,
|
2019-12-22 22:42:04 +00:00
|
|
|
visit_children: F,
|
|
|
|
) where
|
|
|
|
F: FnOnce(&mut Self),
|
2014-12-09 01:26:43 +00:00
|
|
|
{
|
2025-02-21 07:33:05 +00:00
|
|
|
let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
|
2021-07-28 15:23:40 +00:00
|
|
|
debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
|
2020-02-07 17:56:56 +00:00
|
|
|
|
2025-02-09 21:49:33 +00:00
|
|
|
let depr = attr::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span));
|
|
|
|
let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect);
|
|
|
|
|
2020-07-20 14:44:43 +00:00
|
|
|
let mut is_deprecated = false;
|
2020-11-01 11:29:57 +00:00
|
|
|
if let Some((depr, span)) = &depr {
|
2020-07-20 14:44:43 +00:00
|
|
|
is_deprecated = true;
|
2020-02-07 18:24:22 +00:00
|
|
|
|
2023-01-30 12:01:09 +00:00
|
|
|
if matches!(kind, AnnotationKind::Prohibited | AnnotationKind::DeprecationProhibited) {
|
2023-11-24 16:28:19 +00:00
|
|
|
let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
|
2024-01-16 05:27:02 +00:00
|
|
|
self.tcx.emit_node_span_lint(
|
2022-09-14 18:03:12 +00:00
|
|
|
USELESS_DEPRECATED,
|
|
|
|
hir_id,
|
|
|
|
*span,
|
|
|
|
errors::DeprecatedAnnotationHasNoEffect { span: *span },
|
|
|
|
);
|
2020-07-20 14:44:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// `Deprecation` is just two pointers, no need to intern it
|
2022-04-13 20:51:34 +00:00
|
|
|
let depr_entry = DeprecationEntry::local(*depr, def_id);
|
2021-07-28 15:23:40 +00:00
|
|
|
self.index.depr_map.insert(def_id, depr_entry);
|
2022-04-13 20:51:34 +00:00
|
|
|
} else if let Some(parent_depr) = self.parent_depr {
|
2020-07-05 23:02:30 +00:00
|
|
|
if inherit_deprecation.yes() {
|
2020-05-18 03:00:19 +00:00
|
|
|
is_deprecated = true;
|
2021-07-28 15:23:40 +00:00
|
|
|
info!("tagging child {:?} as deprecated from parent", def_id);
|
|
|
|
self.index.depr_map.insert(def_id, parent_depr);
|
2020-05-18 03:00:19 +00:00
|
|
|
}
|
2020-07-20 14:44:43 +00:00
|
|
|
}
|
|
|
|
|
2024-10-09 07:01:57 +00:00
|
|
|
if !self.tcx.features().staged_api() {
|
2022-11-16 20:34:16 +00:00
|
|
|
// Propagate unstability. This can happen even for non-staged-api crates in case
|
2022-01-18 19:37:14 +00:00
|
|
|
// -Zforce-unstable-if-unmarked is set.
|
|
|
|
if let Some(stab) = self.parent_stab {
|
2022-02-08 09:52:11 +00:00
|
|
|
if inherit_deprecation.yes() && stab.is_unstable() {
|
2022-01-18 19:37:14 +00:00
|
|
|
self.index.stab_map.insert(def_id, stab);
|
2024-11-02 19:15:18 +00:00
|
|
|
if fn_sig.is_some_and(|s| s.header.is_const()) {
|
2025-02-09 21:49:33 +00:00
|
|
|
self.index.const_stab_map.insert(
|
|
|
|
def_id,
|
|
|
|
ConstStability::unmarked(const_stability_indirect, stab),
|
|
|
|
);
|
2024-11-02 19:15:18 +00:00
|
|
|
}
|
2022-01-18 19:37:14 +00:00
|
|
|
}
|
2020-07-20 14:44:43 +00:00
|
|
|
}
|
2022-01-18 19:37:14 +00:00
|
|
|
|
2020-07-20 14:44:43 +00:00
|
|
|
self.recurse_with_stability_attrs(
|
2021-07-28 15:23:40 +00:00
|
|
|
depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
|
2020-07-20 14:44:43 +00:00
|
|
|
None,
|
|
|
|
None,
|
|
|
|
visit_children,
|
2020-02-07 17:56:56 +00:00
|
|
|
);
|
2020-07-20 14:44:43 +00:00
|
|
|
return;
|
2020-02-07 17:56:56 +00:00
|
|
|
}
|
2020-02-07 18:24:22 +00:00
|
|
|
|
2024-11-02 20:19:21 +00:00
|
|
|
// # Regular and body stability
|
2025-02-09 21:49:33 +00:00
|
|
|
let stab = attr::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span));
|
|
|
|
let body_stab =
|
|
|
|
attr::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability);
|
2020-02-07 18:24:22 +00:00
|
|
|
|
2023-11-13 13:24:55 +00:00
|
|
|
if let Some((depr, span)) = &depr
|
|
|
|
&& depr.is_since_rustc_version()
|
|
|
|
&& stab.is_none()
|
|
|
|
{
|
2023-12-18 11:21:37 +00:00
|
|
|
self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: *span });
|
2020-07-20 14:44:43 +00:00
|
|
|
}
|
|
|
|
|
2025-02-09 21:49:33 +00:00
|
|
|
if let Some(body_stab) = body_stab {
|
2022-04-27 14:14:19 +00:00
|
|
|
// 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);
|
2022-07-31 12:29:31 +00:00
|
|
|
}
|
2022-04-27 14:14:19 +00:00
|
|
|
|
2021-02-11 05:35:27 +00:00
|
|
|
let stab = stab.map(|(stab, span)| {
|
2020-02-07 17:56:56 +00:00
|
|
|
// Error if prohibited, or can't inherit anything from a container.
|
|
|
|
if kind == AnnotationKind::Prohibited
|
2020-07-20 14:44:43 +00:00
|
|
|
|| (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
|
2020-02-07 17:56:56 +00:00
|
|
|
{
|
2023-12-18 11:21:37 +00:00
|
|
|
self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp });
|
2019-12-08 00:43:10 +00:00
|
|
|
}
|
2015-06-06 22:52:28 +00:00
|
|
|
|
2020-02-07 17:56:56 +00:00
|
|
|
debug!("annotate: found {:?}", stab);
|
|
|
|
|
|
|
|
// Check if deprecated_since < stable_since. If it is,
|
|
|
|
// this is *almost surely* an accident.
|
2023-10-26 17:14:29 +00:00
|
|
|
if let (
|
|
|
|
&Some(DeprecatedSince::RustcVersion(dep_since)),
|
2024-12-07 14:27:17 +00:00
|
|
|
&attr::StabilityLevel::Stable { since: stab_since, .. },
|
2023-10-30 22:51:26 +00:00
|
|
|
) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level)
|
2020-02-07 17:56:56 +00:00
|
|
|
{
|
2023-10-24 04:59:22 +00:00
|
|
|
match stab_since {
|
2023-10-26 17:08:39 +00:00
|
|
|
StableSince::Current => {
|
2023-12-18 11:21:37 +00:00
|
|
|
self.tcx
|
|
|
|
.dcx()
|
|
|
|
.emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
|
2023-10-24 04:59:22 +00:00
|
|
|
}
|
2023-10-26 17:08:39 +00:00
|
|
|
StableSince::Version(stab_since) => {
|
2023-10-26 17:14:29 +00:00
|
|
|
if dep_since < stab_since {
|
|
|
|
self.tcx
|
2023-12-18 11:21:37 +00:00
|
|
|
.dcx()
|
2023-10-26 17:14:29 +00:00
|
|
|
.emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
|
2023-10-24 04:59:22 +00:00
|
|
|
}
|
2015-06-12 00:18:46 +00:00
|
|
|
}
|
2023-10-26 17:08:39 +00:00
|
|
|
StableSince::Err => {
|
2023-10-24 06:06:52 +00:00
|
|
|
// An error already reported. Assume the unparseable stabilization
|
|
|
|
// version is older than the deprecation version.
|
|
|
|
}
|
2015-11-16 16:53:41 +00:00
|
|
|
}
|
2020-02-07 17:56:56 +00:00
|
|
|
}
|
2015-06-12 00:18:46 +00:00
|
|
|
|
2024-10-06 17:59:19 +00:00
|
|
|
// Stable *language* features shouldn't be used as unstable library features.
|
|
|
|
// (Not doing this for stable library features is checked by tidy.)
|
2024-12-07 14:27:17 +00:00
|
|
|
if let Stability { level: StabilityLevel::Unstable { .. }, feature } = stab {
|
2024-10-23 07:20:02 +00:00
|
|
|
if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
|
2024-10-11 20:05:58 +00:00
|
|
|
self.tcx
|
|
|
|
.dcx()
|
|
|
|
.emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp });
|
|
|
|
}
|
|
|
|
}
|
2024-12-07 14:27:17 +00:00
|
|
|
if let Stability {
|
|
|
|
level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. },
|
|
|
|
feature,
|
|
|
|
} = stab
|
2022-10-03 03:22:46 +00:00
|
|
|
{
|
2022-07-13 14:10:19 +00:00
|
|
|
self.index.implications.insert(implied_by, feature);
|
|
|
|
}
|
|
|
|
|
2021-07-28 15:23:40 +00:00
|
|
|
self.index.stab_map.insert(def_id, stab);
|
2020-02-07 18:24:22 +00:00
|
|
|
stab
|
|
|
|
});
|
2015-11-16 16:53:41 +00:00
|
|
|
|
2020-02-07 18:24:22 +00:00
|
|
|
if stab.is_none() {
|
|
|
|
debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
|
2017-08-20 14:49:03 +00:00
|
|
|
if let Some(stab) = self.parent_stab {
|
2022-02-08 09:52:11 +00:00
|
|
|
if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() {
|
2021-07-28 15:23:40 +00:00
|
|
|
self.index.stab_map.insert(def_id, stab);
|
2017-08-20 14:49:03 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-07 18:24:22 +00:00
|
|
|
}
|
|
|
|
|
2024-11-02 20:19:21 +00:00
|
|
|
let final_stab = self.index.stab_map.get(&def_id);
|
|
|
|
|
|
|
|
// # Const stability
|
|
|
|
|
2025-02-09 21:49:33 +00:00
|
|
|
let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span));
|
2024-11-02 20:19:21 +00:00
|
|
|
|
|
|
|
// If the current node is a function with const stability attributes (directly given or
|
2025-02-09 21:49:33 +00:00
|
|
|
// implied), check if the function/method is const or the parent impl block is const.
|
2024-11-02 20:19:21 +00:00
|
|
|
if let Some(fn_sig) = fn_sig
|
|
|
|
&& !fn_sig.header.is_const()
|
|
|
|
&& const_stab.is_some()
|
|
|
|
{
|
|
|
|
self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this is marked const *stable*, it must also be regular-stable.
|
|
|
|
if let Some((const_stab, const_span)) = const_stab
|
|
|
|
&& let Some(fn_sig) = fn_sig
|
|
|
|
&& const_stab.is_const_stable()
|
|
|
|
&& !stab.is_some_and(|s| s.is_stable())
|
|
|
|
{
|
|
|
|
self.tcx
|
|
|
|
.dcx()
|
|
|
|
.emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stable *language* features shouldn't be used as unstable library features.
|
|
|
|
// (Not doing this for stable library features is checked by tidy.)
|
2024-12-07 14:27:17 +00:00
|
|
|
if let Some((
|
2025-02-09 21:49:33 +00:00
|
|
|
PartialConstStability { level: StabilityLevel::Unstable { .. }, feature, .. },
|
2024-12-07 14:27:17 +00:00
|
|
|
const_span,
|
|
|
|
)) = const_stab
|
2024-11-02 20:19:21 +00:00
|
|
|
{
|
|
|
|
if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
|
|
|
|
self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
|
|
|
|
span: const_span,
|
|
|
|
item_sp,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-09 21:49:33 +00:00
|
|
|
if let Some((stab, span)) = &const_stab
|
|
|
|
&& stab.is_const_stable()
|
|
|
|
&& const_stability_indirect
|
|
|
|
{
|
|
|
|
self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span: *span });
|
|
|
|
}
|
|
|
|
|
2024-11-02 20:19:21 +00:00
|
|
|
// After checking the immediate attributes, get rid of the span and compute implied
|
|
|
|
// const stability: inherit feature gate from regular stability.
|
2025-02-09 21:49:33 +00:00
|
|
|
let mut const_stab = const_stab
|
|
|
|
.map(|(stab, _span)| ConstStability::from_partial(stab, const_stability_indirect));
|
2024-11-02 20:19:21 +00:00
|
|
|
|
|
|
|
// If this is a const fn but not annotated with stability markers, see if we can inherit regular stability.
|
2025-02-07 13:58:08 +00:00
|
|
|
if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() &&
|
2024-11-02 20:19:21 +00:00
|
|
|
// We only ever inherit unstable features.
|
|
|
|
let Some(inherit_regular_stab) =
|
|
|
|
final_stab.filter(|s| s.is_unstable())
|
|
|
|
{
|
|
|
|
const_stab = Some(ConstStability {
|
|
|
|
// We subject these implicitly-const functions to recursive const stability.
|
|
|
|
const_stable_indirect: true,
|
|
|
|
promotable: false,
|
|
|
|
level: inherit_regular_stab.level,
|
|
|
|
feature: inherit_regular_stab.feature,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that everything is computed, insert it into the table.
|
|
|
|
const_stab.inspect(|const_stab| {
|
|
|
|
self.index.const_stab_map.insert(def_id, *const_stab);
|
|
|
|
});
|
|
|
|
|
|
|
|
if let Some(ConstStability {
|
2024-12-07 14:27:17 +00:00
|
|
|
level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. },
|
2024-11-02 20:19:21 +00:00
|
|
|
feature,
|
|
|
|
..
|
|
|
|
}) = const_stab
|
|
|
|
{
|
|
|
|
self.index.implications.insert(implied_by, feature);
|
|
|
|
}
|
|
|
|
|
|
|
|
// `impl const Trait for Type` items forward their const stability to their
|
|
|
|
// immediate children.
|
|
|
|
// FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`?
|
|
|
|
// Currently, once that is set, we do not inherit anything from the parent any more.
|
|
|
|
if const_stab.is_none() {
|
|
|
|
debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
|
|
|
|
if let Some(parent) = self.parent_const_stab {
|
|
|
|
if parent.is_const_unstable() {
|
|
|
|
self.index.const_stab_map.insert(def_id, parent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-20 14:44:43 +00:00
|
|
|
self.recurse_with_stability_attrs(
|
2021-07-28 15:23:40 +00:00
|
|
|
depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
|
2020-07-20 14:44:43 +00:00
|
|
|
stab,
|
2023-02-15 17:39:43 +00:00
|
|
|
inherit_const_stability.yes().then_some(const_stab).flatten(),
|
2020-07-20 14:44:43 +00:00
|
|
|
visit_children,
|
|
|
|
);
|
2020-02-07 18:24:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn recurse_with_stability_attrs(
|
|
|
|
&mut self,
|
2020-07-20 14:44:43 +00:00
|
|
|
depr: Option<DeprecationEntry>,
|
2022-02-19 14:36:11 +00:00
|
|
|
stab: Option<Stability>,
|
|
|
|
const_stab: Option<ConstStability>,
|
2020-02-07 18:24:22 +00:00
|
|
|
f: impl FnOnce(&mut Self),
|
|
|
|
) {
|
|
|
|
// These will be `Some` if this item changes the corresponding stability attribute.
|
2020-07-20 14:44:43 +00:00
|
|
|
let mut replaced_parent_depr = None;
|
2020-02-07 18:24:22 +00:00
|
|
|
let mut replaced_parent_stab = None;
|
|
|
|
let mut replaced_parent_const_stab = None;
|
|
|
|
|
2020-07-20 14:44:43 +00:00
|
|
|
if let Some(depr) = depr {
|
|
|
|
replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
|
|
|
|
}
|
2020-02-07 18:24:22 +00:00
|
|
|
if let Some(stab) = stab {
|
|
|
|
replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
|
|
|
|
}
|
|
|
|
if let Some(const_stab) = const_stab {
|
|
|
|
replaced_parent_const_stab =
|
|
|
|
Some(replace(&mut self.parent_const_stab, Some(const_stab)));
|
|
|
|
}
|
|
|
|
|
|
|
|
f(self);
|
|
|
|
|
2020-07-20 14:44:43 +00:00
|
|
|
if let Some(orig_parent_depr) = replaced_parent_depr {
|
|
|
|
self.parent_depr = orig_parent_depr;
|
|
|
|
}
|
2020-02-07 18:24:22 +00:00
|
|
|
if let Some(orig_parent_stab) = replaced_parent_stab {
|
|
|
|
self.parent_stab = orig_parent_stab;
|
|
|
|
}
|
|
|
|
if let Some(orig_parent_const_stab) = replaced_parent_const_stab {
|
|
|
|
self.parent_const_stab = orig_parent_const_stab;
|
2020-02-07 17:56:56 +00:00
|
|
|
}
|
|
|
|
}
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-12 00:23:11 +00:00
|
|
|
}
|
|
|
|
|
2016-11-09 21:45:26 +00:00
|
|
|
impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
|
2015-11-17 23:56:13 +00:00
|
|
|
/// Because stability levels are scoped lexically, we want to walk
|
|
|
|
/// nested items in the context of the outer item, so enable
|
|
|
|
/// deep-walking.
|
2021-11-03 23:03:12 +00:00
|
|
|
type NestedFilter = nested_filter::All;
|
2020-01-07 16:25:33 +00:00
|
|
|
|
2025-02-03 03:42:01 +00:00
|
|
|
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
|
|
|
self.tcx
|
2016-11-04 22:20:15 +00:00
|
|
|
}
|
|
|
|
|
2019-11-28 18:28:50 +00:00
|
|
|
fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
|
2015-11-16 16:53:41 +00:00
|
|
|
let orig_in_trait_impl = self.in_trait_impl;
|
2015-11-16 18:01:06 +00:00
|
|
|
let mut kind = AnnotationKind::Required;
|
2021-01-16 19:59:21 +00:00
|
|
|
let mut const_stab_inherit = InheritConstStability::No;
|
2021-07-03 10:07:06 +00:00
|
|
|
let mut fn_sig = None;
|
|
|
|
|
2019-09-26 16:51:36 +00:00
|
|
|
match i.kind {
|
2015-11-16 16:53:41 +00:00
|
|
|
// Inherent impls and foreign modules serve only as containers for other items,
|
|
|
|
// they don't have their own stability. They still can be annotated as unstable
|
2022-03-30 19:14:15 +00:00
|
|
|
// and propagate this instability to children, but this annotation is completely
|
2015-11-16 16:53:41 +00:00
|
|
|
// optional. They inherit stability from their parents when unannotated.
|
2020-11-22 22:46:21 +00:00
|
|
|
hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
|
|
|
|
| hir::ItemKind::ForeignMod { .. } => {
|
2015-11-16 16:53:41 +00:00
|
|
|
self.in_trait_impl = false;
|
2015-11-16 18:01:06 +00:00
|
|
|
kind = AnnotationKind::Container;
|
2015-11-16 16:53:41 +00:00
|
|
|
}
|
2020-11-22 22:46:21 +00:00
|
|
|
hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
|
2015-11-16 16:53:41 +00:00
|
|
|
self.in_trait_impl = true;
|
2020-10-31 14:34:10 +00:00
|
|
|
kind = AnnotationKind::DeprecationProhibited;
|
2021-01-16 19:59:21 +00:00
|
|
|
const_stab_inherit = InheritConstStability::Yes;
|
2015-10-02 00:53:28 +00:00
|
|
|
}
|
Move `hir::Item::ident` into `hir::ItemKind`.
`hir::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
Trait`, TraitAalis`.
- It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`,
`Impl`.
- For `Use`, it is non-empty for `UseKind::Single` and empty for
`UseKind::{Glob,ListStem}`.
All of this is quite non-obvious; the only documentation is a single
comment saying "The name might be a dummy name in case of anonymous
items". Some sites that handle items check for an empty ident, some
don't. This is a very C-like way of doing things, but this is Rust, we
have sum types, we can do this properly and never forget to check for
the exceptional case and never YOLO possibly empty identifiers (or
possibly dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- A similar transformation makes sense for `ast::Item`, but this is
already a big change. That can be done later.
- Lots of assertions are added to item lowering to ensure that
identifiers are empty/non-empty as expected. These will be removable
when `ast::Item` is done later.
- `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does.
- `lower_use_tree` is significantly simpler. No more confusing `&mut
Ident` to deal with.
- `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's
used with `unwrap` in a few places; sometimes it's hard to tell
exactly which item kinds might occur. None of these unwraps fail on
the test suite. It's conceivable that some might fail on alternative
input. We can deal with those if/when they happen.
- In `trait_path` the `find_map`/`if let` is replaced with a loop, and
things end up much clearer that way.
- `named_span` no longer checks for an empty name; instead the call site
now checks for a missing identifier if necessary.
- `maybe_inline_local` doesn't need the `glob` argument, it can be
computed in-function from the `renamed` argument.
- `arbitrary_source_item_ordering::check_mod` had a big `if` statement
that was just getting the ident from the item kinds that had one. It
could be mostly replaced by a single call to the new `ItemKind::ident`
method.
- `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size,
and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
|
|
|
hir::ItemKind::Struct(_, ref sd, _) => {
|
2022-11-06 19:46:55 +00:00
|
|
|
if let Some(ctor_def_id) = sd.ctor_def_id() {
|
2020-05-18 03:00:19 +00:00
|
|
|
self.annotate(
|
2022-11-06 19:46:55 +00:00
|
|
|
ctor_def_id,
|
2020-05-18 03:00:19 +00:00
|
|
|
i.span,
|
2021-07-03 10:07:06 +00:00
|
|
|
None,
|
2020-05-18 03:00:19 +00:00
|
|
|
AnnotationKind::Required,
|
2020-07-05 23:02:30 +00:00
|
|
|
InheritDeprecation::Yes,
|
2021-01-16 19:59:21 +00:00
|
|
|
InheritConstStability::No,
|
2020-04-23 18:15:04 +00:00
|
|
|
InheritStability::Yes,
|
2020-05-18 03:00:19 +00:00
|
|
|
|_| {},
|
|
|
|
)
|
2015-11-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
}
|
2025-01-04 10:30:31 +00:00
|
|
|
hir::ItemKind::Fn { sig: ref item_fn_sig, .. } => {
|
2021-07-03 10:07:06 +00:00
|
|
|
fn_sig = Some(item_fn_sig);
|
|
|
|
}
|
2015-11-16 16:53:41 +00:00
|
|
|
_ => {}
|
2014-11-11 20:46:47 +00:00
|
|
|
}
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-12 00:23:11 +00:00
|
|
|
|
2021-01-16 19:59:21 +00:00
|
|
|
self.annotate(
|
2022-10-27 03:02:18 +00:00
|
|
|
i.owner_id.def_id,
|
2021-01-16 19:59:21 +00:00
|
|
|
i.span,
|
2021-07-03 10:07:06 +00:00
|
|
|
fn_sig,
|
2021-01-16 19:59:21 +00:00
|
|
|
kind,
|
|
|
|
InheritDeprecation::Yes,
|
|
|
|
const_stab_inherit,
|
2020-04-23 18:15:04 +00:00
|
|
|
InheritStability::No,
|
2021-01-16 19:59:21 +00:00
|
|
|
|v| intravisit::walk_item(v, i),
|
|
|
|
);
|
2015-11-16 16:53:41 +00:00
|
|
|
self.in_trait_impl = orig_in_trait_impl;
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-12 00:23:11 +00:00
|
|
|
}
|
|
|
|
|
2019-11-28 20:47:10 +00:00
|
|
|
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
|
2021-07-03 10:07:06 +00:00
|
|
|
let fn_sig = match ti.kind {
|
|
|
|
hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
2020-07-05 23:02:30 +00:00
|
|
|
self.annotate(
|
2022-10-27 03:02:18 +00:00
|
|
|
ti.owner_id.def_id,
|
2020-07-05 23:02:30 +00:00
|
|
|
ti.span,
|
2021-07-03 10:07:06 +00:00
|
|
|
fn_sig,
|
2020-07-05 23:02:30 +00:00
|
|
|
AnnotationKind::Required,
|
|
|
|
InheritDeprecation::Yes,
|
2021-01-16 19:59:21 +00:00
|
|
|
InheritConstStability::No,
|
2020-04-23 18:15:04 +00:00
|
|
|
InheritStability::No,
|
2020-07-05 23:02:30 +00:00
|
|
|
|v| {
|
|
|
|
intravisit::walk_trait_item(v, ti);
|
|
|
|
},
|
|
|
|
);
|
2015-03-10 10:28:44 +00:00
|
|
|
}
|
2014-08-06 02:44:21 +00:00
|
|
|
|
2019-11-28 21:16:44 +00:00
|
|
|
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
|
2019-12-22 22:42:04 +00:00
|
|
|
let kind =
|
|
|
|
if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
|
2021-07-03 10:07:06 +00:00
|
|
|
|
|
|
|
let fn_sig = match ii.kind {
|
|
|
|
hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
2021-01-16 19:59:21 +00:00
|
|
|
self.annotate(
|
2022-10-27 03:02:18 +00:00
|
|
|
ii.owner_id.def_id,
|
2021-01-16 19:59:21 +00:00
|
|
|
ii.span,
|
2021-07-03 10:07:06 +00:00
|
|
|
fn_sig,
|
2021-01-16 19:59:21 +00:00
|
|
|
kind,
|
|
|
|
InheritDeprecation::Yes,
|
|
|
|
InheritConstStability::No,
|
2020-04-23 18:15:04 +00:00
|
|
|
InheritStability::No,
|
2021-01-16 19:59:21 +00:00
|
|
|
|v| {
|
|
|
|
intravisit::walk_impl_item(v, ii);
|
|
|
|
},
|
|
|
|
);
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-12 00:23:11 +00:00
|
|
|
}
|
|
|
|
|
2022-08-10 01:22:01 +00:00
|
|
|
fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
|
2020-07-05 23:02:30 +00:00
|
|
|
self.annotate(
|
2022-11-06 19:46:55 +00:00
|
|
|
var.def_id,
|
2020-07-05 23:02:30 +00:00
|
|
|
var.span,
|
2021-07-03 10:07:06 +00:00
|
|
|
None,
|
2020-07-05 23:02:30 +00:00
|
|
|
AnnotationKind::Required,
|
|
|
|
InheritDeprecation::Yes,
|
2021-01-16 19:59:21 +00:00
|
|
|
InheritConstStability::No,
|
2020-04-23 18:15:04 +00:00
|
|
|
InheritStability::Yes,
|
2020-07-05 23:02:30 +00:00
|
|
|
|v| {
|
2022-11-06 19:46:55 +00:00
|
|
|
if let Some(ctor_def_id) = var.data.ctor_def_id() {
|
2020-07-05 23:02:30 +00:00
|
|
|
v.annotate(
|
2022-11-06 19:46:55 +00:00
|
|
|
ctor_def_id,
|
2020-07-05 23:02:30 +00:00
|
|
|
var.span,
|
2021-07-03 10:07:06 +00:00
|
|
|
None,
|
2020-07-05 23:02:30 +00:00
|
|
|
AnnotationKind::Required,
|
|
|
|
InheritDeprecation::Yes,
|
2021-01-16 19:59:21 +00:00
|
|
|
InheritConstStability::No,
|
2022-08-11 22:20:35 +00:00
|
|
|
InheritStability::Yes,
|
2020-07-05 23:02:30 +00:00
|
|
|
|_| {},
|
|
|
|
);
|
|
|
|
}
|
2019-03-21 22:38:50 +00:00
|
|
|
|
2022-08-10 01:22:01 +00:00
|
|
|
intravisit::walk_variant(v, var)
|
2020-07-05 23:02:30 +00:00
|
|
|
},
|
|
|
|
)
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-12 00:23:11 +00:00
|
|
|
}
|
|
|
|
|
2021-03-15 21:36:07 +00:00
|
|
|
fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
|
2020-07-05 23:02:30 +00:00
|
|
|
self.annotate(
|
2022-11-06 19:46:55 +00:00
|
|
|
s.def_id,
|
2020-07-05 23:02:30 +00:00
|
|
|
s.span,
|
2021-07-03 10:07:06 +00:00
|
|
|
None,
|
2020-07-05 23:02:30 +00:00
|
|
|
AnnotationKind::Required,
|
|
|
|
InheritDeprecation::Yes,
|
2021-01-16 19:59:21 +00:00
|
|
|
InheritConstStability::No,
|
2020-04-23 18:15:04 +00:00
|
|
|
InheritStability::Yes,
|
2020-07-05 23:02:30 +00:00
|
|
|
|v| {
|
2021-03-15 21:36:07 +00:00
|
|
|
intravisit::walk_field_def(v, s);
|
2020-07-05 23:02:30 +00:00
|
|
|
},
|
|
|
|
);
|
2014-07-10 18:17:40 +00:00
|
|
|
}
|
2014-12-20 18:08:16 +00:00
|
|
|
|
2019-11-28 19:18:29 +00:00
|
|
|
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
|
2024-10-06 17:59:19 +00:00
|
|
|
let fn_sig = match &i.kind {
|
|
|
|
rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig),
|
|
|
|
_ => None,
|
|
|
|
};
|
2020-07-05 23:02:30 +00:00
|
|
|
self.annotate(
|
2022-10-27 03:02:18 +00:00
|
|
|
i.owner_id.def_id,
|
2020-07-05 23:02:30 +00:00
|
|
|
i.span,
|
2024-10-06 17:59:19 +00:00
|
|
|
fn_sig,
|
2020-07-05 23:02:30 +00:00
|
|
|
AnnotationKind::Required,
|
|
|
|
InheritDeprecation::Yes,
|
2021-01-16 19:59:21 +00:00
|
|
|
InheritConstStability::No,
|
2020-04-23 18:15:04 +00:00
|
|
|
InheritStability::No,
|
2020-07-05 23:02:30 +00:00
|
|
|
|v| {
|
|
|
|
intravisit::walk_foreign_item(v, i);
|
|
|
|
},
|
|
|
|
);
|
2015-11-16 16:53:41 +00:00
|
|
|
}
|
|
|
|
|
2020-05-18 03:00:19 +00:00
|
|
|
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
|
|
|
|
let kind = match &p.kind {
|
2020-12-30 15:34:53 +00:00
|
|
|
// Allow stability attributes on default generic arguments.
|
|
|
|
hir::GenericParamKind::Type { default: Some(_), .. }
|
|
|
|
| hir::GenericParamKind::Const { default: Some(_), .. } => AnnotationKind::Container,
|
2020-05-18 03:00:19 +00:00
|
|
|
_ => AnnotationKind::Prohibited,
|
|
|
|
};
|
|
|
|
|
2021-01-16 19:59:21 +00:00
|
|
|
self.annotate(
|
2022-11-06 18:26:36 +00:00
|
|
|
p.def_id,
|
2021-01-16 19:59:21 +00:00
|
|
|
p.span,
|
2021-07-03 10:07:06 +00:00
|
|
|
None,
|
2021-01-16 19:59:21 +00:00
|
|
|
kind,
|
|
|
|
InheritDeprecation::No,
|
|
|
|
InheritConstStability::No,
|
2020-04-23 18:15:04 +00:00
|
|
|
InheritStability::No,
|
2021-01-16 19:59:21 +00:00
|
|
|
|v| {
|
|
|
|
intravisit::walk_generic_param(v, p);
|
|
|
|
},
|
|
|
|
);
|
2014-12-20 18:08:16 +00:00
|
|
|
}
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-12 00:23:11 +00:00
|
|
|
}
|
|
|
|
|
2020-06-25 20:41:36 +00:00
|
|
|
struct MissingStabilityAnnotations<'tcx> {
|
2019-06-13 21:48:52 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2022-09-22 13:19:53 +00:00
|
|
|
effective_visibilities: &'tcx EffectiveVisibilities,
|
2016-11-10 17:08:21 +00:00
|
|
|
}
|
|
|
|
|
2020-06-25 20:41:36 +00:00
|
|
|
impl<'tcx> MissingStabilityAnnotations<'tcx> {
|
2021-07-28 15:23:40 +00:00
|
|
|
fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
|
|
|
|
let stab = self.tcx.stability().local_stability(def_id);
|
2023-04-09 19:37:31 +00:00
|
|
|
if !self.tcx.sess.is_test_crate()
|
2022-09-22 13:19:53 +00:00
|
|
|
&& stab.is_none()
|
|
|
|
&& self.effective_visibilities.is_reachable(def_id)
|
|
|
|
{
|
2023-02-21 21:05:32 +00:00
|
|
|
let descr = self.tcx.def_descr(def_id.to_def_id());
|
2023-12-18 11:21:37 +00:00
|
|
|
self.tcx.dcx().emit_err(errors::MissingStabilityAttr { span, descr });
|
2016-11-10 17:08:21 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-25 20:48:48 +00:00
|
|
|
|
2024-11-02 20:19:21 +00:00
|
|
|
fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
|
2025-01-12 20:52:30 +00:00
|
|
|
let is_const = self.tcx.is_const_fn(def_id.to_def_id())
|
|
|
|
|| (self.tcx.def_kind(def_id.to_def_id()) == DefKind::Trait
|
|
|
|
&& self.tcx.is_const_trait(def_id.to_def_id()));
|
2021-11-18 02:06:17 +00:00
|
|
|
|
2025-01-12 20:52:30 +00:00
|
|
|
// Reachable const fn/trait must have a stability attribute.
|
2024-11-02 20:19:21 +00:00
|
|
|
if is_const
|
|
|
|
&& self.effective_visibilities.is_reachable(def_id)
|
|
|
|
&& self.tcx.lookup_const_stability(def_id).is_none()
|
|
|
|
{
|
2023-02-21 21:05:32 +00:00
|
|
|
let descr = self.tcx.def_descr(def_id.to_def_id());
|
2023-12-18 11:21:37 +00:00
|
|
|
self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr });
|
2020-09-25 20:48:48 +00:00
|
|
|
}
|
|
|
|
}
|
2016-11-10 17:08:21 +00:00
|
|
|
}
|
|
|
|
|
2020-06-25 20:41:36 +00:00
|
|
|
impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
|
2021-11-03 23:03:12 +00:00
|
|
|
type NestedFilter = nested_filter::OnlyBodies;
|
2020-01-07 16:25:33 +00:00
|
|
|
|
2025-02-03 03:42:01 +00:00
|
|
|
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
|
|
|
self.tcx
|
2016-11-28 17:10:37 +00:00
|
|
|
}
|
|
|
|
|
2019-11-28 18:28:50 +00:00
|
|
|
fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
|
2020-09-25 20:48:48 +00:00
|
|
|
// Inherent impls and foreign modules serve only as containers for other items,
|
|
|
|
// they don't have their own stability. They still can be annotated as unstable
|
2022-03-30 19:14:15 +00:00
|
|
|
// and propagate this instability to children, but this annotation is completely
|
2020-09-25 20:48:48 +00:00
|
|
|
// optional. They inherit stability from their parents when unannotated.
|
|
|
|
if !matches!(
|
|
|
|
i.kind,
|
2021-01-09 17:00:45 +00:00
|
|
|
hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
|
|
|
|
| hir::ItemKind::ForeignMod { .. }
|
2020-09-25 20:48:48 +00:00
|
|
|
) {
|
2022-10-27 03:02:18 +00:00
|
|
|
self.check_missing_stability(i.owner_id.def_id, i.span);
|
2020-09-25 20:48:48 +00:00
|
|
|
}
|
2016-11-10 17:08:21 +00:00
|
|
|
|
2021-11-18 02:06:17 +00:00
|
|
|
// Ensure stable `const fn` have a const stability attribute.
|
2024-11-02 20:19:21 +00:00
|
|
|
self.check_missing_const_stability(i.owner_id.def_id, i.span);
|
2016-11-10 17:08:21 +00:00
|
|
|
|
|
|
|
intravisit::walk_item(self, i)
|
|
|
|
}
|
|
|
|
|
2019-11-28 20:47:10 +00:00
|
|
|
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
|
2022-10-27 03:02:18 +00:00
|
|
|
self.check_missing_stability(ti.owner_id.def_id, ti.span);
|
2016-11-10 17:08:21 +00:00
|
|
|
intravisit::walk_trait_item(self, ti);
|
|
|
|
}
|
|
|
|
|
2019-11-28 21:16:44 +00:00
|
|
|
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
|
2025-02-20 20:54:35 +00:00
|
|
|
let impl_def_id = self.tcx.hir_get_parent_item(ii.hir_id());
|
2016-11-10 17:08:21 +00:00
|
|
|
if self.tcx.impl_trait_ref(impl_def_id).is_none() {
|
2022-10-27 03:02:18 +00:00
|
|
|
self.check_missing_stability(ii.owner_id.def_id, ii.span);
|
2024-11-02 20:19:21 +00:00
|
|
|
self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
|
2016-11-10 17:08:21 +00:00
|
|
|
}
|
|
|
|
intravisit::walk_impl_item(self, ii);
|
|
|
|
}
|
|
|
|
|
2022-08-10 01:22:01 +00:00
|
|
|
fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
|
2022-11-06 19:46:55 +00:00
|
|
|
self.check_missing_stability(var.def_id, var.span);
|
|
|
|
if let Some(ctor_def_id) = var.data.ctor_def_id() {
|
|
|
|
self.check_missing_stability(ctor_def_id, var.span);
|
2022-08-11 22:25:16 +00:00
|
|
|
}
|
2022-08-10 01:22:01 +00:00
|
|
|
intravisit::walk_variant(self, var);
|
2016-11-10 17:08:21 +00:00
|
|
|
}
|
|
|
|
|
2021-03-15 21:36:07 +00:00
|
|
|
fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
|
2022-11-06 19:46:55 +00:00
|
|
|
self.check_missing_stability(s.def_id, s.span);
|
2021-03-15 21:36:07 +00:00
|
|
|
intravisit::walk_field_def(self, s);
|
2016-11-10 17:08:21 +00:00
|
|
|
}
|
|
|
|
|
2019-11-28 19:18:29 +00:00
|
|
|
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
|
2022-10-27 03:02:18 +00:00
|
|
|
self.check_missing_stability(i.owner_id.def_id, i.span);
|
2016-11-10 17:08:21 +00:00
|
|
|
intravisit::walk_foreign_item(self, i);
|
|
|
|
}
|
2020-05-18 03:00:19 +00:00
|
|
|
// Note that we don't need to `check_missing_stability` for default generic parameters,
|
|
|
|
// as we assume that any default generic parameters without attributes are automatically
|
|
|
|
// stable (assuming they have not inherited instability from their parent).
|
2016-11-10 17:08:21 +00:00
|
|
|
}
|
|
|
|
|
2022-02-19 14:36:11 +00:00
|
|
|
fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
|
2019-12-29 10:20:20 +00:00
|
|
|
let mut index = Index {
|
|
|
|
stab_map: Default::default(),
|
|
|
|
const_stab_map: Default::default(),
|
2022-04-27 14:14:19 +00:00
|
|
|
default_body_stab_map: Default::default(),
|
2019-12-29 10:20:20 +00:00
|
|
|
depr_map: Default::default(),
|
2022-07-13 14:10:19 +00:00
|
|
|
implications: Default::default(),
|
2019-12-29 10:20:20 +00:00
|
|
|
};
|
2017-08-31 22:08:34 +00:00
|
|
|
|
2019-12-29 10:20:20 +00:00
|
|
|
{
|
|
|
|
let mut annotator = Annotator {
|
|
|
|
tcx,
|
|
|
|
index: &mut index,
|
|
|
|
parent_stab: None,
|
2020-02-07 18:24:22 +00:00
|
|
|
parent_const_stab: None,
|
2019-12-29 10:20:20 +00:00
|
|
|
parent_depr: None,
|
|
|
|
in_trait_impl: false,
|
|
|
|
};
|
2015-02-03 15:46:08 +00:00
|
|
|
|
2019-12-29 10:20:20 +00:00
|
|
|
// If the `-Z force-unstable-if-unmarked` flag is passed then we provide
|
|
|
|
// a parent stability annotation which indicates that this is private
|
|
|
|
// with the `rustc_private` feature. This is intended for use when
|
2020-04-03 10:03:13 +00:00
|
|
|
// compiling `librustc_*` crates themselves so we can leverage crates.io
|
2019-12-29 10:20:20 +00:00
|
|
|
// while maintaining the invariant that all sysroot crates are unstable
|
|
|
|
// by default and are unable to be used.
|
2022-07-06 12:44:47 +00:00
|
|
|
if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
|
2022-02-19 14:36:11 +00:00
|
|
|
let stability = Stability {
|
2019-12-29 10:20:20 +00:00
|
|
|
level: attr::StabilityLevel::Unstable {
|
2022-07-01 15:20:46 +00:00
|
|
|
reason: UnstableReason::Default,
|
2024-02-08 22:03:25 +00:00
|
|
|
issue: NonZero::new(27812),
|
2019-12-29 10:20:20 +00:00
|
|
|
is_soft: false,
|
2022-07-13 12:10:37 +00:00
|
|
|
implied_by: None,
|
2019-12-29 10:20:20 +00:00
|
|
|
},
|
|
|
|
feature: sym::rustc_private,
|
2022-02-19 14:36:11 +00:00
|
|
|
};
|
2019-12-29 10:20:20 +00:00
|
|
|
annotator.parent_stab = Some(stability);
|
|
|
|
}
|
2019-12-08 00:43:10 +00:00
|
|
|
|
2019-12-29 10:20:20 +00:00
|
|
|
annotator.annotate(
|
2021-07-28 15:23:40 +00:00
|
|
|
CRATE_DEF_ID,
|
2021-08-26 16:42:08 +00:00
|
|
|
tcx.hir().span(CRATE_HIR_ID),
|
2021-07-03 10:07:06 +00:00
|
|
|
None,
|
2019-12-29 10:20:20 +00:00
|
|
|
AnnotationKind::Required,
|
2020-07-05 23:02:30 +00:00
|
|
|
InheritDeprecation::Yes,
|
2021-01-16 19:59:21 +00:00
|
|
|
InheritConstStability::No,
|
2020-04-23 18:15:04 +00:00
|
|
|
InheritStability::No,
|
2025-02-17 03:17:57 +00:00
|
|
|
|v| tcx.hir_walk_toplevel_module(v),
|
2019-12-29 10:20:20 +00:00
|
|
|
);
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-12 00:23:11 +00:00
|
|
|
}
|
2020-03-20 14:03:11 +00:00
|
|
|
index
|
2014-06-26 18:37:39 +00:00
|
|
|
}
|
Add stability inheritance
This commit makes several changes to the stability index infrastructure:
* Stability levels are now inherited lexically, i.e., each item's
stability level becomes the default for any nested items.
* The computed stability level for an item is stored as part of the
metadata. When using an item from an external crate, this data is
looked up and cached.
* The stability lint works from the computed stability level, rather
than manual stability attribute annotations. However, the lint still
checks only a limited set of item uses (e.g., it does not check every
component of a path on import). This will be addressed in a later PR,
as part of issue #8962.
* The stability lint only applies to items originating from external
crates, since the stability index is intended as a promise to
downstream crates.
* The "experimental" lint is now _allow_ by default. This is because
almost all existing crates have been marked "experimental", pending
library stabilization. With inheritance in place, this would generate
a massive explosion of warnings for every Rust program.
The lint should be changed back to deny-by-default after library
stabilization is complete.
* The "deprecated" lint still warns by default.
The net result: we can begin tracking stability index for the standard
libraries as we stabilize, without impacting most clients.
Closes #13540.
2014-06-12 00:23:11 +00:00
|
|
|
|
2015-01-14 23:20:14 +00:00
|
|
|
/// Cross-references the feature names of unstable APIs with enabled
|
2016-11-10 17:08:21 +00:00
|
|
|
/// features and possibly prints errors.
|
2023-04-26 18:53:51 +00:00
|
|
|
fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
2025-02-17 03:17:57 +00:00
|
|
|
tcx.hir_visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
|
2018-06-06 20:13:52 +00:00
|
|
|
}
|
|
|
|
|
2020-07-05 20:00:14 +00:00
|
|
|
pub(crate) fn provide(providers: &mut Providers) {
|
2022-01-16 21:26:46 +00:00
|
|
|
*providers = Providers {
|
|
|
|
check_mod_unstable_api_usage,
|
|
|
|
stability_index,
|
2022-07-13 14:10:19 +00:00
|
|
|
stability_implications: |tcx, _| tcx.stability().implications.clone(),
|
2023-03-13 18:54:05 +00:00
|
|
|
lookup_stability: |tcx, id| tcx.stability().local_stability(id),
|
|
|
|
lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id),
|
|
|
|
lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id),
|
|
|
|
lookup_deprecation_entry: |tcx, id| tcx.stability().local_deprecation_entry(id),
|
2022-01-16 21:26:46 +00:00
|
|
|
..*providers
|
|
|
|
};
|
2019-06-21 23:44:45 +00:00
|
|
|
}
|
|
|
|
|
2019-06-11 19:03:44 +00:00
|
|
|
struct Checker<'tcx> {
|
2019-06-13 21:48:52 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2015-01-14 23:20:14 +00:00
|
|
|
}
|
|
|
|
|
2021-12-14 05:16:36 +00:00
|
|
|
impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
2021-11-03 23:03:12 +00:00
|
|
|
type NestedFilter = nested_filter::OnlyBodies;
|
2020-01-07 16:25:33 +00:00
|
|
|
|
2016-11-28 19:00:26 +00:00
|
|
|
/// Because stability levels are scoped lexically, we want to walk
|
|
|
|
/// nested items in the context of the outer item, so enable
|
|
|
|
/// deep-walking.
|
2025-02-03 03:42:01 +00:00
|
|
|
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
|
|
|
self.tcx
|
2016-10-28 20:58:32 +00:00
|
|
|
}
|
|
|
|
|
2019-11-28 18:28:50 +00:00
|
|
|
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
2019-09-26 16:51:36 +00:00
|
|
|
match item.kind {
|
Move `hir::Item::ident` into `hir::ItemKind`.
`hir::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
Trait`, TraitAalis`.
- It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`,
`Impl`.
- For `Use`, it is non-empty for `UseKind::Single` and empty for
`UseKind::{Glob,ListStem}`.
All of this is quite non-obvious; the only documentation is a single
comment saying "The name might be a dummy name in case of anonymous
items". Some sites that handle items check for an empty ident, some
don't. This is a very C-like way of doing things, but this is Rust, we
have sum types, we can do this properly and never forget to check for
the exceptional case and never YOLO possibly empty identifiers (or
possibly dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- A similar transformation makes sense for `ast::Item`, but this is
already a big change. That can be done later.
- Lots of assertions are added to item lowering to ensure that
identifiers are empty/non-empty as expected. These will be removable
when `ast::Item` is done later.
- `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does.
- `lower_use_tree` is significantly simpler. No more confusing `&mut
Ident` to deal with.
- `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's
used with `unwrap` in a few places; sometimes it's hard to tell
exactly which item kinds might occur. None of these unwraps fail on
the test suite. It's conceivable that some might fail on alternative
input. We can deal with those if/when they happen.
- In `trait_path` the `find_map`/`if let` is replaced with a loop, and
things end up much clearer that way.
- `named_span` no longer checks for an empty name; instead the call site
now checks for a missing identifier if necessary.
- `maybe_inline_local` doesn't need the `glob` argument, it can be
computed in-function from the `renamed` argument.
- `arbitrary_source_item_ordering::check_mod` had a big `if` statement
that was just getting the ident from the item kinds that had one. It
could be mostly replaced by a single call to the new `ItemKind::ident`
method.
- `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size,
and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
|
|
|
hir::ItemKind::ExternCrate(_, ident) => {
|
2016-11-10 17:08:21 +00:00
|
|
|
// compiler-generated `extern crate` items have a dummy span.
|
2020-06-01 01:09:25 +00:00
|
|
|
// `std` is still checked for the `restricted-std` feature.
|
Move `hir::Item::ident` into `hir::ItemKind`.
`hir::Item` has an `ident` field.
- It's always non-empty for these item kinds: `ExternCrate`, `Static`,
`Const`, `Fn`, `Macro`, `Mod`, `TyAlias`, `Enum`, `Struct`, `Union`,
Trait`, TraitAalis`.
- It's always empty for these item kinds: `ForeignMod`, `GlobalAsm`,
`Impl`.
- For `Use`, it is non-empty for `UseKind::Single` and empty for
`UseKind::{Glob,ListStem}`.
All of this is quite non-obvious; the only documentation is a single
comment saying "The name might be a dummy name in case of anonymous
items". Some sites that handle items check for an empty ident, some
don't. This is a very C-like way of doing things, but this is Rust, we
have sum types, we can do this properly and never forget to check for
the exceptional case and never YOLO possibly empty identifiers (or
possibly dummy spans) around and hope that things will work out.
The commit is large but it's mostly obvious plumbing work. Some notable
things.
- A similar transformation makes sense for `ast::Item`, but this is
already a big change. That can be done later.
- Lots of assertions are added to item lowering to ensure that
identifiers are empty/non-empty as expected. These will be removable
when `ast::Item` is done later.
- `ItemKind::Use` doesn't get an `Ident`, but `UseKind::Single` does.
- `lower_use_tree` is significantly simpler. No more confusing `&mut
Ident` to deal with.
- `ItemKind::ident` is a new method, it returns an `Option<Ident>`. It's
used with `unwrap` in a few places; sometimes it's hard to tell
exactly which item kinds might occur. None of these unwraps fail on
the test suite. It's conceivable that some might fail on alternative
input. We can deal with those if/when they happen.
- In `trait_path` the `find_map`/`if let` is replaced with a loop, and
things end up much clearer that way.
- `named_span` no longer checks for an empty name; instead the call site
now checks for a missing identifier if necessary.
- `maybe_inline_local` doesn't need the `glob` argument, it can be
computed in-function from the `renamed` argument.
- `arbitrary_source_item_ordering::check_mod` had a big `if` statement
that was just getting the ident from the item kinds that had one. It
could be mostly replaced by a single call to the new `ItemKind::ident`
method.
- `ItemKind` grows from 56 to 64 bytes, but `Item` stays the same size,
and that's what matters, because `ItemKind` only occurs within `Item`.
2025-03-06 08:07:36 +00:00
|
|
|
if item.span.is_dummy() && ident.name != sym::std {
|
2019-12-22 22:42:04 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-11-10 17:08:21 +00:00
|
|
|
|
2022-10-27 03:02:18 +00:00
|
|
|
let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else {
|
2022-02-18 23:48:49 +00:00
|
|
|
return;
|
2016-11-10 17:08:21 +00:00
|
|
|
};
|
2022-04-15 17:27:53 +00:00
|
|
|
let def_id = cnum.as_def_id();
|
2021-05-07 02:41:04 +00:00
|
|
|
self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
|
2015-02-17 21:56:06 +00:00
|
|
|
}
|
|
|
|
|
2016-11-10 17:08:21 +00:00
|
|
|
// For implementations of traits, check the stability of each item
|
|
|
|
// individually as it's possible to have a stable trait with unstable
|
|
|
|
// items.
|
2025-01-12 20:52:30 +00:00
|
|
|
hir::ItemKind::Impl(hir::Impl {
|
2025-02-20 18:28:48 +00:00
|
|
|
of_trait: Some(t), self_ty, items, constness, ..
|
2025-01-12 20:52:30 +00:00
|
|
|
}) => {
|
2022-02-22 19:54:47 +00:00
|
|
|
let features = self.tcx.features();
|
2024-10-09 07:01:57 +00:00
|
|
|
if features.staged_api() {
|
2025-02-21 07:33:05 +00:00
|
|
|
let attrs = self.tcx.hir_attrs(item.hir_id());
|
2025-02-09 21:49:33 +00:00
|
|
|
let stab = attr::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span));
|
|
|
|
|
|
|
|
// FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
|
|
|
|
let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);
|
2022-02-22 19:54:47 +00:00
|
|
|
|
2020-09-10 18:43:13 +00:00
|
|
|
// If this impl block has an #[unstable] attribute, give an
|
|
|
|
// error if all involved types and traits are stable, because
|
|
|
|
// it will have no effect.
|
|
|
|
// See: https://github.com/rust-lang/rust/issues/55436
|
2024-12-07 14:27:17 +00:00
|
|
|
if let Some((
|
|
|
|
Stability { level: attr::StabilityLevel::Unstable { .. }, .. },
|
|
|
|
span,
|
|
|
|
)) = stab
|
|
|
|
{
|
2020-09-10 18:43:13 +00:00
|
|
|
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
|
2025-01-18 22:45:41 +00:00
|
|
|
c.visit_ty_unambig(self_ty);
|
2020-09-10 18:43:13 +00:00
|
|
|
c.visit_trait_ref(t);
|
2023-02-25 08:39:05 +00:00
|
|
|
|
|
|
|
// do not lint when the trait isn't resolved, since resolution error should
|
|
|
|
// be fixed first
|
|
|
|
if t.path.res != Res::Err && c.fully_stable {
|
2024-01-16 05:27:02 +00:00
|
|
|
self.tcx.emit_node_span_lint(
|
2020-09-10 18:43:13 +00:00
|
|
|
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
|
2021-01-30 16:47:51 +00:00
|
|
|
item.hir_id(),
|
2020-09-10 18:43:13 +00:00
|
|
|
span,
|
2023-04-25 17:42:42 +00:00
|
|
|
errors::IneffectiveUnstableImpl,
|
2020-09-10 18:43:13 +00:00
|
|
|
);
|
|
|
|
}
|
2020-09-09 20:16:13 +00:00
|
|
|
}
|
2022-02-22 19:54:47 +00:00
|
|
|
|
2024-10-09 07:01:57 +00:00
|
|
|
if features.const_trait_impl()
|
2025-02-07 13:58:08 +00:00
|
|
|
&& let hir::Constness::Const = constness
|
2022-02-22 19:54:47 +00:00
|
|
|
{
|
2025-02-07 13:58:08 +00:00
|
|
|
let stable_or_implied_stable = match const_stab {
|
|
|
|
None => true,
|
|
|
|
Some(stab) if stab.is_const_stable() => {
|
|
|
|
// `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
|
|
|
|
// needs to have an error emitted.
|
|
|
|
// Note: Remove this error once `const_trait_impl` is stabilized
|
|
|
|
self.tcx
|
|
|
|
.dcx()
|
|
|
|
.emit_err(errors::TraitImplConstStable { span: item.span });
|
|
|
|
true
|
|
|
|
}
|
|
|
|
Some(_) => false,
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(trait_id) = t.trait_def_id()
|
|
|
|
&& let Some(const_stab) = self.tcx.lookup_const_stability(trait_id)
|
|
|
|
{
|
|
|
|
// the const stability of a trait impl must match the const stability on the trait.
|
|
|
|
if const_stab.is_const_stable() != stable_or_implied_stable {
|
|
|
|
let trait_span = self.tcx.def_ident_span(trait_id).unwrap();
|
|
|
|
|
|
|
|
let impl_stability = if stable_or_implied_stable {
|
|
|
|
errors::ImplConstStability::Stable { span: item.span }
|
|
|
|
} else {
|
|
|
|
errors::ImplConstStability::Unstable { span: item.span }
|
|
|
|
};
|
|
|
|
let trait_stability = if const_stab.is_const_stable() {
|
|
|
|
errors::TraitConstStability::Stable { span: trait_span }
|
|
|
|
} else {
|
|
|
|
errors::TraitConstStability::Unstable { span: trait_span }
|
|
|
|
};
|
|
|
|
|
|
|
|
self.tcx.dcx().emit_err(errors::TraitImplConstStabilityMismatch {
|
|
|
|
span: item.span,
|
|
|
|
impl_stability,
|
|
|
|
trait_stability,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2022-02-22 19:54:47 +00:00
|
|
|
}
|
2020-09-09 20:16:13 +00:00
|
|
|
}
|
|
|
|
|
2025-02-07 13:58:08 +00:00
|
|
|
if let hir::Constness::Const = constness
|
|
|
|
&& let Some(def_id) = t.trait_def_id()
|
|
|
|
{
|
|
|
|
// FIXME(const_trait_impl): Improve the span here.
|
|
|
|
self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
|
2025-01-12 20:52:30 +00:00
|
|
|
}
|
|
|
|
|
2022-02-05 14:26:49 +00:00
|
|
|
for impl_item_ref in *items {
|
2022-10-27 03:02:18 +00:00
|
|
|
let impl_item = self.tcx.associated_item(impl_item_ref.id.owner_id);
|
2021-11-18 21:35:42 +00:00
|
|
|
|
|
|
|
if let Some(def_id) = impl_item.trait_item_def_id {
|
|
|
|
// Pass `None` to skip deprecation warnings.
|
|
|
|
self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
|
2016-09-05 22:26:02 +00:00
|
|
|
}
|
2016-11-10 17:08:21 +00:00
|
|
|
}
|
2015-02-25 11:34:21 +00:00
|
|
|
}
|
2015-01-14 23:20:14 +00:00
|
|
|
|
2019-12-22 22:42:04 +00:00
|
|
|
_ => (/* pass */),
|
2015-02-25 11:34:21 +00:00
|
|
|
}
|
2016-11-10 17:08:21 +00:00
|
|
|
intravisit::walk_item(self, item);
|
2015-02-25 11:34:21 +00:00
|
|
|
}
|
2016-10-27 02:17:42 +00:00
|
|
|
|
2025-01-12 20:52:30 +00:00
|
|
|
fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) {
|
|
|
|
match t.modifiers.constness {
|
|
|
|
hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) => {
|
|
|
|
if let Some(def_id) = t.trait_ref.trait_def_id() {
|
|
|
|
self.tcx.check_const_stability(def_id, t.trait_ref.path.span, span);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hir::BoundConstness::Never => {}
|
|
|
|
}
|
|
|
|
intravisit::walk_poly_trait_ref(self, t);
|
|
|
|
}
|
|
|
|
|
2022-11-25 08:26:36 +00:00
|
|
|
fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) {
|
2019-04-20 16:36:05 +00:00
|
|
|
if let Some(def_id) = path.res.opt_def_id() {
|
2021-06-15 11:35:03 +00:00
|
|
|
let method_span = path.segments.last().map(|s| s.ident.span);
|
2022-04-12 01:12:26 +00:00
|
|
|
let item_is_allowed = self.tcx.check_stability_allow_unstable(
|
2022-06-04 22:05:33 +00:00
|
|
|
def_id,
|
|
|
|
Some(id),
|
|
|
|
path.span,
|
|
|
|
method_span,
|
|
|
|
if is_unstable_reexport(self.tcx, id) {
|
|
|
|
AllowUnstable::Yes
|
|
|
|
} else {
|
|
|
|
AllowUnstable::No
|
|
|
|
},
|
2022-04-12 01:12:26 +00:00
|
|
|
);
|
|
|
|
|
2025-01-01 18:09:01 +00:00
|
|
|
if item_is_allowed {
|
|
|
|
// The item itself is allowed; check whether the path there is also allowed.
|
2025-02-02 11:33:40 +00:00
|
|
|
let is_allowed_through_unstable_modules: Option<Symbol> =
|
2025-01-01 18:09:01 +00:00
|
|
|
self.tcx.lookup_stability(def_id).and_then(|stab| match stab.level {
|
|
|
|
StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
|
|
|
|
allowed_through_unstable_modules
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
});
|
|
|
|
|
2025-02-02 11:33:40 +00:00
|
|
|
// Check parent modules stability as well if the item the path refers to is itself
|
|
|
|
// stable. We only emit errors for unstable path segments if the item is stable
|
|
|
|
// or allowed because stability is often inherited, so the most common case is that
|
|
|
|
// both the segments and the item are unstable behind the same feature flag.
|
|
|
|
//
|
|
|
|
// We check here rather than in `visit_path_segment` to prevent visiting the last
|
|
|
|
// path segment twice
|
|
|
|
//
|
|
|
|
// We include special cases via #[rustc_allowed_through_unstable_modules] for items
|
|
|
|
// that were accidentally stabilized through unstable paths before this check was
|
|
|
|
// added, such as `core::intrinsics::transmute`
|
|
|
|
let parents = path.segments.iter().rev().skip(1);
|
|
|
|
for path_segment in parents {
|
|
|
|
if let Some(def_id) = path_segment.res.opt_def_id() {
|
|
|
|
match is_allowed_through_unstable_modules {
|
|
|
|
None => {
|
|
|
|
// Emit a hard stability error if this path is not stable.
|
|
|
|
|
|
|
|
// use `None` for id to prevent deprecation check
|
|
|
|
self.tcx.check_stability_allow_unstable(
|
|
|
|
def_id,
|
|
|
|
None,
|
|
|
|
path.span,
|
|
|
|
None,
|
|
|
|
if is_unstable_reexport(self.tcx, id) {
|
|
|
|
AllowUnstable::Yes
|
|
|
|
} else {
|
|
|
|
AllowUnstable::No
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
Some(deprecation) => {
|
|
|
|
// Call the stability check directly so that we can control which
|
|
|
|
// diagnostic is emitted.
|
|
|
|
let eval_result = self.tcx.eval_stability_allow_unstable(
|
|
|
|
def_id,
|
|
|
|
None,
|
|
|
|
path.span,
|
|
|
|
None,
|
|
|
|
if is_unstable_reexport(self.tcx, id) {
|
|
|
|
AllowUnstable::Yes
|
|
|
|
} else {
|
|
|
|
AllowUnstable::No
|
|
|
|
},
|
2025-01-01 18:09:01 +00:00
|
|
|
);
|
2025-02-02 11:33:40 +00:00
|
|
|
let is_allowed = matches!(eval_result, EvalResult::Allow);
|
|
|
|
if !is_allowed {
|
|
|
|
// Calculating message for lint involves calling `self.def_path_str`,
|
|
|
|
// which will by default invoke the expensive `visible_parent_map` query.
|
|
|
|
// Skip all that work if the lint is allowed anyway.
|
|
|
|
if self.tcx.lint_level_at_node(DEPRECATED, id).0
|
|
|
|
== lint::Level::Allow
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Show a deprecation message.
|
|
|
|
let def_path =
|
|
|
|
with_no_trimmed_paths!(self.tcx.def_path_str(def_id));
|
|
|
|
let def_kind = self.tcx.def_descr(def_id);
|
|
|
|
let diag = Deprecated {
|
|
|
|
sub: None,
|
|
|
|
kind: def_kind.to_owned(),
|
|
|
|
path: def_path,
|
|
|
|
note: Some(deprecation),
|
|
|
|
since_kind: lint::DeprecatedSinceKind::InEffect,
|
|
|
|
};
|
|
|
|
self.tcx.emit_node_span_lint(
|
|
|
|
DEPRECATED,
|
|
|
|
id,
|
|
|
|
method_span.unwrap_or(path.span),
|
|
|
|
diag,
|
|
|
|
);
|
|
|
|
}
|
2025-01-01 18:09:01 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-12 01:12:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-11-10 17:08:21 +00:00
|
|
|
}
|
2022-04-12 01:12:26 +00:00
|
|
|
|
2016-11-10 17:08:21 +00:00
|
|
|
intravisit::walk_path(self, path)
|
2016-10-27 02:17:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-04 22:05:33 +00:00
|
|
|
/// Check whether a path is a `use` item that has been marked as unstable.
|
|
|
|
///
|
|
|
|
/// See issue #94972 for details on why this is a special case
|
2022-12-20 21:10:40 +00:00
|
|
|
fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
2022-06-04 22:05:33 +00:00
|
|
|
// Get the LocalDefId so we can lookup the item to check the kind.
|
2023-07-13 01:49:27 +00:00
|
|
|
let Some(owner) = id.as_owner() else {
|
|
|
|
return false;
|
|
|
|
};
|
2022-11-05 15:33:58 +00:00
|
|
|
let def_id = owner.def_id;
|
2022-06-04 22:05:33 +00:00
|
|
|
|
|
|
|
let Some(stab) = tcx.stability().local_stability(def_id) else {
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
if stab.level.is_stable() {
|
|
|
|
// The re-export is not marked as unstable, don't override
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this is a path that isn't a use, we don't need to do anything special
|
2025-02-21 07:33:05 +00:00
|
|
|
if !matches!(tcx.hir_expect_item(def_id).kind, ItemKind::Use(..)) {
|
2022-06-04 22:05:33 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2020-09-09 20:16:13 +00:00
|
|
|
struct CheckTraitImplStable<'tcx> {
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
fully_stable: bool,
|
|
|
|
}
|
|
|
|
|
2021-12-14 05:16:36 +00:00
|
|
|
impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
|
2022-11-25 08:26:36 +00:00
|
|
|
fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: hir::HirId) {
|
2020-09-09 20:16:13 +00:00
|
|
|
if let Some(def_id) = path.res.opt_def_id() {
|
|
|
|
if let Some(stab) = self.tcx.lookup_stability(def_id) {
|
|
|
|
self.fully_stable &= stab.level.is_stable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
intravisit::walk_path(self, path)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
|
|
|
|
if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
|
|
|
|
if let Some(stab) = self.tcx.lookup_stability(trait_did) {
|
|
|
|
self.fully_stable &= stab.level.is_stable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
intravisit::walk_trait_ref(self, t)
|
|
|
|
}
|
|
|
|
|
2025-01-11 19:12:36 +00:00
|
|
|
fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) {
|
2022-10-19 11:33:45 +00:00
|
|
|
if let TyKind::Never = t.kind {
|
|
|
|
self.fully_stable = false;
|
|
|
|
}
|
2025-02-05 19:18:18 +00:00
|
|
|
if let TyKind::BareFn(function) = t.kind {
|
|
|
|
if extern_abi_stability(function.abi).is_err() {
|
2022-10-19 11:33:45 +00:00
|
|
|
self.fully_stable = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
intravisit::walk_ty(self, t)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
|
|
|
|
for ty in fd.inputs {
|
2025-01-18 22:45:41 +00:00
|
|
|
self.visit_ty_unambig(ty)
|
2022-10-19 11:33:45 +00:00
|
|
|
}
|
|
|
|
if let hir::FnRetTy::Return(output_ty) = fd.output {
|
|
|
|
match output_ty.kind {
|
|
|
|
TyKind::Never => {} // `-> !` is stable
|
2025-01-18 22:45:41 +00:00
|
|
|
_ => self.visit_ty_unambig(output_ty),
|
2022-10-19 10:41:35 +00:00
|
|
|
}
|
2020-09-09 20:16:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-27 02:59:49 +00:00
|
|
|
/// Given the list of enabled features that were not language features (i.e., that
|
2015-01-14 23:20:14 +00:00
|
|
|
/// were expected to be library features), and the list of features used from
|
|
|
|
/// libraries, identify activated features that don't exist and error about them.
|
2019-06-21 21:49:03 +00:00
|
|
|
pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
|
2022-01-16 15:30:33 +00:00
|
|
|
let is_staged_api =
|
2024-10-09 07:01:57 +00:00
|
|
|
tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api();
|
2022-01-16 15:30:33 +00:00
|
|
|
if is_staged_api {
|
2022-09-22 13:19:53 +00:00
|
|
|
let effective_visibilities = &tcx.effective_visibilities(());
|
|
|
|
let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
|
2021-08-26 16:42:08 +00:00
|
|
|
missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
|
2025-02-17 03:17:57 +00:00
|
|
|
tcx.hir_walk_toplevel_module(&mut missing);
|
|
|
|
tcx.hir_visit_all_item_likes_in_crate(&mut missing);
|
2016-11-10 17:08:21 +00:00
|
|
|
}
|
|
|
|
|
2024-10-09 06:30:43 +00:00
|
|
|
let enabled_lang_features = tcx.features().enabled_lang_features();
|
2023-12-21 09:52:27 +00:00
|
|
|
let mut lang_features = UnordSet::default();
|
2024-10-24 15:53:08 +00:00
|
|
|
for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features {
|
|
|
|
if let Some(version) = stable_since {
|
2018-07-23 01:03:01 +00:00
|
|
|
// Warn if the user has enabled an already-stable lang feature.
|
2024-10-24 15:53:08 +00:00
|
|
|
unnecessary_stable_feature_lint(tcx, *attr_sp, *gate_name, *version);
|
2018-07-23 01:03:01 +00:00
|
|
|
}
|
2024-10-24 15:53:08 +00:00
|
|
|
if !lang_features.insert(gate_name) {
|
2018-07-23 01:03:01 +00:00
|
|
|
// Warn if the user enables a lang feature multiple times.
|
2024-10-24 15:53:08 +00:00
|
|
|
tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
|
2018-07-23 01:03:01 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-23 00:20:33 +00:00
|
|
|
|
2024-10-09 06:30:43 +00:00
|
|
|
let enabled_lib_features = tcx.features().enabled_lib_features();
|
2022-02-21 17:59:24 +00:00
|
|
|
let mut remaining_lib_features = FxIndexMap::default();
|
2024-10-24 15:53:08 +00:00
|
|
|
for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features {
|
|
|
|
if remaining_lib_features.contains_key(gate_name) {
|
2018-07-23 16:34:04 +00:00
|
|
|
// Warn if the user enables a lib feature multiple times.
|
2024-10-24 15:53:08 +00:00
|
|
|
tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
|
2018-07-23 00:22:01 +00:00
|
|
|
}
|
2024-10-24 15:53:08 +00:00
|
|
|
remaining_lib_features.insert(*gate_name, *attr_sp);
|
2018-07-23 00:20:33 +00:00
|
|
|
}
|
2018-07-23 23:56:00 +00:00
|
|
|
// `stdbuild` has special handling for `libc`, so we need to
|
|
|
|
// recognise the feature when building std.
|
2018-08-06 15:46:08 +00:00
|
|
|
// Likewise, libtest is handled specially, so `test` isn't
|
|
|
|
// available as we'd like it to be.
|
2024-10-08 12:06:56 +00:00
|
|
|
// FIXME: only remove `libc` when `stdbuild` is enabled.
|
2018-08-06 15:46:08 +00:00
|
|
|
// FIXME: remove special casing for `test`.
|
2024-01-28 20:53:28 +00:00
|
|
|
// FIXME(#120456) - is `swap_remove` correct?
|
|
|
|
remaining_lib_features.swap_remove(&sym::libc);
|
|
|
|
remaining_lib_features.swap_remove(&sym::test);
|
2018-07-23 00:20:33 +00:00
|
|
|
|
2022-08-02 16:27:18 +00:00
|
|
|
/// For each feature in `defined_features`..
|
|
|
|
///
|
|
|
|
/// - If it is in `remaining_lib_features` (those features with `#![feature(..)]` attributes in
|
|
|
|
/// the current crate), check if it is stable (or partially stable) and thus an unnecessary
|
|
|
|
/// attribute.
|
|
|
|
/// - If it is in `remaining_implications` (a feature that is referenced by an `implied_by`
|
|
|
|
/// from the current crate), then remove it from the remaining implications.
|
|
|
|
///
|
|
|
|
/// Once this function has been invoked for every feature (local crate and all extern crates),
|
|
|
|
/// then..
|
|
|
|
///
|
|
|
|
/// - If features remain in `remaining_lib_features`, then the user has enabled a feature that
|
|
|
|
/// does not exist.
|
|
|
|
/// - If features remain in `remaining_implications`, the `implied_by` refers to a feature that
|
|
|
|
/// does not exist.
|
|
|
|
///
|
|
|
|
/// By structuring the code in this way: checking the features defined from each crate one at a
|
|
|
|
/// time, less loading from metadata is performed and thus compiler performance is improved.
|
|
|
|
fn check_features<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
2024-10-24 15:53:08 +00:00
|
|
|
remaining_lib_features: &mut FxIndexMap<Symbol, Span>,
|
2023-12-21 09:52:27 +00:00
|
|
|
remaining_implications: &mut UnordMap<Symbol, Symbol>,
|
2023-09-23 05:38:49 +00:00
|
|
|
defined_features: &LibFeatures,
|
2023-12-21 09:52:27 +00:00
|
|
|
all_implications: &UnordMap<Symbol, Symbol>,
|
2022-08-02 16:27:18 +00:00
|
|
|
) {
|
2023-12-21 09:52:27 +00:00
|
|
|
for (feature, since) in defined_features.to_sorted_vec() {
|
2023-09-23 05:38:49 +00:00
|
|
|
if let FeatureStability::AcceptedSince(since) = since
|
2023-10-13 08:58:33 +00:00
|
|
|
&& let Some(span) = remaining_lib_features.get(&feature)
|
|
|
|
{
|
2022-07-13 14:10:19 +00:00
|
|
|
// Warn if the user has enabled an already-stable lib feature.
|
2022-08-02 16:27:18 +00:00
|
|
|
if let Some(implies) = all_implications.get(&feature) {
|
2023-09-23 05:38:49 +00:00
|
|
|
unnecessary_partially_stable_feature_lint(tcx, *span, feature, *implies, since);
|
2022-07-13 14:10:19 +00:00
|
|
|
} else {
|
2023-09-23 05:38:49 +00:00
|
|
|
unnecessary_stable_feature_lint(tcx, *span, feature, since);
|
2018-08-21 00:39:48 +00:00
|
|
|
}
|
|
|
|
}
|
2024-01-28 20:53:28 +00:00
|
|
|
// FIXME(#120456) - is `swap_remove` correct?
|
|
|
|
remaining_lib_features.swap_remove(&feature);
|
2022-08-02 16:27:18 +00:00
|
|
|
|
|
|
|
// `feature` is the feature doing the implying, but `implied_by` is the feature with
|
|
|
|
// the attribute that establishes this relationship. `implied_by` is guaranteed to be a
|
|
|
|
// feature defined in the local crate because `remaining_implications` is only the
|
|
|
|
// implications from this crate.
|
2023-09-23 05:38:49 +00:00
|
|
|
remaining_implications.remove(&feature);
|
2022-08-02 16:27:18 +00:00
|
|
|
|
|
|
|
if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
|
2019-12-22 22:42:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-07-23 00:20:33 +00:00
|
|
|
}
|
|
|
|
|
2022-08-02 16:27:18 +00:00
|
|
|
// All local crate implications need to have the feature that implies it confirmed to exist.
|
2023-11-17 23:40:04 +00:00
|
|
|
let mut remaining_implications = tcx.stability_implications(LOCAL_CRATE).clone();
|
2022-08-02 16:27:18 +00:00
|
|
|
|
2024-10-08 12:06:56 +00:00
|
|
|
// We always collect the lib features enabled in the current crate, even if there are
|
2022-08-02 16:27:18 +00:00
|
|
|
// no unknown features, because the collection also does feature attribute validation.
|
2023-11-17 23:40:04 +00:00
|
|
|
let local_defined_features = tcx.lib_features(LOCAL_CRATE);
|
2022-08-02 16:27:18 +00:00
|
|
|
if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() {
|
|
|
|
// Loading the implications of all crates is unavoidable to be able to emit the partial
|
|
|
|
// stabilization diagnostic, but it can be avoided when there are no
|
|
|
|
// `remaining_lib_features`.
|
|
|
|
let mut all_implications = remaining_implications.clone();
|
2024-06-06 09:45:50 +00:00
|
|
|
for &cnum in tcx.crates(()) {
|
2023-12-21 09:52:27 +00:00
|
|
|
all_implications
|
|
|
|
.extend_unord(tcx.stability_implications(cnum).items().map(|(k, v)| (*k, *v)));
|
2022-08-02 16:27:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
check_features(
|
|
|
|
tcx,
|
|
|
|
&mut remaining_lib_features,
|
|
|
|
&mut remaining_implications,
|
2023-09-23 05:38:49 +00:00
|
|
|
local_defined_features,
|
2022-08-02 16:27:18 +00:00
|
|
|
&all_implications,
|
|
|
|
);
|
|
|
|
|
2024-06-06 09:45:50 +00:00
|
|
|
for &cnum in tcx.crates(()) {
|
2022-08-02 16:27:18 +00:00
|
|
|
if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
check_features(
|
|
|
|
tcx,
|
|
|
|
&mut remaining_lib_features,
|
|
|
|
&mut remaining_implications,
|
2023-09-23 05:38:49 +00:00
|
|
|
tcx.lib_features(cnum),
|
2022-08-02 16:27:18 +00:00
|
|
|
&all_implications,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-23 00:20:33 +00:00
|
|
|
for (feature, span) in remaining_lib_features {
|
2024-10-24 15:53:08 +00:00
|
|
|
tcx.dcx().emit_err(errors::UnknownFeature { span, feature });
|
2018-07-23 00:20:33 +00:00
|
|
|
}
|
|
|
|
|
2023-12-21 09:52:27 +00:00
|
|
|
for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() {
|
2023-11-17 23:40:04 +00:00
|
|
|
let local_defined_features = tcx.lib_features(LOCAL_CRATE);
|
|
|
|
let span = local_defined_features
|
|
|
|
.stability
|
2022-08-02 16:27:18 +00:00
|
|
|
.get(&feature)
|
2023-11-17 23:40:04 +00:00
|
|
|
.expect("feature that implied another does not exist")
|
|
|
|
.1;
|
2023-12-18 11:21:37 +00:00
|
|
|
tcx.dcx().emit_err(errors::ImpliedFeatureNotExist { span, feature, implied_by });
|
2022-08-02 16:27:18 +00:00
|
|
|
}
|
|
|
|
|
2018-07-23 00:20:33 +00:00
|
|
|
// FIXME(#44232): the `used_features` table no longer exists, so we
|
2020-03-06 11:13:55 +00:00
|
|
|
// don't lint about unused features. We should re-enable this one day!
|
2017-08-31 22:08:34 +00:00
|
|
|
}
|
2015-01-16 18:25:16 +00:00
|
|
|
|
2022-07-13 14:10:19 +00:00
|
|
|
fn unnecessary_partially_stable_feature_lint(
|
|
|
|
tcx: TyCtxt<'_>,
|
|
|
|
span: Span,
|
|
|
|
feature: Symbol,
|
|
|
|
implies: Symbol,
|
|
|
|
since: Symbol,
|
|
|
|
) {
|
2024-01-16 05:27:02 +00:00
|
|
|
tcx.emit_node_span_lint(
|
2022-09-16 07:01:02 +00:00
|
|
|
lint::builtin::STABLE_FEATURES,
|
|
|
|
hir::CRATE_HIR_ID,
|
|
|
|
span,
|
2023-04-25 17:42:42 +00:00
|
|
|
errors::UnnecessaryPartialStableFeature {
|
|
|
|
span,
|
|
|
|
line: tcx.sess.source_map().span_extend_to_line(span),
|
|
|
|
feature,
|
|
|
|
since,
|
|
|
|
implies,
|
2022-09-16 07:01:02 +00:00
|
|
|
},
|
|
|
|
);
|
2022-07-13 14:10:19 +00:00
|
|
|
}
|
|
|
|
|
2022-09-13 17:46:08 +00:00
|
|
|
fn unnecessary_stable_feature_lint(
|
|
|
|
tcx: TyCtxt<'_>,
|
|
|
|
span: Span,
|
|
|
|
feature: Symbol,
|
|
|
|
mut since: Symbol,
|
|
|
|
) {
|
|
|
|
if since.as_str() == VERSION_PLACEHOLDER {
|
2023-10-25 21:05:42 +00:00
|
|
|
since = sym::env_CFG_RELEASE;
|
2022-09-13 17:46:08 +00:00
|
|
|
}
|
2024-01-16 05:27:02 +00:00
|
|
|
tcx.emit_node_span_lint(
|
2023-04-25 17:42:42 +00:00
|
|
|
lint::builtin::STABLE_FEATURES,
|
|
|
|
hir::CRATE_HIR_ID,
|
|
|
|
span,
|
|
|
|
errors::UnnecessaryStableFeature { feature, since },
|
|
|
|
);
|
2018-07-23 16:34:04 +00:00
|
|
|
}
|