@@ -17,7 +17,7 @@ use rustc_lint::{LateContext, LateLintPass};
17
17
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AutoBorrow , AutoBorrowMutability } ;
18
18
use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitable , TypeckResults } ;
19
19
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
20
- use rustc_span:: { symbol:: sym, Span , Symbol } ;
20
+ use rustc_span:: { symbol:: sym, Span , Symbol , DUMMY_SP } ;
21
21
use rustc_trait_selection:: infer:: InferCtxtExt ;
22
22
23
23
declare_clippy_lint ! {
@@ -609,26 +609,29 @@ enum Position {
609
609
Postfix ,
610
610
Deref ,
611
611
/// Any other location which will trigger auto-deref to a specific time.
612
- DerefStable ( i8 ) ,
612
+ /// Contains the precedence of the parent expression and whether the target type is sized.
613
+ DerefStable ( i8 , bool ) ,
613
614
/// Any other location which will trigger auto-reborrowing.
615
+ /// Contains the precedence of the parent expression.
614
616
ReborrowStable ( i8 ) ,
617
+ /// Contains the precedence of the parent expression.
615
618
Other ( i8 ) ,
616
619
}
617
620
impl Position {
618
621
fn is_deref_stable ( self ) -> bool {
619
- matches ! ( self , Self :: DerefStable ( _ ) )
622
+ matches ! ( self , Self :: DerefStable ( .. ) )
620
623
}
621
624
622
625
fn is_reborrow_stable ( self ) -> bool {
623
- matches ! ( self , Self :: DerefStable ( _ ) | Self :: ReborrowStable ( _) )
626
+ matches ! ( self , Self :: DerefStable ( .. ) | Self :: ReborrowStable ( _) )
624
627
}
625
628
626
629
fn can_auto_borrow ( self ) -> bool {
627
630
matches ! ( self , Self :: MethodReceiver | Self :: FieldAccess ( _) | Self :: Callee )
628
631
}
629
632
630
633
fn lint_explicit_deref ( self ) -> bool {
631
- matches ! ( self , Self :: Other ( _) | Self :: DerefStable ( _ ) | Self :: ReborrowStable ( _) )
634
+ matches ! ( self , Self :: Other ( _) | Self :: DerefStable ( .. ) | Self :: ReborrowStable ( _) )
632
635
}
633
636
634
637
fn precedence ( self ) -> i8 {
@@ -639,7 +642,7 @@ impl Position {
639
642
| Self :: FieldAccess ( _)
640
643
| Self :: Postfix => PREC_POSTFIX ,
641
644
Self :: Deref => PREC_PREFIX ,
642
- Self :: DerefStable ( p) | Self :: ReborrowStable ( p) | Self :: Other ( p) => p,
645
+ Self :: DerefStable ( p, _ ) | Self :: ReborrowStable ( p) | Self :: Other ( p) => p,
643
646
}
644
647
}
645
648
}
@@ -659,7 +662,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
659
662
}
660
663
match parent {
661
664
Node :: Local ( Local { ty : Some ( ty) , span, .. } ) if span. ctxt ( ) == ctxt => {
662
- Some ( binding_ty_auto_deref_stability ( ty, precedence) )
665
+ Some ( binding_ty_auto_deref_stability ( cx , ty, precedence) )
663
666
} ,
664
667
Node :: Item ( & Item {
665
668
kind : ItemKind :: Static ( ..) | ItemKind :: Const ( ..) ,
@@ -680,8 +683,11 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
680
683
..
681
684
} ) if span. ctxt ( ) == ctxt => {
682
685
let ty = cx. tcx . type_of ( def_id) ;
683
- Some ( if ty. is_ref ( ) {
684
- Position :: DerefStable ( precedence)
686
+ Some ( if let ty:: Ref ( _, ty, _) = * ty. kind ( ) {
687
+ Position :: DerefStable (
688
+ precedence,
689
+ ty. is_sized ( cx. tcx . at ( DUMMY_SP ) , cx. param_env . without_caller_bounds ( ) ) ,
690
+ )
685
691
} else {
686
692
Position :: Other ( precedence)
687
693
} )
@@ -705,13 +711,20 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
705
711
span,
706
712
..
707
713
} ) if span. ctxt ( ) == ctxt => {
708
- let output = cx. tcx . fn_sig ( def_id. to_def_id ( ) ) . skip_binder ( ) . output ( ) ;
709
- Some ( if !output. is_ref ( ) {
710
- Position :: Other ( precedence)
711
- } else if output. has_placeholders ( ) || output. has_opaque_types ( ) {
712
- Position :: ReborrowStable ( precedence)
714
+ let output = cx
715
+ . tcx
716
+ . erase_late_bound_regions ( cx. tcx . fn_sig ( def_id. to_def_id ( ) ) . output ( ) ) ;
717
+ Some ( if let ty:: Ref ( _, ty, _) = * output. kind ( ) {
718
+ if ty. has_placeholders ( ) || ty. has_opaque_types ( ) {
719
+ Position :: ReborrowStable ( precedence)
720
+ } else {
721
+ Position :: DerefStable (
722
+ precedence,
723
+ ty. is_sized ( cx. tcx . at ( DUMMY_SP ) , cx. param_env . without_caller_bounds ( ) ) ,
724
+ )
725
+ }
713
726
} else {
714
- Position :: DerefStable ( precedence)
727
+ Position :: Other ( precedence)
715
728
} )
716
729
} ,
717
730
@@ -725,21 +738,24 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
725
738
} ) = cx. tcx . hir ( ) . get ( owner_id)
726
739
{
727
740
match fn_decl. output {
728
- FnRetTy :: Return ( ty) => binding_ty_auto_deref_stability ( ty, precedence) ,
741
+ FnRetTy :: Return ( ty) => binding_ty_auto_deref_stability ( cx , ty, precedence) ,
729
742
FnRetTy :: DefaultReturn ( _) => Position :: Other ( precedence) ,
730
743
}
731
744
} else {
732
745
let output = cx
733
746
. tcx
734
- . fn_sig ( cx. tcx . hir ( ) . local_def_id ( owner_id) )
735
- . skip_binder ( )
736
- . output ( ) ;
737
- if !output. is_ref ( ) {
738
- Position :: Other ( precedence)
739
- } else if output. has_placeholders ( ) || output. has_opaque_types ( ) {
740
- Position :: ReborrowStable ( precedence)
747
+ . erase_late_bound_regions ( cx. tcx . fn_sig ( cx. tcx . hir ( ) . local_def_id ( owner_id) ) . output ( ) ) ;
748
+ if let ty:: Ref ( _, ty, _) = * output. kind ( ) {
749
+ if ty. has_placeholders ( ) || ty. has_opaque_types ( ) {
750
+ Position :: ReborrowStable ( precedence)
751
+ } else {
752
+ Position :: DerefStable (
753
+ precedence,
754
+ ty. is_sized ( cx. tcx . at ( DUMMY_SP ) , cx. param_env . without_caller_bounds ( ) ) ,
755
+ )
756
+ }
741
757
} else {
742
- Position :: DerefStable ( precedence)
758
+ Position :: Other ( precedence)
743
759
}
744
760
} ,
745
761
)
@@ -755,8 +771,8 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
755
771
. map ( |( hir_ty, ty) | match hir_ty {
756
772
// Type inference for closures can depend on how they're called. Only go by the explicit
757
773
// types here.
758
- Some ( ty) => binding_ty_auto_deref_stability ( ty, precedence) ,
759
- None => param_auto_deref_stability ( ty . skip_binder ( ) , precedence) ,
774
+ Some ( ty) => binding_ty_auto_deref_stability ( cx , ty, precedence) ,
775
+ None => param_auto_deref_stability ( cx , cx . tcx . erase_late_bound_regions ( ty ) , precedence) ,
760
776
} ) ,
761
777
ExprKind :: MethodCall ( _, args, _) => {
762
778
let id = cx. typeck_results ( ) . type_dependent_def_id ( parent. hir_id ) . unwrap ( ) ;
@@ -797,7 +813,11 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
797
813
Position :: MethodReceiver
798
814
}
799
815
} else {
800
- param_auto_deref_stability ( cx. tcx . fn_sig ( id) . skip_binder ( ) . inputs ( ) [ i] , precedence)
816
+ param_auto_deref_stability (
817
+ cx,
818
+ cx. tcx . erase_late_bound_regions ( cx. tcx . fn_sig ( id) . input ( i) ) ,
819
+ precedence,
820
+ )
801
821
}
802
822
} )
803
823
} ,
@@ -808,7 +828,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
808
828
. find ( |f| f. expr . hir_id == child_id)
809
829
. zip ( variant)
810
830
. and_then ( |( field, variant) | variant. fields . iter ( ) . find ( |f| f. name == field. ident . name ) )
811
- . map ( |field| param_auto_deref_stability ( cx. tcx . type_of ( field. did ) , precedence) )
831
+ . map ( |field| param_auto_deref_stability ( cx, cx . tcx . type_of ( field. did ) , precedence) )
812
832
} ,
813
833
ExprKind :: Field ( child, name) if child. hir_id == e. hir_id => Some ( Position :: FieldAccess ( name. name ) ) ,
814
834
ExprKind :: Unary ( UnOp :: Deref , child) if child. hir_id == e. hir_id => Some ( Position :: Deref ) ,
@@ -840,7 +860,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
840
860
//
841
861
// Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
842
862
// switching to auto-dereferencing.
843
- fn binding_ty_auto_deref_stability ( ty : & hir:: Ty < ' _ > , precedence : i8 ) -> Position {
863
+ fn binding_ty_auto_deref_stability ( cx : & LateContext < ' _ > , ty : & hir:: Ty < ' _ > , precedence : i8 ) -> Position {
844
864
let TyKind :: Rptr ( _, ty) = & ty. kind else {
845
865
return Position :: Other ( precedence) ;
846
866
} ;
@@ -870,7 +890,13 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position
870
890
{
871
891
Position :: ReborrowStable ( precedence)
872
892
} else {
873
- Position :: DerefStable ( precedence)
893
+ Position :: DerefStable (
894
+ precedence,
895
+ cx
896
+ . typeck_results ( )
897
+ . node_type ( ty. ty . hir_id )
898
+ . is_sized ( cx. tcx . at ( DUMMY_SP ) , cx. param_env . without_caller_bounds ( ) ) ,
899
+ )
874
900
}
875
901
} ,
876
902
TyKind :: Slice ( _)
@@ -880,7 +906,13 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position
880
906
| TyKind :: Tup ( _)
881
907
| TyKind :: Ptr ( _)
882
908
| TyKind :: TraitObject ( ..)
883
- | TyKind :: Path ( _) => Position :: DerefStable ( precedence) ,
909
+ | TyKind :: Path ( _) => Position :: DerefStable (
910
+ precedence,
911
+ cx
912
+ . typeck_results ( )
913
+ . node_type ( ty. ty . hir_id )
914
+ . is_sized ( cx. tcx . at ( DUMMY_SP ) , cx. param_env . without_caller_bounds ( ) ) ,
915
+ ) ,
884
916
TyKind :: OpaqueDef ( ..)
885
917
| TyKind :: Infer
886
918
| TyKind :: Typeof ( ..)
@@ -921,7 +953,7 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
921
953
}
922
954
923
955
// Checks whether a type is stable when switching to auto dereferencing,
924
- fn param_auto_deref_stability ( ty : Ty < ' _ > , precedence : i8 ) -> Position {
956
+ fn param_auto_deref_stability < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > , precedence : i8 ) -> Position {
925
957
let ty:: Ref ( _, mut ty, _) = * ty. kind ( ) else {
926
958
return Position :: Other ( precedence) ;
927
959
} ;
@@ -960,7 +992,10 @@ fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position {
960
992
| ty:: GeneratorWitness ( ..)
961
993
| ty:: Never
962
994
| ty:: Tuple ( _)
963
- | ty:: Projection ( _) => Position :: DerefStable ( precedence) ,
995
+ | ty:: Projection ( _) => Position :: DerefStable (
996
+ precedence,
997
+ ty. is_sized ( cx. tcx . at ( DUMMY_SP ) , cx. param_env . without_caller_bounds ( ) ) ,
998
+ ) ,
964
999
} ;
965
1000
}
966
1001
}
@@ -1040,6 +1075,19 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
1040
1075
} ) ;
1041
1076
} ,
1042
1077
State :: ExplicitDeref { deref_span_id } => {
1078
+ if matches ! (
1079
+ expr. kind,
1080
+ ExprKind :: Block ( ..)
1081
+ | ExprKind :: ConstBlock ( _)
1082
+ | ExprKind :: If ( ..)
1083
+ | ExprKind :: Loop ( ..)
1084
+ | ExprKind :: Match ( ..)
1085
+ ) && matches ! ( data. position, Position :: DerefStable ( _, true ) )
1086
+ {
1087
+ // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
1088
+ return ;
1089
+ }
1090
+
1043
1091
let ( span, hir_id, precedence) = if let Some ( ( span, hir_id) ) = deref_span_id
1044
1092
&& !cx. typeck_results ( ) . expr_ty ( expr) . is_ref ( )
1045
1093
{
@@ -1067,6 +1115,19 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
1067
1115
) ;
1068
1116
} ,
1069
1117
State :: ExplicitDerefField { .. } => {
1118
+ if matches ! (
1119
+ expr. kind,
1120
+ ExprKind :: Block ( ..)
1121
+ | ExprKind :: ConstBlock ( _)
1122
+ | ExprKind :: If ( ..)
1123
+ | ExprKind :: Loop ( ..)
1124
+ | ExprKind :: Match ( ..)
1125
+ ) && matches ! ( data. position, Position :: DerefStable ( _, true ) )
1126
+ {
1127
+ // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
1128
+ return ;
1129
+ }
1130
+
1070
1131
span_lint_hir_and_then (
1071
1132
cx,
1072
1133
EXPLICIT_AUTO_DEREF ,
0 commit comments