@@ -2,15 +2,16 @@ use crate::consts::ConstEvalCtxt;
2
2
use crate :: macros:: macro_backtrace;
3
3
use crate :: source:: { SpanRange , SpanRangeExt , walk_span_to_context} ;
4
4
use crate :: tokenize_with_text;
5
+ use rustc_ast:: ast;
5
6
use rustc_ast:: ast:: InlineAsmTemplatePiece ;
6
7
use rustc_data_structures:: fx:: FxHasher ;
7
8
use rustc_hir:: MatchSource :: TryDesugar ;
8
9
use rustc_hir:: def:: { DefKind , Res } ;
9
10
use rustc_hir:: {
10
11
AssocItemConstraint , BinOpKind , BindingMode , Block , BodyId , Closure , ConstArg , ConstArgKind , Expr , ExprField ,
11
12
ExprKind , FnRetTy , GenericArg , GenericArgs , HirId , HirIdMap , InlineAsmOperand , LetExpr , Lifetime , LifetimeKind ,
12
- Pat , PatExpr , PatExprKind , PatField , PatKind , Path , PathSegment , PrimTy , QPath , Stmt , StmtKind , StructTailExpr ,
13
- TraitBoundModifiers , Ty , TyKind , TyPat , TyPatKind ,
13
+ Node , Pat , PatExpr , PatExprKind , PatField , PatKind , Path , PathSegment , PrimTy , QPath , Stmt , StmtKind ,
14
+ StructTailExpr , TraitBoundModifiers , Ty , TyKind , TyPat , TyPatKind ,
14
15
} ;
15
16
use rustc_lexer:: { TokenKind , tokenize} ;
16
17
use rustc_lint:: LateContext ;
@@ -1004,8 +1005,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
1004
1005
self . hash_expr ( e) ;
1005
1006
}
1006
1007
} ,
1007
- ExprKind :: Match ( e , arms, s ) => {
1008
- self . hash_expr ( e ) ;
1008
+ ExprKind :: Match ( scrutinee , arms, _ ) => {
1009
+ self . hash_expr ( scrutinee ) ;
1009
1010
1010
1011
for arm in * arms {
1011
1012
self . hash_pat ( arm. pat ) ;
@@ -1014,8 +1015,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
1014
1015
}
1015
1016
self . hash_expr ( arm. body ) ;
1016
1017
}
1017
-
1018
- s. hash ( & mut self . s ) ;
1019
1018
} ,
1020
1019
ExprKind :: MethodCall ( path, receiver, args, _fn_span) => {
1021
1020
self . hash_name ( path. ident . name ) ;
@@ -1058,8 +1057,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
1058
1057
ExprKind :: Use ( expr, _) => {
1059
1058
self . hash_expr ( expr) ;
1060
1059
} ,
1061
- ExprKind :: Unary ( lop , le) => {
1062
- std:: mem:: discriminant ( lop ) . hash ( & mut self . s ) ;
1060
+ ExprKind :: Unary ( l_op , le) => {
1061
+ std:: mem:: discriminant ( l_op ) . hash ( & mut self . s ) ;
1063
1062
self . hash_expr ( le) ;
1064
1063
} ,
1065
1064
ExprKind :: UnsafeBinderCast ( kind, expr, ty) => {
@@ -1394,3 +1393,70 @@ fn eq_span_tokens(
1394
1393
}
1395
1394
f ( cx, left. into_range ( ) , right. into_range ( ) , pred)
1396
1395
}
1396
+
1397
+ /// Returns true if the expression contains ambiguous literals (unsuffixed float or int literals)
1398
+ /// that could be interpreted as either f32/f64 or i32/i64 depending on context.
1399
+ pub fn has_ambiguous_literal_in_expr ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
1400
+ match expr. kind {
1401
+ ExprKind :: Path ( ref qpath) => {
1402
+ if let Res :: Local ( hir_id) = cx. qpath_res ( qpath, expr. hir_id )
1403
+ && let Node :: LetStmt ( local) = cx. tcx . parent_hir_node ( hir_id)
1404
+ && local. ty . is_none ( )
1405
+ && let Some ( init) = local. init
1406
+ {
1407
+ return has_ambiguous_literal_in_expr ( cx, init) ;
1408
+ }
1409
+ false
1410
+ } ,
1411
+ ExprKind :: Lit ( lit) => matches ! (
1412
+ lit. node,
1413
+ ast:: LitKind :: Float ( _, ast:: LitFloatType :: Unsuffixed ) | ast:: LitKind :: Int ( _, ast:: LitIntType :: Unsuffixed )
1414
+ ) ,
1415
+
1416
+ ExprKind :: Array ( exprs) | ExprKind :: Tup ( exprs) => exprs. iter ( ) . any ( |e| has_ambiguous_literal_in_expr ( cx, e) ) ,
1417
+
1418
+ ExprKind :: Assign ( lhs, rhs, _) | ExprKind :: AssignOp ( _, lhs, rhs) | ExprKind :: Binary ( _, lhs, rhs) => {
1419
+ has_ambiguous_literal_in_expr ( cx, lhs) || has_ambiguous_literal_in_expr ( cx, rhs)
1420
+ } ,
1421
+
1422
+ ExprKind :: Unary ( _, e)
1423
+ | ExprKind :: Cast ( e, _)
1424
+ | ExprKind :: Type ( e, _)
1425
+ | ExprKind :: DropTemps ( e)
1426
+ | ExprKind :: AddrOf ( _, _, e)
1427
+ | ExprKind :: Field ( e, _)
1428
+ | ExprKind :: Index ( e, _, _)
1429
+ | ExprKind :: Yield ( e, _) => has_ambiguous_literal_in_expr ( cx, e) ,
1430
+
1431
+ ExprKind :: MethodCall ( _, receiver, args, _) | ExprKind :: Call ( receiver, args) => {
1432
+ has_ambiguous_literal_in_expr ( cx, receiver) || args. iter ( ) . any ( |e| has_ambiguous_literal_in_expr ( cx, e) )
1433
+ } ,
1434
+
1435
+ ExprKind :: Closure ( Closure { body, .. } ) => {
1436
+ let body = cx. tcx . hir_body ( * body) ;
1437
+ let closure_expr = crate :: peel_blocks ( body. value ) ;
1438
+ has_ambiguous_literal_in_expr ( cx, closure_expr)
1439
+ } ,
1440
+
1441
+ ExprKind :: Block ( blk, _) => blk. expr . as_ref ( ) . is_some_and ( |e| has_ambiguous_literal_in_expr ( cx, e) ) ,
1442
+
1443
+ ExprKind :: If ( cond, then_expr, else_expr) => {
1444
+ has_ambiguous_literal_in_expr ( cx, cond)
1445
+ || has_ambiguous_literal_in_expr ( cx, then_expr)
1446
+ || else_expr. as_ref ( ) . is_some_and ( |e| has_ambiguous_literal_in_expr ( cx, e) )
1447
+ } ,
1448
+
1449
+ ExprKind :: Match ( scrutinee, arms, _) => {
1450
+ has_ambiguous_literal_in_expr ( cx, scrutinee)
1451
+ || arms. iter ( ) . any ( |arm| has_ambiguous_literal_in_expr ( cx, arm. body ) )
1452
+ } ,
1453
+
1454
+ ExprKind :: Loop ( body, ..) => body. expr . is_some_and ( |e| has_ambiguous_literal_in_expr ( cx, e) ) ,
1455
+
1456
+ ExprKind :: Ret ( opt_expr) | ExprKind :: Break ( _, opt_expr) => {
1457
+ opt_expr. as_ref ( ) . is_some_and ( |e| has_ambiguous_literal_in_expr ( cx, e) )
1458
+ } ,
1459
+
1460
+ _ => false ,
1461
+ }
1462
+ }
0 commit comments