@@ -2,15 +2,16 @@ use crate::consts::ConstEvalCtxt;
22use crate :: macros:: macro_backtrace;
33use crate :: source:: { SpanRange , SpanRangeExt , walk_span_to_context} ;
44use crate :: tokenize_with_text;
5+ use rustc_ast:: ast;
56use rustc_ast:: ast:: InlineAsmTemplatePiece ;
67use rustc_data_structures:: fx:: FxHasher ;
78use rustc_hir:: MatchSource :: TryDesugar ;
89use rustc_hir:: def:: { DefKind , Res } ;
910use rustc_hir:: {
1011 AssocItemConstraint , BinOpKind , BindingMode , Block , BodyId , Closure , ConstArg , ConstArgKind , Expr , ExprField ,
1112 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 ,
1415} ;
1516use rustc_lexer:: { TokenKind , tokenize} ;
1617use rustc_lint:: LateContext ;
@@ -1004,8 +1005,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
10041005 self . hash_expr ( e) ;
10051006 }
10061007 } ,
1007- ExprKind :: Match ( e , arms, s ) => {
1008- self . hash_expr ( e ) ;
1008+ ExprKind :: Match ( scrutinee , arms, _ ) => {
1009+ self . hash_expr ( scrutinee ) ;
10091010
10101011 for arm in * arms {
10111012 self . hash_pat ( arm. pat ) ;
@@ -1014,8 +1015,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
10141015 }
10151016 self . hash_expr ( arm. body ) ;
10161017 }
1017-
1018- s. hash ( & mut self . s ) ;
10191018 } ,
10201019 ExprKind :: MethodCall ( path, receiver, args, _fn_span) => {
10211020 self . hash_name ( path. ident . name ) ;
@@ -1058,8 +1057,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
10581057 ExprKind :: Use ( expr, _) => {
10591058 self . hash_expr ( expr) ;
10601059 } ,
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 ) ;
10631062 self . hash_expr ( le) ;
10641063 } ,
10651064 ExprKind :: UnsafeBinderCast ( kind, expr, ty) => {
@@ -1394,3 +1393,70 @@ fn eq_span_tokens(
13941393 }
13951394 f ( cx, left. into_range ( ) , right. into_range ( ) , pred)
13961395}
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