11use crate :: consts:: { constant_context, constant_simple} ;
2- use crate :: differing_macro_contexts;
2+ use crate :: { differing_macro_contexts, snippet_opt } ;
33use rustc_ast:: ast:: InlineAsmTemplatePiece ;
44use rustc_data_structures:: fx:: FxHashMap ;
55use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
@@ -9,6 +9,7 @@ use rustc_hir::{
99 GenericArg , GenericArgs , Guard , HirId , InlineAsmOperand , Lifetime , LifetimeName , ParamName , Pat , PatKind , Path ,
1010 PathSegment , QPath , Stmt , StmtKind , Ty , TyKind , TypeBinding ,
1111} ;
12+ use rustc_lexer:: { tokenize, TokenKind } ;
1213use rustc_lint:: LateContext ;
1314use rustc_middle:: ich:: StableHashingContextProvider ;
1415use rustc_middle:: ty:: TypeckResults ;
@@ -110,8 +111,54 @@ impl HirEqInterExpr<'_, '_, '_> {
110111
111112 /// Checks whether two blocks are the same.
112113 fn eq_block ( & mut self , left : & Block < ' _ > , right : & Block < ' _ > ) -> bool {
113- over ( & left. stmts , & right. stmts , |l, r| self . eq_stmt ( l, r) )
114- && both ( & left. expr , & right. expr , |l, r| self . eq_expr ( l, r) )
114+ match ( left. stmts , left. expr , right. stmts , right. expr ) {
115+ ( [ ] , None , [ ] , None ) => {
116+ // For empty blocks, check to see if the tokens are equal. This will catch the case where a macro
117+ // expanded to nothing, or the cfg attribute was used.
118+ let ( left, right) = match (
119+ snippet_opt ( self . inner . cx , left. span ) ,
120+ snippet_opt ( self . inner . cx , right. span ) ,
121+ ) {
122+ ( Some ( left) , Some ( right) ) => ( left, right) ,
123+ _ => return true ,
124+ } ;
125+ let mut left_pos = 0 ;
126+ let left = tokenize ( & left)
127+ . map ( |t| {
128+ let end = left_pos + t. len ;
129+ let s = & left[ left_pos..end] ;
130+ left_pos = end;
131+ ( t, s)
132+ } )
133+ . filter ( |( t, _) | {
134+ !matches ! (
135+ t. kind,
136+ TokenKind :: LineComment { .. } | TokenKind :: BlockComment { .. } | TokenKind :: Whitespace
137+ )
138+ } )
139+ . map ( |( _, s) | s) ;
140+ let mut right_pos = 0 ;
141+ let right = tokenize ( & right)
142+ . map ( |t| {
143+ let end = right_pos + t. len ;
144+ let s = & right[ right_pos..end] ;
145+ right_pos = end;
146+ ( t, s)
147+ } )
148+ . filter ( |( t, _) | {
149+ !matches ! (
150+ t. kind,
151+ TokenKind :: LineComment { .. } | TokenKind :: BlockComment { .. } | TokenKind :: Whitespace
152+ )
153+ } )
154+ . map ( |( _, s) | s) ;
155+ left. eq ( right)
156+ } ,
157+ _ => {
158+ over ( & left. stmts , & right. stmts , |l, r| self . eq_stmt ( l, r) )
159+ && both ( & left. expr , & right. expr , |l, r| self . eq_expr ( l, r) )
160+ } ,
161+ }
115162 }
116163
117164 #[ allow( clippy:: similar_names) ]
@@ -131,7 +178,10 @@ impl HirEqInterExpr<'_, '_, '_> {
131178 }
132179 }
133180
134- let is_eq = match ( & reduce_exprkind ( & left. kind ) , & reduce_exprkind ( & right. kind ) ) {
181+ let is_eq = match (
182+ & reduce_exprkind ( self . inner . cx , & left. kind ) ,
183+ & reduce_exprkind ( self . inner . cx , & right. kind ) ,
184+ ) {
135185 ( & ExprKind :: AddrOf ( lb, l_mut, ref le) , & ExprKind :: AddrOf ( rb, r_mut, ref re) ) => {
136186 lb == rb && l_mut == r_mut && self . eq_expr ( le, re)
137187 } ,
@@ -360,11 +410,30 @@ impl HirEqInterExpr<'_, '_, '_> {
360410}
361411
362412/// Some simple reductions like `{ return }` => `return`
363- fn reduce_exprkind < ' hir > ( kind : & ' hir ExprKind < ' hir > ) -> & ExprKind < ' hir > {
413+ fn reduce_exprkind < ' hir > ( cx : & LateContext < ' _ > , kind : & ' hir ExprKind < ' hir > ) -> & ' hir ExprKind < ' hir > {
364414 if let ExprKind :: Block ( block, _) = kind {
365415 match ( block. stmts , block. expr ) {
416+ // From an `if let` expression without an `else` block. The arm for the implicit wild pattern is an empty
417+ // block with an empty span.
418+ ( [ ] , None ) if block. span . is_empty ( ) => & ExprKind :: Tup ( & [ ] ) ,
366419 // `{}` => `()`
367- ( [ ] , None ) => & ExprKind :: Tup ( & [ ] ) ,
420+ ( [ ] , None ) => match snippet_opt ( cx, block. span ) {
421+ // Don't reduce if there are any tokens contained in the braces
422+ Some ( snip)
423+ if tokenize ( & snip)
424+ . map ( |t| t. kind )
425+ . filter ( |t| {
426+ !matches ! (
427+ t,
428+ TokenKind :: LineComment { .. } | TokenKind :: BlockComment { .. } | TokenKind :: Whitespace
429+ )
430+ } )
431+ . ne ( [ TokenKind :: OpenBrace , TokenKind :: CloseBrace ] . iter ( ) . cloned ( ) ) =>
432+ {
433+ kind
434+ } ,
435+ _ => & ExprKind :: Tup ( & [ ] ) ,
436+ } ,
368437 ( [ ] , Some ( expr) ) => match expr. kind {
369438 // `{ return .. }` => `return ..`
370439 ExprKind :: Ret ( ..) => & expr. kind ,
0 commit comments