11//! List of the unstable feature gates.
22
33use std:: path:: PathBuf ;
4+ use std:: sync:: { LazyLock , Mutex } ;
45use std:: time:: { SystemTime , UNIX_EPOCH } ;
56
67use rustc_data_structures:: fx:: FxHashSet ;
@@ -27,6 +28,9 @@ macro_rules! status_to_enum {
2728 } ;
2829}
2930
31+ static USED_FEATURES : LazyLock < Mutex < FxHashSet < Symbol > > > =
32+ LazyLock :: new ( || Mutex :: new ( FxHashSet :: default ( ) ) ) ;
33+
3034/// A set of features to be used by later passes.
3135///
3236/// There are two ways to check if a language feature `foo` is enabled:
@@ -35,6 +39,79 @@ macro_rules! status_to_enum {
3539///
3640/// The former is preferred. `enabled` should only be used when the feature symbol is not a
3741/// constant, e.g. a parameter, or when the feature is a library feature.
42+ ///
43+ /// NOTE: Do NOT use any other method (e.g. `enabled_features`) to check if a feature is enabled.
44+ /// Only `enabled(&self, feature: Symbol)` and the generated `foo(&self)` methods will record
45+ /// feature usage. Using any other method will silently skip tracking and lead to incorrect
46+ /// "unused features" diagnostics.
47+ #[ derive( Clone , Debug ) ]
48+ pub struct TrackedFeatures {
49+ features : Features ,
50+ }
51+
52+ impl TrackedFeatures {
53+ pub fn new ( features : Features ) -> Self {
54+ Self { features }
55+ }
56+
57+ pub fn unused_features ( & self ) -> Vec < ( Symbol , Span ) > {
58+ let used_features = USED_FEATURES . lock ( ) . unwrap ( ) ;
59+ self . enabled_features_iter_stable_order ( )
60+ . filter ( |( f, _) | !used_features. contains ( f) )
61+ . collect ( )
62+ }
63+
64+ /// Is the given feature enabled (via `#[feature(...)]`)?
65+ pub fn enabled ( & self , feature : Symbol ) -> bool {
66+ USED_FEATURES . lock ( ) . unwrap ( ) . insert ( feature) ;
67+ self . features . enabled ( feature)
68+ }
69+
70+ /// Returns a list of [`EnabledLangFeature`] with info about:
71+ ///
72+ /// - Feature gate name.
73+ /// - The span of the `#[feature]` attribute.
74+ /// - For stable language features, version info for when it was stabilized.
75+ pub fn enabled_lang_features ( & self ) -> & Vec < EnabledLangFeature > {
76+ self . features . enabled_lang_features ( )
77+ }
78+
79+ pub fn enabled_lib_features ( & self ) -> & Vec < EnabledLibFeature > {
80+ self . features . enabled_lib_features ( )
81+ }
82+
83+ pub fn enabled_features ( & self ) -> & FxHashSet < Symbol > {
84+ & self . features . enabled_features ( )
85+ }
86+
87+ /// Returns a iterator of enabled features in stable order.
88+ pub fn enabled_features_iter_stable_order (
89+ & self ,
90+ ) -> impl Iterator < Item = ( Symbol , Span ) > + Clone {
91+ self . features . enabled_features_iter_stable_order ( )
92+ }
93+
94+ pub fn dump_feature_usage_metrics (
95+ & self ,
96+ metrics_path : PathBuf ,
97+ ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
98+ self . features . dump_feature_usage_metrics ( metrics_path)
99+ }
100+
101+ /// Some features are known to be incomplete and using them is likely to have
102+ /// unanticipated results, such as compiler crashes. We warn the user about these
103+ /// to alert them.
104+ pub fn incomplete ( & self , feature : Symbol ) -> bool {
105+ self . features . incomplete ( feature)
106+ }
107+
108+ /// Some features are internal to the compiler and standard library and should not
109+ /// be used in normal projects. We warn the user about these to alert them.
110+ pub fn internal ( & self , feature : Symbol ) -> bool {
111+ self . features . internal ( feature)
112+ }
113+ }
114+
38115#[ derive( Clone , Default , Debug ) ]
39116pub struct Features {
40117 /// `#![feature]` attrs for language features, for error reporting.
@@ -89,22 +166,18 @@ impl Features {
89166 & self . enabled_lib_features
90167 }
91168
92- pub fn enabled_features ( & self ) -> & FxHashSet < Symbol > {
169+ fn enabled_features ( & self ) -> & FxHashSet < Symbol > {
93170 & self . enabled_features
94171 }
95172
96- /// Returns a iterator of enabled features in stable order.
97- pub fn enabled_features_iter_stable_order (
98- & self ,
99- ) -> impl Iterator < Item = ( Symbol , Span ) > + Clone {
173+ fn enabled_features_iter_stable_order ( & self ) -> impl Iterator < Item = ( Symbol , Span ) > + Clone {
100174 self . enabled_lang_features
101175 . iter ( )
102176 . map ( |feat| ( feat. gate_name , feat. attr_sp ) )
103177 . chain ( self . enabled_lib_features . iter ( ) . map ( |feat| ( feat. gate_name , feat. attr_sp ) ) )
104178 }
105179
106- /// Is the given feature enabled (via `#[feature(...)]`)?
107- pub fn enabled ( & self , feature : Symbol ) -> bool {
180+ fn enabled ( & self , feature : Symbol ) -> bool {
108181 self . enabled_features . contains ( & feature)
109182 }
110183}
@@ -123,17 +196,19 @@ macro_rules! declare_features {
123196 } ) ,+
124197 ] ;
125198
126- impl Features {
199+ impl TrackedFeatures {
127200 $(
128201 pub fn $feature( & self ) -> bool {
129- self . enabled_features . contains ( & sym:: $feature)
202+ self . enabled ( sym:: $feature)
130203 }
131204 ) *
205+ }
132206
207+ impl Features {
133208 /// Some features are known to be incomplete and using them is likely to have
134209 /// unanticipated results, such as compiler crashes. We warn the user about these
135210 /// to alert them.
136- pub fn incomplete( & self , feature: Symbol ) -> bool {
211+ fn incomplete( & self , feature: Symbol ) -> bool {
137212 match feature {
138213 $(
139214 sym:: $feature => status_to_enum!( $status) == FeatureStatus :: Incomplete ,
@@ -711,7 +786,7 @@ declare_features! (
711786) ;
712787
713788impl Features {
714- pub fn dump_feature_usage_metrics (
789+ fn dump_feature_usage_metrics (
715790 & self ,
716791 metrics_path : PathBuf ,
717792 ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
0 commit comments