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.
2023-02-05 01:49:50 +00:00
use crate ::errors ;
2022-04-27 14:14:19 +00:00
use rustc_attr ::{
2022-09-13 17:46:08 +00:00
self as attr , rust_version_symbol , ConstStability , Stability , StabilityLevel , Unstable ,
UnstableReason , VERSION_PLACEHOLDER ,
2022-04-27 14:14:19 +00:00
} ;
2022-07-20 13:52:23 +00:00
use rustc_data_structures ::fx ::{ FxHashMap , FxHashSet , FxIndexMap } ;
2022-10-03 03:22:46 +00:00
use rustc_errors ::Applicability ;
2020-01-05 01:37:57 +00:00
use rustc_hir as hir ;
use rustc_hir ::def ::{ DefKind , Res } ;
2022-04-15 17:27:53 +00:00
use rustc_hir ::def_id ::{ LocalDefId , CRATE_DEF_ID } ;
2021-08-26 16:42:08 +00:00
use rustc_hir ::hir_id ::CRATE_HIR_ID ;
2021-11-03 23:03:12 +00:00
use rustc_hir ::intravisit ::{ self , Visitor } ;
2022-08-10 01:22:01 +00:00
use rustc_hir ::{ FieldDef , Item , ItemKind , TraitRef , Ty , TyKind , Variant } ;
2021-11-03 23:03:12 +00:00
use rustc_middle ::hir ::nested_filter ;
2022-09-22 13:19:53 +00:00
use rustc_middle ::middle ::privacy ::EffectiveVisibilities ;
2022-06-04 22:05:33 +00:00
use rustc_middle ::middle ::stability ::{ AllowUnstable , DeprecationEntry , Index } ;
2022-06-30 02:33:18 +00:00
use rustc_middle ::ty ::{ query ::Providers , TyCtxt } ;
2020-03-11 11:49:08 +00:00
use rustc_session ::lint ;
2020-11-01 11:58:47 +00:00
use rustc_session ::lint ::builtin ::{ INEFFECTIVE_UNSTABLE_TRAIT_IMPL , USELESS_DEPRECATED } ;
2020-01-01 18:30:57 +00:00
use rustc_span ::symbol ::{ sym , Symbol } ;
2022-06-30 02:33:18 +00:00
use rustc_span ::Span ;
2021-07-03 10:07:06 +00:00
use rustc_target ::spec ::abi ::Abi ;
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-06-12 00:18:46 +00:00
use std ::cmp ::Ordering ;
2021-03-08 23:32:41 +00:00
use std ::iter ;
2019-11-11 17:33:30 +00:00
use std ::mem ::replace ;
use std ::num ::NonZeroU32 ;
2014-09-12 10:10:30 +00:00
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-02-18 14:35:20 +00:00
fn annotate < F > (
& mut self ,
2021-07-28 15:23:40 +00:00
def_id : LocalDefId ,
2015-11-16 16:53:41 +00:00
item_sp : Span ,
2021-07-03 10:07:06 +00:00
fn_sig : Option < & ' tcx hir ::FnSig < ' tcx > > ,
2015-11-16 16:53:41 +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 ,
2015-11-16 16:53:41 +00:00
visit_children : F ,
2016-11-09 21:45:26 +00:00
) where
F : FnOnce ( & mut Self ) ,
2014-12-09 01:26:43 +00:00
{
2022-05-02 07:31:56 +00:00
let attrs = self . tcx . hir ( ) . attrs ( self . tcx . hir ( ) . 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
2022-01-18 19:37:14 +00:00
let depr = attr ::find_deprecation ( & self . tcx . sess , attrs ) ;
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 ) {
2021-07-28 15:23:40 +00:00
let hir_id = self . tcx . hir ( ) . local_def_id_to_hir_id ( def_id ) ;
2022-09-14 18:03:12 +00:00
self . tcx . emit_spanned_lint (
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
}
2022-01-18 19:37:14 +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 ) ;
}
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
2022-04-27 14:14:19 +00:00
let ( stab , const_stab , body_stab ) = attr ::find_stability ( & self . tcx . sess , attrs , item_sp ) ;
2021-07-03 10:07:06 +00:00
let mut const_span = None ;
2020-02-07 18:24:22 +00:00
2021-07-03 10:07:06 +00:00
let const_stab = const_stab . map ( | ( const_stab , const_span_node ) | {
2021-07-28 15:23:40 +00:00
self . index . const_stab_map . insert ( def_id , const_stab ) ;
2021-07-03 10:07:06 +00:00
const_span = Some ( const_span_node ) ;
2020-02-07 18:24:22 +00:00
const_stab
} ) ;
2021-07-03 10:07:06 +00:00
// If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI,
// check if the function/method is const or the parent impl block is const
if let ( Some ( const_span ) , Some ( fn_sig ) ) = ( const_span , fn_sig ) {
if fn_sig . header . abi ! = Abi ::RustIntrinsic
& & fn_sig . header . abi ! = Abi ::PlatformIntrinsic
& & ! fn_sig . header . is_const ( )
{
if ! self . in_trait_impl
2021-07-28 15:23:40 +00:00
| | ( self . in_trait_impl & & ! self . tcx . is_const_fn_raw ( def_id . to_def_id ( ) ) )
2021-07-03 10:07:06 +00:00
{
2022-10-03 03:22:46 +00:00
self . tcx
. sess
2023-02-05 01:49:50 +00:00
. emit_err ( errors ::MissingConstErr { fn_sig_span : fn_sig . span , const_span } ) ;
2021-07-03 10:07:06 +00:00
}
}
}
2021-01-16 19:59:21 +00:00
// `impl const Trait for Type` items forward their const stability to their
// immediate children.
2020-02-07 18:24:22 +00:00
if const_stab . is_none ( ) {
debug! ( " annotate: const_stab not found, parent = {:?} " , self . parent_const_stab ) ;
if let Some ( parent ) = self . parent_const_stab {
2022-02-08 09:52:11 +00:00
if parent . is_const_unstable ( ) {
2021-07-28 15:23:40 +00:00
self . index . const_stab_map . insert ( def_id , parent ) ;
2020-02-07 18:24:22 +00:00
}
}
2020-02-07 17:56:56 +00:00
}
2020-02-07 18:24:22 +00:00
2020-11-01 11:29:57 +00:00
if let Some ( ( rustc_attr ::Deprecation { is_since_rustc_version : true , .. } , span ) ) = & depr {
2020-07-20 14:44:43 +00:00
if stab . is_none ( ) {
2023-02-05 01:49:50 +00:00
self . tcx . sess . emit_err ( errors ::DeprecatedAttribute { span : * span } ) ;
2020-07-20 14:44:43 +00:00
}
}
2022-07-31 12:29:31 +00:00
if let Some ( ( body_stab , _span ) ) = 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-02-05 01:49:50 +00:00
self . tcx . sess . 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.
2022-05-09 22:18:53 +00:00
if let ( & Some ( dep_since ) , & attr ::Stable { since : stab_since , .. } ) =
2020-11-01 11:29:57 +00:00
( & depr . as_ref ( ) . and_then ( | ( d , _ ) | d . since ) , & stab . level )
2020-02-07 17:56:56 +00:00
{
// Explicit version of iter::order::lt to handle parse errors properly
for ( dep_v , stab_v ) in
2021-03-08 23:32:41 +00:00
iter ::zip ( dep_since . as_str ( ) . split ( '.' ) , stab_since . as_str ( ) . split ( '.' ) )
2016-11-16 10:52:37 +00:00
{
2020-12-09 23:26:42 +00:00
match stab_v . parse ::< u64 > ( ) {
Err ( _ ) = > {
2023-02-05 01:49:50 +00:00
self . tcx . sess . emit_err ( errors ::InvalidStability { span , item_sp } ) ;
2020-12-09 23:26:42 +00:00
break ;
}
Ok ( stab_vp ) = > match dep_v . parse ::< u64 > ( ) {
Ok ( dep_vp ) = > match dep_vp . cmp ( & stab_vp ) {
Ordering ::Less = > {
2023-02-05 01:49:50 +00:00
self . tcx . sess . emit_err ( errors ::CannotStabilizeDeprecated {
span ,
item_sp ,
} ) ;
2020-12-09 23:26:42 +00:00
break ;
}
Ordering ::Equal = > continue ,
Ordering ::Greater = > break ,
} ,
Err ( _ ) = > {
if dep_v ! = " TBD " {
2023-02-05 01:49:50 +00:00
self . tcx . sess . emit_err ( errors ::InvalidDeprecationVersion {
span ,
item_sp ,
} ) ;
2020-12-09 23:26:42 +00:00
}
2020-02-07 17:56:56 +00:00
break ;
2015-06-12 00:18:46 +00:00
}
2020-12-09 23:26:42 +00:00
} ,
2015-06-12 00:18:46 +00:00
}
2015-11-16 16:53:41 +00:00
}
2020-02-07 17:56:56 +00:00
}
2015-06-12 00:18:46 +00:00
2022-10-03 03:22:46 +00:00
if let Stability { level : Unstable { implied_by : Some ( implied_by ) , .. } , feature } =
stab
{
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
}
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 ,
2021-01-16 19:59:21 +00:00
if inherit_const_stability . yes ( ) { const_stab } else { None } ,
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
2021-11-03 23:03:12 +00:00
fn nested_visit_map ( & mut self ) -> Self ::Map {
self . tcx . hir ( )
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
}
2018-07-11 15:36:06 +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
}
}
2021-07-03 10:07:06 +00:00
hir ::ItemKind ::Fn ( ref item_fn_sig , _ , _ ) = > {
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 > ) {
2015-11-16 18:01:06 +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 > ) {
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 ,
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 ::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 ) ;
2022-09-22 13:19:53 +00:00
if ! self . tcx . sess . opts . test
& & stab . is_none ( )
& & self . effective_visibilities . is_reachable ( def_id )
{
2020-04-24 19:26:11 +00:00
let descr = self . tcx . def_kind ( def_id ) . descr ( def_id . to_def_id ( ) ) ;
2023-02-05 01:49:50 +00:00
self . tcx . sess . emit_err ( errors ::MissingStabilityAttr { span , descr } ) ;
2016-11-10 17:08:21 +00:00
}
}
2020-09-25 20:48:48 +00:00
2021-07-28 15:23:40 +00:00
fn check_missing_const_stability ( & self , def_id : LocalDefId , span : Span ) {
2021-11-18 02:06:17 +00:00
if ! self . tcx . features ( ) . staged_api {
return ;
}
2022-11-12 12:57:10 +00:00
// if the const impl is derived using the `derive_const` attribute,
// then it would be "stable" at least for the impl.
// We gate usages of it using `feature(const_trait_impl)` anyways
// so there is no unstable leakage
if self . tcx . is_builtin_derive ( def_id . to_def_id ( ) ) {
return ;
}
2022-02-13 10:54:00 +00:00
let is_const = self . tcx . is_const_fn ( def_id . to_def_id ( ) )
| | self . tcx . is_const_trait_impl_raw ( def_id . to_def_id ( ) ) ;
2021-11-18 02:06:17 +00:00
let is_stable = self
. tcx
. lookup_stability ( def_id )
. map_or ( false , | stability | stability . level . is_stable ( ) ) ;
let missing_const_stability_attribute = self . tcx . lookup_const_stability ( def_id ) . is_none ( ) ;
2022-09-22 13:19:53 +00:00
let is_reachable = self . effective_visibilities . is_reachable ( def_id ) ;
2021-11-18 02:06:17 +00:00
if is_const & & is_stable & & missing_const_stability_attribute & & is_reachable {
let descr = self . tcx . def_kind ( def_id ) . descr ( def_id . to_def_id ( ) ) ;
2023-02-05 01:49:50 +00:00
self . tcx . sess . 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
2021-11-03 23:03:12 +00:00
fn nested_visit_map ( & mut self ) -> Self ::Map {
self . tcx . hir ( )
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.
2022-10-27 03:02:18 +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 > ) {
2021-10-21 17:41:47 +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 ) ;
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 ,
2019-12-29 10:20:20 +00:00
issue : NonZeroU32 ::new ( 27812 ) ,
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 ,
2021-09-02 17:22:24 +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.
2020-06-27 11:09:54 +00:00
fn check_mod_unstable_api_usage ( tcx : TyCtxt < '_ > , module_def_id : LocalDefId ) {
2022-07-03 13:28: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 ( ) ,
2022-01-16 21:26:46 +00:00
lookup_stability : | tcx , id | tcx . stability ( ) . local_stability ( id . expect_local ( ) ) ,
lookup_const_stability : | tcx , id | tcx . stability ( ) . local_const_stability ( id . expect_local ( ) ) ,
2022-04-27 14:14:19 +00:00
lookup_default_body_stability : | tcx , id | {
tcx . stability ( ) . local_default_body_stability ( id . expect_local ( ) )
} ,
2022-01-16 21:26:46 +00:00
lookup_deprecation_entry : | tcx , id | {
tcx . stability ( ) . local_deprecation_entry ( id . expect_local ( ) )
} ,
.. * 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.
2021-11-03 23:03:12 +00:00
fn nested_visit_map ( & mut self ) -> Self ::Map {
self . tcx . hir ( )
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 {
2018-07-11 15:36:06 +00:00
hir ::ItemKind ::ExternCrate ( _ ) = > {
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.
2022-04-05 12:52:53 +00:00
if item . span . is_dummy ( ) & & item . ident . name ! = sym ::std {
2018-06-24 22:00:21 +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.
2022-02-22 19:54:47 +00:00
hir ::ItemKind ::Impl ( hir ::Impl {
of_trait : Some ( ref t ) ,
self_ty ,
items ,
constness ,
..
} ) = > {
let features = self . tcx . features ( ) ;
if features . staged_api {
let attrs = self . tcx . hir ( ) . attrs ( item . hir_id ( ) ) ;
2022-04-27 14:14:19 +00:00
let ( stab , const_stab , _ ) =
attr ::find_stability ( & self . tcx . sess , attrs , item . span ) ;
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
2022-02-22 19:54:47 +00:00
if let Some ( ( Stability { level : attr ::Unstable { .. } , .. } , span ) ) = stab {
2020-09-10 18:43:13 +00:00
let mut c = CheckTraitImplStable { tcx : self . tcx , fully_stable : true } ;
c . visit_ty ( self_ty ) ;
c . visit_trait_ref ( t ) ;
if c . fully_stable {
self . tcx . struct_span_lint_hir (
INEFFECTIVE_UNSTABLE_TRAIT_IMPL ,
2021-01-30 16:47:51 +00:00
item . hir_id ( ) ,
2020-09-10 18:43:13 +00:00
span ,
2022-09-16 07:01:02 +00:00
" an `#[unstable]` annotation here has no effect " ,
| lint | lint . note ( " see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information " )
2020-09-10 18:43:13 +00:00
) ;
}
2020-09-09 20:16:13 +00:00
}
2022-02-22 19:54:47 +00:00
// `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
// needs to have an error emitted.
if features . const_trait_impl
2022-05-19 12:26:06 +00:00
& & * constness = = hir ::Constness ::Const
2022-02-22 19:54:47 +00:00
& & const_stab . map_or ( false , | ( stab , _ ) | stab . is_const_stable ( ) )
{
2023-02-05 01:49:50 +00:00
self . tcx . sess . emit_err ( errors ::TraitImplConstStable { span : item . span } ) ;
2022-02-22 19:54:47 +00:00
}
2020-09-09 20:16:13 +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
2016-11-10 17:08:21 +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
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
) ;
2022-05-09 22:18:53 +00:00
let is_allowed_through_unstable_modules = | def_id | {
self . tcx
. lookup_stability ( def_id )
. map ( | stab | match stab . level {
StabilityLevel ::Stable { allowed_through_unstable_modules , .. } = > {
allowed_through_unstable_modules
}
_ = > false ,
} )
. unwrap_or ( false )
} ;
if item_is_allowed & & ! is_allowed_through_unstable_modules ( def_id ) {
2022-05-07 18:08:31 +00:00
// Check parent modules stability as well if the item the path refers to is itself
// stable. We only emit warnings for unstable path segments if the item is stable
2022-05-07 18:31:53 +00:00
// 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.
2022-04-12 01:12:26 +00:00
//
// We check here rather than in `visit_path_segment` to prevent visiting the last
// path segment twice
2022-05-09 22:18:53 +00:00
//
// 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`
2022-04-12 01:12:26 +00:00
let parents = path . segments . iter ( ) . rev ( ) . skip ( 1 ) ;
for path_segment in parents {
2022-08-30 05:10:28 +00:00
if let Some ( def_id ) = path_segment . res . opt_def_id ( ) {
2022-04-12 01:12:26 +00:00
// 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
} ,
2022-07-07 22:29:38 +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.
2022-11-05 15:33:58 +00:00
let Some ( owner ) = id . as_owner ( ) else { return false ; } ;
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
2022-09-20 05:11:23 +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 )
}
fn visit_ty ( & mut self , t : & ' tcx Ty < ' tcx > ) {
2022-10-19 11:33:45 +00:00
if let TyKind ::Never = t . kind {
self . fully_stable = false ;
}
if let TyKind ::BareFn ( f ) = t . kind {
if rustc_target ::spec ::abi ::is_stable ( f . abi . name ( ) ) . is_err ( ) {
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 {
self . visit_ty ( ty )
}
if let hir ::FnRetTy ::Return ( output_ty ) = fd . output {
match output_ty . kind {
TyKind ::Never = > { } // `-> !` is stable
_ = > self . visit_ty ( 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 =
2022-07-06 12:44:47 +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 ) ) ;
2021-09-02 17:22:24 +00:00
tcx . hir ( ) . walk_toplevel_module ( & mut missing ) ;
2022-07-03 13:28:57 +00:00
tcx . hir ( ) . visit_all_item_likes_in_crate ( & mut missing ) ;
2016-11-10 17:08:21 +00:00
}
2018-07-23 01:03:01 +00:00
let declared_lang_features = & tcx . features ( ) . declared_lang_features ;
2018-10-16 08:44:26 +00:00
let mut lang_features = FxHashSet ::default ( ) ;
2018-07-23 16:34:04 +00:00
for & ( feature , span , since ) in declared_lang_features {
2018-07-23 01:03:01 +00:00
if let Some ( since ) = since {
// Warn if the user has enabled an already-stable lang feature.
2018-07-23 16:34:04 +00:00
unnecessary_stable_feature_lint ( tcx , span , feature , since ) ;
2018-07-23 01:03:01 +00:00
}
2019-10-16 04:48:20 +00:00
if ! lang_features . insert ( feature ) {
2018-07-23 01:03:01 +00:00
// Warn if the user enables a lang feature multiple times.
2023-02-05 01:49:50 +00:00
tcx . sess . emit_err ( errors ::DuplicateFeatureErr { span , feature } ) ;
2018-07-23 01:03:01 +00:00
}
}
2018-07-23 00:20:33 +00:00
2018-07-23 01:03:01 +00:00
let declared_lib_features = & tcx . features ( ) . declared_lib_features ;
2022-02-21 17:59:24 +00:00
let mut remaining_lib_features = FxIndexMap ::default ( ) ;
2018-07-23 01:03:01 +00:00
for ( feature , span ) in declared_lib_features {
2021-09-16 13:58:03 +00:00
if ! tcx . sess . opts . unstable_features . is_nightly_build ( ) {
2023-02-05 01:49:50 +00:00
tcx . sess . emit_err ( errors ::FeatureOnlyOnNightly {
2022-10-03 03:22:46 +00:00
span : * span ,
release_channel : env ! ( " CFG_RELEASE_CHANNEL " ) ,
} ) ;
2021-09-16 13:58:03 +00:00
}
2018-07-23 00:22:01 +00:00
if remaining_lib_features . contains_key ( & feature ) {
2018-07-23 16:34:04 +00:00
// Warn if the user enables a lib feature multiple times.
2023-02-05 01:49:50 +00:00
tcx . sess . emit_err ( errors ::DuplicateFeatureErr { span : * span , feature : * feature } ) ;
2018-07-23 00:22:01 +00:00
}
2020-04-15 22:00:22 +00:00
remaining_lib_features . insert ( feature , * span ) ;
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.
2018-07-23 23:56:00 +00:00
// FIXME: only remove `libc` when `stdbuild` is active.
2018-08-06 15:46:08 +00:00
// FIXME: remove special casing for `test`.
2020-07-08 01:04:10 +00:00
remaining_lib_features . remove ( & sym ::libc ) ;
2019-05-22 02:42:23 +00:00
remaining_lib_features . 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 > ,
remaining_lib_features : & mut FxIndexMap < & Symbol , Span > ,
remaining_implications : & mut FxHashMap < Symbol , Symbol > ,
defined_features : & [ ( Symbol , Option < Symbol > ) ] ,
all_implications : & FxHashMap < Symbol , Symbol > ,
) {
for ( feature , since ) in defined_features {
2022-07-13 14:10:19 +00:00
if let Some ( since ) = since & & let Some ( span ) = remaining_lib_features . get ( & feature ) {
// 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 ) {
2022-07-20 13:52:23 +00:00
unnecessary_partially_stable_feature_lint ( tcx , * span , * feature , * implies , * since ) ;
2022-07-13 14:10:19 +00:00
} else {
2022-07-20 13:52:23 +00:00
unnecessary_stable_feature_lint ( tcx , * span , * feature , * since ) ;
2018-08-21 00:39:48 +00:00
}
2022-08-02 16:27:18 +00:00
2018-08-21 00:39:48 +00:00
}
2022-08-02 16:27:18 +00:00
remaining_lib_features . remove ( feature ) ;
// `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.
remaining_implications . remove ( feature ) ;
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.
let mut remaining_implications =
tcx . stability_implications ( rustc_hir ::def_id ::LOCAL_CRATE ) . clone ( ) ;
// We always collect the lib features declared in the current crate, even if there are
// no unknown features, because the collection also does feature attribute validation.
let local_defined_features = tcx . lib_features ( ( ) ) . to_vec ( ) ;
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 ( ) ;
for & cnum in tcx . crates ( ( ) ) {
all_implications . extend ( tcx . stability_implications ( cnum ) ) ;
}
check_features (
tcx ,
& mut remaining_lib_features ,
& mut remaining_implications ,
local_defined_features . as_slice ( ) ,
& all_implications ,
) ;
for & cnum in tcx . crates ( ( ) ) {
if remaining_lib_features . is_empty ( ) & & remaining_implications . is_empty ( ) {
break ;
}
check_features (
tcx ,
& mut remaining_lib_features ,
& mut remaining_implications ,
tcx . defined_lib_features ( cnum ) . to_vec ( ) . as_slice ( ) ,
& all_implications ,
) ;
}
}
2018-07-23 00:20:33 +00:00
for ( feature , span ) in remaining_lib_features {
2023-02-05 01:49:50 +00:00
tcx . sess . emit_err ( errors ::UnknownFeature { span , feature : * feature } ) ;
2018-07-23 00:20:33 +00:00
}
2022-08-02 16:27:18 +00:00
for ( implied_by , feature ) in remaining_implications {
let local_defined_features = tcx . lib_features ( ( ) ) ;
2022-10-03 03:22:46 +00:00
let span = * local_defined_features
2022-08-02 16:27:18 +00:00
. stable
. get ( & feature )
. map ( | ( _ , span ) | span )
. or_else ( | | local_defined_features . unstable . get ( & feature ) )
. expect ( " feature that implied another does not exist " ) ;
2023-02-05 01:49:50 +00:00
tcx . sess . 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 ,
) {
2022-09-16 07:01:02 +00:00
tcx . struct_span_lint_hir (
lint ::builtin ::STABLE_FEATURES ,
hir ::CRATE_HIR_ID ,
span ,
format! (
2022-07-13 14:10:19 +00:00
" the feature `{feature}` has been partially stabilized since {since} and is succeeded \
by the feature ` { implies } ` "
2022-09-16 07:01:02 +00:00
) ,
| lint | {
2022-10-03 03:22:46 +00:00
lint . span_suggestion (
span ,
& format! (
2022-07-13 14:10:19 +00:00
" if you are using features which are still unstable, change to using `{implies}` "
) ,
2022-10-03 03:22:46 +00:00
implies ,
Applicability ::MaybeIncorrect ,
)
. span_suggestion (
tcx . sess . source_map ( ) . span_extend_to_line ( span ) ,
" if you are using features which are now stable, remove this line " ,
" " ,
Applicability ::MaybeIncorrect ,
)
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 {
since = rust_version_symbol ( ) ;
}
2022-09-16 07:01:02 +00:00
tcx . struct_span_lint_hir ( lint ::builtin ::STABLE_FEATURES , hir ::CRATE_HIR_ID , span , format! ( " the feature ` {feature} ` has been stable since {since} and no longer requires an attribute to enable " ) , | lint | {
lint
2020-02-01 23:47:58 +00:00
} ) ;
2018-07-23 16:34:04 +00:00
}