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