@@ -3,10 +3,11 @@ use crate::{
33 lints:: {
44 AtomicOrderingFence , AtomicOrderingLoad , AtomicOrderingStore , ImproperCTypes ,
55 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 ,
1011 } ,
1112} ;
1213use crate :: { LateContext , LateLintPass , LintContext } ;
@@ -17,10 +18,10 @@ use rustc_errors::DiagnosticMessage;
1718use rustc_hir as hir;
1819use rustc_hir:: { is_range_literal, Expr , ExprKind , Node } ;
1920use rustc_middle:: ty:: layout:: { IntegerExt , LayoutOf , SizeSkeleton } ;
20- use rustc_middle:: ty:: GenericArgsRef ;
2121use rustc_middle:: ty:: {
2222 self , AdtKind , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt ,
2323} ;
24+ use rustc_middle:: ty:: { GenericArgsRef , TypeAndMut } ;
2425use rustc_span:: def_id:: LocalDefId ;
2526use rustc_span:: source_map;
2627use rustc_span:: symbol:: sym;
@@ -136,6 +137,37 @@ declare_lint! {
136137 "detects invalid floating point NaN comparisons"
137138}
138139
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+
139171#[ derive( Copy , Clone ) ]
140172pub struct TypeLimits {
141173 /// Id of the last visited negated expression
@@ -144,7 +176,12 @@ pub struct TypeLimits {
144176 negated_expr_span : Option < Span > ,
145177}
146178
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+ ] ) ;
148185
149186impl TypeLimits {
150187 pub fn new ( ) -> TypeLimits {
@@ -620,6 +657,52 @@ fn lint_nan<'tcx>(
620657 cx. emit_spanned_lint ( INVALID_NAN_COMPARISONS , e. span , lint) ;
621658}
622659
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+
623706impl < ' tcx > LateLintPass < ' tcx > for TypeLimits {
624707 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , e : & ' tcx hir:: Expr < ' tcx > ) {
625708 match e. kind {
@@ -636,6 +719,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
636719 cx. emit_spanned_lint ( UNUSED_COMPARISONS , e. span , UnusedComparisons ) ;
637720 } else {
638721 lint_nan ( cx, e, binop, l, r) ;
722+ lint_pointer_trait ( cx, e, binop, l, r) ;
639723 }
640724 }
641725 }
0 commit comments