@@ -5,7 +5,9 @@ use crate::{
55 InvalidAtomicOrderingDiag , InvalidNanComparisons , InvalidNanComparisonsSuggestion ,
66 OnlyCastu8ToChar , OverflowingBinHex , OverflowingBinHexSign , OverflowingBinHexSignBitSub ,
77 OverflowingBinHexSub , OverflowingInt , OverflowingIntHelp , OverflowingLiteral ,
8- OverflowingUInt , RangeEndpointOutOfRange , UnusedComparisons , UseInclusiveRange ,
8+ OverflowingUInt , RangeEndpointOutOfRange , UnclearFatPointerComparisons ,
9+ UnclearFatPointerComparisonsAddrMetadataSuggestion ,
10+ UnclearFatPointerComparisonsAddrSuggestion , UnusedComparisons , UseInclusiveRange ,
911 VariantSizeDifferencesDiag ,
1012 } ,
1113} ;
@@ -17,10 +19,10 @@ use rustc_errors::DiagnosticMessage;
1719use rustc_hir as hir;
1820use rustc_hir:: { is_range_literal, Expr , ExprKind , Node } ;
1921use rustc_middle:: ty:: layout:: { IntegerExt , LayoutOf , SizeSkeleton } ;
20- use rustc_middle:: ty:: GenericArgsRef ;
2122use rustc_middle:: ty:: {
2223 self , AdtKind , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt ,
2324} ;
25+ use rustc_middle:: ty:: { GenericArgsRef , TypeAndMut } ;
2426use rustc_span:: def_id:: LocalDefId ;
2527use rustc_span:: source_map;
2628use rustc_span:: symbol:: sym;
@@ -136,6 +138,37 @@ declare_lint! {
136138 "detects invalid floating point NaN comparisons"
137139}
138140
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+
139172#[ derive( Copy , Clone ) ]
140173pub struct TypeLimits {
141174 /// Id of the last visited negated expression
@@ -144,7 +177,12 @@ pub struct TypeLimits {
144177 negated_expr_span : Option < Span > ,
145178}
146179
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+ ] ) ;
148186
149187impl TypeLimits {
150188 pub fn new ( ) -> TypeLimits {
@@ -620,6 +658,50 @@ fn lint_nan<'tcx>(
620658 cx. emit_spanned_lint ( INVALID_NAN_COMPARISONS , e. span , lint) ;
621659}
622660
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+
623705impl < ' tcx > LateLintPass < ' tcx > for TypeLimits {
624706 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , e : & ' tcx hir:: Expr < ' tcx > ) {
625707 match e. kind {
@@ -636,6 +718,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
636718 cx. emit_spanned_lint ( UNUSED_COMPARISONS , e. span , UnusedComparisons ) ;
637719 } else {
638720 lint_nan ( cx, e, binop, l, r) ;
721+ lint_fat_pointer ( cx, e, binop, l, r) ;
639722 }
640723 }
641724 }
0 commit comments