@@ -5,7 +5,9 @@ use crate::{
5
5
InvalidAtomicOrderingDiag , InvalidNanComparisons , InvalidNanComparisonsSuggestion ,
6
6
OnlyCastu8ToChar , OverflowingBinHex , OverflowingBinHexSign , OverflowingBinHexSignBitSub ,
7
7
OverflowingBinHexSub , OverflowingInt , OverflowingIntHelp , OverflowingLiteral ,
8
- OverflowingUInt , RangeEndpointOutOfRange , UnusedComparisons , UseInclusiveRange ,
8
+ OverflowingUInt , RangeEndpointOutOfRange , UnclearFatPointerComparisons ,
9
+ UnclearFatPointerComparisonsAddrMetadataSuggestion ,
10
+ UnclearFatPointerComparisonsAddrSuggestion , UnusedComparisons , UseInclusiveRange ,
9
11
VariantSizeDifferencesDiag ,
10
12
} ,
11
13
} ;
@@ -17,10 +19,10 @@ use rustc_errors::DiagnosticMessage;
17
19
use rustc_hir as hir;
18
20
use rustc_hir:: { is_range_literal, Expr , ExprKind , Node } ;
19
21
use rustc_middle:: ty:: layout:: { IntegerExt , LayoutOf , SizeSkeleton } ;
20
- use rustc_middle:: ty:: GenericArgsRef ;
21
22
use rustc_middle:: ty:: {
22
23
self , AdtKind , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt ,
23
24
} ;
25
+ use rustc_middle:: ty:: { GenericArgsRef , TypeAndMut } ;
24
26
use rustc_span:: def_id:: LocalDefId ;
25
27
use rustc_span:: source_map;
26
28
use rustc_span:: symbol:: sym;
@@ -136,6 +138,37 @@ declare_lint! {
136
138
"detects invalid floating point NaN comparisons"
137
139
}
138
140
141
+ declare_lint ! {
142
+ /// The `unclear_fat_pointer_comparisons` lint checks comparison
143
+ /// of `*const/*mut ?Sized` as the operands.
144
+ ///
145
+ /// ### Example
146
+ ///
147
+ /// ```rust
148
+ /// # struct A;
149
+ /// # struct B;
150
+ ///
151
+ /// # trait T {}
152
+ /// # impl T for A {}
153
+ /// # impl T for B {}
154
+ ///
155
+ /// let ab = (A, B);
156
+ /// let a = &ab.0 as *const dyn T;
157
+ /// let b = &ab.1 as *const dyn T;
158
+ ///
159
+ /// let _ = a == b;
160
+ /// ```
161
+ ///
162
+ /// {{produces}}
163
+ ///
164
+ /// ### Explanation
165
+ ///
166
+ /// The comparison include metadata which is not guaranteed to be equivalent.
167
+ UNCLEAR_FAT_POINTER_COMPARISONS ,
168
+ Warn ,
169
+ "detects unclear fat pointer comparisons"
170
+ }
171
+
139
172
#[ derive( Copy , Clone ) ]
140
173
pub struct TypeLimits {
141
174
/// Id of the last visited negated expression
@@ -144,7 +177,12 @@ pub struct TypeLimits {
144
177
negated_expr_span : Option < Span > ,
145
178
}
146
179
147
- impl_lint_pass ! ( TypeLimits => [ UNUSED_COMPARISONS , OVERFLOWING_LITERALS , INVALID_NAN_COMPARISONS ] ) ;
180
+ impl_lint_pass ! ( TypeLimits => [
181
+ UNUSED_COMPARISONS ,
182
+ OVERFLOWING_LITERALS ,
183
+ INVALID_NAN_COMPARISONS ,
184
+ UNCLEAR_FAT_POINTER_COMPARISONS
185
+ ] ) ;
148
186
149
187
impl TypeLimits {
150
188
pub fn new ( ) -> TypeLimits {
@@ -620,6 +658,50 @@ fn lint_nan<'tcx>(
620
658
cx. emit_spanned_lint ( INVALID_NAN_COMPARISONS , e. span , lint) ;
621
659
}
622
660
661
+ fn lint_fat_pointer < ' tcx > (
662
+ cx : & LateContext < ' tcx > ,
663
+ e : & ' tcx hir:: Expr < ' tcx > ,
664
+ binop : hir:: BinOp ,
665
+ l : & ' tcx hir:: Expr < ' tcx > ,
666
+ r : & ' tcx hir:: Expr < ' tcx > ,
667
+ ) {
668
+ let Some ( l_ty) = cx. typeck_results ( ) . expr_ty_adjusted_opt ( l) else {
669
+ return ;
670
+ } ;
671
+ let Some ( r_ty) = cx. typeck_results ( ) . expr_ty_adjusted_opt ( r) else {
672
+ return ;
673
+ } ;
674
+
675
+ let is_ptr_unsized = |ty : Ty < ' tcx > | -> bool {
676
+ match ty. kind ( ) {
677
+ ty:: RawPtr ( TypeAndMut { mutbl : _, ty } ) => !ty. is_sized ( cx. tcx , cx. param_env ) ,
678
+ _ => false ,
679
+ }
680
+ } ;
681
+
682
+ if !is_ptr_unsized ( l_ty) || !is_ptr_unsized ( r_ty) {
683
+ return ;
684
+ }
685
+
686
+ cx. emit_spanned_lint (
687
+ UNCLEAR_FAT_POINTER_COMPARISONS ,
688
+ e. span ,
689
+ UnclearFatPointerComparisons {
690
+ addr_metadata_suggestion : matches ! ( binop. node, hir:: BinOpKind :: Eq | hir:: BinOpKind :: Ne )
691
+ . then ( || UnclearFatPointerComparisonsAddrMetadataSuggestion {
692
+ left_ne : ( binop. node == hir:: BinOpKind :: Ne ) . then ( || l. span . shrink_to_lo ( ) ) ,
693
+ left_eq : ( binop. node != hir:: BinOpKind :: Ne ) . then ( || l. span . shrink_to_lo ( ) ) ,
694
+ middle : l. span . shrink_to_hi ( ) . until ( r. span . shrink_to_lo ( ) ) ,
695
+ right : r. span . shrink_to_hi ( ) ,
696
+ } ) ,
697
+ addr_suggestion : UnclearFatPointerComparisonsAddrSuggestion {
698
+ left : l. span . shrink_to_hi ( ) ,
699
+ right : r. span . shrink_to_hi ( ) ,
700
+ } ,
701
+ } ,
702
+ ) ;
703
+ }
704
+
623
705
impl < ' tcx > LateLintPass < ' tcx > for TypeLimits {
624
706
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , e : & ' tcx hir:: Expr < ' tcx > ) {
625
707
match e. kind {
@@ -636,6 +718,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
636
718
cx. emit_spanned_lint ( UNUSED_COMPARISONS , e. span , UnusedComparisons ) ;
637
719
} else {
638
720
lint_nan ( cx, e, binop, l, r) ;
721
+ lint_fat_pointer ( cx, e, binop, l, r) ;
639
722
}
640
723
}
641
724
}
0 commit comments