@@ -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 , TypeFoldable , 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
)
@@ -753,8 +769,8 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
753
769
. map ( |( hir_ty, ty) | match hir_ty {
754
770
// Type inference for closures can depend on how they're called. Only go by the explicit
755
771
// types here.
756
- Some ( ty) => binding_ty_auto_deref_stability ( ty, precedence) ,
757
- None => param_auto_deref_stability ( ty . skip_binder ( ) , precedence) ,
772
+ Some ( ty) => binding_ty_auto_deref_stability ( cx , ty, precedence) ,
773
+ None => param_auto_deref_stability ( cx , cx . tcx . erase_late_bound_regions ( ty ) , precedence) ,
758
774
} ) ,
759
775
ExprKind :: MethodCall ( _, args, _) => {
760
776
let id = cx. typeck_results ( ) . type_dependent_def_id ( parent. hir_id ) . unwrap ( ) ;
@@ -790,7 +806,11 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
790
806
Position :: MethodReceiver
791
807
}
792
808
} else {
793
- param_auto_deref_stability ( cx. tcx . fn_sig ( id) . skip_binder ( ) . inputs ( ) [ i] , precedence)
809
+ param_auto_deref_stability (
810
+ cx,
811
+ cx. tcx . erase_late_bound_regions ( cx. tcx . fn_sig ( id) . input ( i) ) ,
812
+ precedence,
813
+ )
794
814
}
795
815
} )
796
816
} ,
@@ -801,7 +821,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
801
821
. find ( |f| f. expr . hir_id == child_id)
802
822
. zip ( variant)
803
823
. and_then ( |( field, variant) | variant. fields . iter ( ) . find ( |f| f. name == field. ident . name ) )
804
- . map ( |field| param_auto_deref_stability ( cx. tcx . type_of ( field. did ) , precedence) )
824
+ . map ( |field| param_auto_deref_stability ( cx, cx . tcx . type_of ( field. did ) , precedence) )
805
825
} ,
806
826
ExprKind :: Field ( child, name) if child. hir_id == e. hir_id => Some ( Position :: FieldAccess ( name. name ) ) ,
807
827
ExprKind :: Unary ( UnOp :: Deref , child) if child. hir_id == e. hir_id => Some ( Position :: Deref ) ,
@@ -833,7 +853,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
833
853
//
834
854
// Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
835
855
// switching to auto-dereferencing.
836
- fn binding_ty_auto_deref_stability ( ty : & hir:: Ty < ' _ > , precedence : i8 ) -> Position {
856
+ fn binding_ty_auto_deref_stability ( cx : & LateContext < ' _ > , ty : & hir:: Ty < ' _ > , precedence : i8 ) -> Position {
837
857
let TyKind :: Rptr ( _, ty) = & ty. kind else {
838
858
return Position :: Other ( precedence) ;
839
859
} ;
@@ -863,7 +883,13 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position
863
883
{
864
884
Position :: ReborrowStable ( precedence)
865
885
} else {
866
- Position :: DerefStable ( precedence)
886
+ Position :: DerefStable (
887
+ precedence,
888
+ cx
889
+ . typeck_results ( )
890
+ . node_type ( ty. ty . hir_id )
891
+ . is_sized ( cx. tcx . at ( DUMMY_SP ) , cx. param_env . without_caller_bounds ( ) ) ,
892
+ )
867
893
}
868
894
} ,
869
895
TyKind :: Slice ( _)
@@ -873,7 +899,13 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position
873
899
| TyKind :: Tup ( _)
874
900
| TyKind :: Ptr ( _)
875
901
| TyKind :: TraitObject ( ..)
876
- | TyKind :: Path ( _) => Position :: DerefStable ( precedence) ,
902
+ | TyKind :: Path ( _) => Position :: DerefStable (
903
+ precedence,
904
+ cx
905
+ . typeck_results ( )
906
+ . node_type ( ty. ty . hir_id )
907
+ . is_sized ( cx. tcx . at ( DUMMY_SP ) , cx. param_env . without_caller_bounds ( ) ) ,
908
+ ) ,
877
909
TyKind :: OpaqueDef ( ..)
878
910
| TyKind :: Infer
879
911
| TyKind :: Typeof ( ..)
@@ -914,7 +946,7 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
914
946
}
915
947
916
948
// Checks whether a type is stable when switching to auto dereferencing,
917
- fn param_auto_deref_stability ( ty : Ty < ' _ > , precedence : i8 ) -> Position {
949
+ fn param_auto_deref_stability < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > , precedence : i8 ) -> Position {
918
950
let ty:: Ref ( _, mut ty, _) = * ty. kind ( ) else {
919
951
return Position :: Other ( precedence) ;
920
952
} ;
@@ -953,7 +985,10 @@ fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position {
953
985
| ty:: GeneratorWitness ( ..)
954
986
| ty:: Never
955
987
| ty:: Tuple ( _)
956
- | ty:: Projection ( _) => Position :: DerefStable ( precedence) ,
988
+ | ty:: Projection ( _) => Position :: DerefStable (
989
+ precedence,
990
+ ty. is_sized ( cx. tcx . at ( DUMMY_SP ) , cx. param_env . without_caller_bounds ( ) ) ,
991
+ ) ,
957
992
} ;
958
993
}
959
994
}
@@ -1033,6 +1068,19 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
1033
1068
} ) ;
1034
1069
} ,
1035
1070
State :: ExplicitDeref { deref_span_id } => {
1071
+ if matches ! (
1072
+ expr. kind,
1073
+ ExprKind :: Block ( ..)
1074
+ | ExprKind :: ConstBlock ( _)
1075
+ | ExprKind :: If ( ..)
1076
+ | ExprKind :: Loop ( ..)
1077
+ | ExprKind :: Match ( ..)
1078
+ ) && matches ! ( data. position, Position :: DerefStable ( _, true ) )
1079
+ {
1080
+ // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
1081
+ return ;
1082
+ }
1083
+
1036
1084
let ( span, hir_id, precedence) = if let Some ( ( span, hir_id) ) = deref_span_id
1037
1085
&& !cx. typeck_results ( ) . expr_ty ( expr) . is_ref ( )
1038
1086
{
@@ -1060,6 +1108,19 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
1060
1108
) ;
1061
1109
} ,
1062
1110
State :: ExplicitDerefField { .. } => {
1111
+ if matches ! (
1112
+ expr. kind,
1113
+ ExprKind :: Block ( ..)
1114
+ | ExprKind :: ConstBlock ( _)
1115
+ | ExprKind :: If ( ..)
1116
+ | ExprKind :: Loop ( ..)
1117
+ | ExprKind :: Match ( ..)
1118
+ ) && matches ! ( data. position, Position :: DerefStable ( _, true ) )
1119
+ {
1120
+ // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
1121
+ return ;
1122
+ }
1123
+
1063
1124
span_lint_hir_and_then (
1064
1125
cx,
1065
1126
EXPLICIT_AUTO_DEREF ,
0 commit comments