11use rustc_ast:: token:: Token ;
22use rustc_ast:: tokenstream:: TokenStream ;
33use rustc_ast:: { AttrStyle , NodeId , token} ;
4+ use rustc_data_structures:: fx:: FxHashMap ;
45use rustc_feature:: { AttributeTemplate , Features } ;
56use rustc_hir:: attrs:: CfgEntry ;
67use rustc_hir:: { AttrPath , Target } ;
@@ -9,11 +10,12 @@ use rustc_parse::parser::{Parser, Recovery};
910use rustc_session:: Session ;
1011use rustc_session:: lint:: BuiltinLintDiag ;
1112use rustc_session:: lint:: builtin:: UNREACHABLE_CFG_SELECT_PREDICATES ;
12- use rustc_span:: { ErrorGuaranteed , Span , sym} ;
13+ use rustc_span:: { ErrorGuaranteed , Span , Symbol , sym} ;
1314
1415use crate :: parser:: MetaItemOrLitParser ;
1516use crate :: { AttributeParser , ParsedDescription , ShouldEmit , parse_cfg_entry} ;
1617
18+ #[ derive( Clone ) ]
1719pub enum CfgSelectPredicate {
1820 Cfg ( CfgEntry ) ,
1921 Wildcard ( Token ) ,
@@ -126,19 +128,102 @@ pub fn parse_cfg_select(
126128 }
127129 }
128130
129- if let Some ( ( underscore , _ , _ ) ) = branches . wildcard
130- && features. map_or ( false , |f| f . enabled ( rustc_span :: sym:: cfg_select) )
131+ if let Some ( features ) = features
132+ && features. enabled ( sym:: cfg_select)
131133 {
132- for ( predicate , _ , _ ) in & branches. unreachable {
133- let span = predicate . span ( ) ;
134- p . psess . buffer_lint (
135- UNREACHABLE_CFG_SELECT_PREDICATES ,
136- span ,
137- lint_node_id ,
138- BuiltinLintDiag :: UnreachableCfg { span , wildcard_span : underscore . span } ,
134+ let it = branches
135+ . reachable
136+ . iter ( )
137+ . map ( | ( entry , _ , _ ) | CfgSelectPredicate :: Cfg ( entry . clone ( ) ) )
138+ . chain ( branches . wildcard . as_ref ( ) . map ( | ( t , _ , _ ) | CfgSelectPredicate :: Wildcard ( * t ) ) )
139+ . chain (
140+ branches . unreachable . iter ( ) . map ( | ( entry , _ , _ ) | CfgSelectPredicate :: clone ( entry ) ) ,
139141 ) ;
140- }
142+
143+ lint_unreachable ( p, it, lint_node_id) ;
141144 }
142145
143146 Ok ( branches)
144147}
148+
149+ fn lint_unreachable (
150+ p : & mut Parser < ' _ > ,
151+ predicates : impl Iterator < Item = CfgSelectPredicate > ,
152+ lint_node_id : NodeId ,
153+ ) {
154+ // Symbols that have a known value.
155+ let mut known = FxHashMap :: < Symbol , bool > :: default ( ) ;
156+ let mut wildcard_span = None ;
157+ let mut it = predicates;
158+
159+ let branch_is_unreachable = |predicate : CfgSelectPredicate , wildcard_span| {
160+ let span = predicate. span ( ) ;
161+ p. psess . buffer_lint (
162+ UNREACHABLE_CFG_SELECT_PREDICATES ,
163+ span,
164+ lint_node_id,
165+ BuiltinLintDiag :: UnreachableCfg { span, wildcard_span } ,
166+ ) ;
167+ } ;
168+
169+ for predicate in & mut it {
170+ let CfgSelectPredicate :: Cfg ( ref cfg_entry) = predicate else {
171+ wildcard_span = Some ( predicate. span ( ) ) ;
172+ break ;
173+ } ;
174+
175+ match cfg_entry {
176+ CfgEntry :: Bool ( true , _) => {
177+ wildcard_span = Some ( predicate. span ( ) ) ;
178+ break ;
179+ }
180+ CfgEntry :: Bool ( false , _) => continue ,
181+ CfgEntry :: NameValue { name, value, .. } => match value {
182+ None => {
183+ // `name` will be false in all subsequent branches.
184+ let current = known. insert ( * name, false ) ;
185+
186+ match current {
187+ None => continue ,
188+ Some ( false ) => {
189+ branch_is_unreachable ( predicate, None ) ;
190+ break ;
191+ }
192+ Some ( true ) => {
193+ // this branch will be taken, so all subsequent branches are unreachable.
194+ break ;
195+ }
196+ }
197+ }
198+ Some ( _) => { /* for now we don't bother solving these */ }
199+ } ,
200+ CfgEntry :: Not ( inner, _) => match & * * inner {
201+ CfgEntry :: NameValue { name, value : None , .. } => {
202+ // `name` will be true in all subsequent branches.
203+ let current = known. insert ( * name, true ) ;
204+
205+ match current {
206+ None => continue ,
207+ Some ( true ) => {
208+ branch_is_unreachable ( predicate, None ) ;
209+ break ;
210+ }
211+ Some ( false ) => {
212+ // this branch will be taken, so all subsequent branches are unreachable.
213+ break ;
214+ }
215+ }
216+ }
217+ _ => { /* for now we don't bother solving these */ }
218+ } ,
219+ CfgEntry :: All ( _, _) | CfgEntry :: Any ( _, _) => {
220+ /* for now we don't bother solving these */
221+ }
222+ CfgEntry :: Version ( ..) => { /* don't bother solving these */ }
223+ }
224+ }
225+
226+ for predicate in it {
227+ branch_is_unreachable ( predicate, wildcard_span)
228+ }
229+ }
0 commit comments