Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8a37655

Browse files
committedDec 11, 2023
Auto merge of rust-lang#117758 - Urgau:lint_pointer_trait_comparisons, r=davidtwco
Add lint against ambiguous wide pointer comparisons This PR is the resolution of rust-lang#106447 decided in rust-lang#117717 by T-lang. ## `ambiguous_wide_pointer_comparisons` *warn-by-default* The `ambiguous_wide_pointer_comparisons` lint checks comparison of `*const/*mut ?Sized` as the operands. ### Example ```rust let ab = (A, B); let a = &ab.0 as *const dyn T; let b = &ab.1 as *const dyn T; let _ = a == b; ``` ### Explanation The comparison includes metadata which may not be expected. ------- This PR also drops `clippy::vtable_address_comparisons` which is superseded by this one. ~~One thing: is the current naming right? `invalid` seems a bit too much.~~ Fixes rust-lang#117717
2 parents ff2c563 + 5e1bfb5 commit 8a37655

File tree

25 files changed

+933
-254
lines changed

25 files changed

+933
-254
lines changed
 

‎compiler/rustc_codegen_cranelift/example/mini_core.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
thread_local
1212
)]
1313
#![no_core]
14-
#![allow(dead_code, internal_features)]
14+
#![allow(dead_code, internal_features, ambiguous_wide_pointer_comparisons)]
1515

1616
#[lang = "sized"]
1717
pub trait Sized {}

‎compiler/rustc_lint/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
2+
.addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses
3+
.addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
4+
15
lint_array_into_iter =
26
this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021
37
.use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity

‎compiler/rustc_lint/src/lints.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,76 @@ pub enum InvalidNanComparisonsSuggestion {
15741574
Spanless,
15751575
}
15761576

1577+
#[derive(LintDiagnostic)]
1578+
pub enum AmbiguousWidePointerComparisons<'a> {
1579+
#[diag(lint_ambiguous_wide_pointer_comparisons)]
1580+
Spanful {
1581+
#[subdiagnostic]
1582+
addr_suggestion: AmbiguousWidePointerComparisonsAddrSuggestion<'a>,
1583+
#[subdiagnostic]
1584+
addr_metadata_suggestion: Option<AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a>>,
1585+
},
1586+
#[diag(lint_ambiguous_wide_pointer_comparisons)]
1587+
#[help(lint_addr_metadata_suggestion)]
1588+
#[help(lint_addr_suggestion)]
1589+
Spanless,
1590+
}
1591+
1592+
#[derive(Subdiagnostic)]
1593+
#[multipart_suggestion(
1594+
lint_addr_metadata_suggestion,
1595+
style = "verbose",
1596+
applicability = "machine-applicable"
1597+
)]
1598+
pub struct AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a> {
1599+
pub ne: &'a str,
1600+
pub deref_left: &'a str,
1601+
pub deref_right: &'a str,
1602+
#[suggestion_part(code = "{ne}std::ptr::eq({deref_left}")]
1603+
pub left: Span,
1604+
#[suggestion_part(code = ", {deref_right}")]
1605+
pub middle: Span,
1606+
#[suggestion_part(code = ")")]
1607+
pub right: Span,
1608+
}
1609+
1610+
#[derive(Subdiagnostic)]
1611+
pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
1612+
#[multipart_suggestion(
1613+
lint_addr_suggestion,
1614+
style = "verbose",
1615+
applicability = "machine-applicable"
1616+
)]
1617+
AddrEq {
1618+
ne: &'a str,
1619+
deref_left: &'a str,
1620+
deref_right: &'a str,
1621+
#[suggestion_part(code = "{ne}std::ptr::addr_eq({deref_left}")]
1622+
left: Span,
1623+
#[suggestion_part(code = ", {deref_right}")]
1624+
middle: Span,
1625+
#[suggestion_part(code = ")")]
1626+
right: Span,
1627+
},
1628+
#[multipart_suggestion(
1629+
lint_addr_suggestion,
1630+
style = "verbose",
1631+
applicability = "machine-applicable"
1632+
)]
1633+
Cast {
1634+
deref_left: &'a str,
1635+
deref_right: &'a str,
1636+
#[suggestion_part(code = "{deref_left}")]
1637+
left_before: Option<Span>,
1638+
#[suggestion_part(code = " as *const ()")]
1639+
left: Span,
1640+
#[suggestion_part(code = "{deref_right}")]
1641+
right_before: Option<Span>,
1642+
#[suggestion_part(code = " as *const ()")]
1643+
right: Span,
1644+
},
1645+
}
1646+
15771647
pub struct ImproperCTypes<'a> {
15781648
pub ty: Ty<'a>,
15791649
pub desc: &'a str,

‎compiler/rustc_lint/src/types.rs

Lines changed: 172 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use crate::{
22
fluent_generated as fluent,
33
lints::{
4-
AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes,
5-
InvalidAtomicOrderingDiag, InvalidNanComparisons, InvalidNanComparisonsSuggestion,
6-
OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub,
7-
OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral,
8-
OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange,
9-
VariantSizeDifferencesDiag,
4+
AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
5+
AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
6+
AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
7+
InvalidNanComparisonsSuggestion, OnlyCastu8ToChar, OverflowingBinHex,
8+
OverflowingBinHexSign, OverflowingBinHexSignBitSub, OverflowingBinHexSub, OverflowingInt,
9+
OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, RangeEndpointOutOfRange,
10+
UnusedComparisons, UseInclusiveRange, VariantSizeDifferencesDiag,
1011
},
1112
};
1213
use crate::{LateContext, LateLintPass, LintContext};
@@ -17,17 +18,18 @@ use rustc_errors::DiagnosticMessage;
1718
use rustc_hir as hir;
1819
use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
1920
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
20-
use rustc_middle::ty::GenericArgsRef;
2121
use rustc_middle::ty::{
2222
self, AdtKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
2323
};
24+
use rustc_middle::ty::{GenericArgsRef, TypeAndMut};
2425
use rustc_span::def_id::LocalDefId;
2526
use rustc_span::source_map;
2627
use rustc_span::symbol::sym;
2728
use rustc_span::{Span, Symbol};
2829
use rustc_target::abi::{Abi, Size, WrappingRange};
2930
use rustc_target::abi::{Integer, TagEncoding, Variants};
3031
use rustc_target::spec::abi::Abi as SpecAbi;
32+
use rustc_type_ir::DynKind;
3133

3234
use std::iter;
3335
use std::ops::ControlFlow;
@@ -136,6 +138,37 @@ declare_lint! {
136138
"detects invalid floating point NaN comparisons"
137139
}
138140

141+
declare_lint! {
142+
/// The `ambiguous_wide_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 includes metadata which may not be expected.
167+
AMBIGUOUS_WIDE_POINTER_COMPARISONS,
168+
Warn,
169+
"detects ambiguous wide pointer comparisons"
170+
}
171+
139172
#[derive(Copy, Clone)]
140173
pub 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+
AMBIGUOUS_WIDE_POINTER_COMPARISONS
185+
]);
148186

149187
impl TypeLimits {
150188
pub fn new() -> TypeLimits {
@@ -620,6 +658,106 @@ fn lint_nan<'tcx>(
620658
cx.emit_spanned_lint(INVALID_NAN_COMPARISONS, e.span, lint);
621659
}
622660

661+
fn lint_wide_pointer<'tcx>(
662+
cx: &LateContext<'tcx>,
663+
e: &'tcx hir::Expr<'tcx>,
664+
binop: hir::BinOpKind,
665+
l: &'tcx hir::Expr<'tcx>,
666+
r: &'tcx hir::Expr<'tcx>,
667+
) {
668+
let ptr_unsized = |mut ty: Ty<'tcx>| -> Option<(usize, bool)> {
669+
let mut refs = 0;
670+
// here we remove any "implicit" references and count the number
671+
// of them to correctly suggest the right number of deref
672+
while let ty::Ref(_, inner_ty, _) = ty.kind() {
673+
ty = *inner_ty;
674+
refs += 1;
675+
}
676+
match ty.kind() {
677+
ty::RawPtr(TypeAndMut { mutbl: _, ty }) => (!ty.is_sized(cx.tcx, cx.param_env))
678+
.then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, DynKind::Dyn)))),
679+
_ => None,
680+
}
681+
};
682+
683+
// PartialEq::{eq,ne} takes references, remove any explicit references
684+
let l = l.peel_borrows();
685+
let r = r.peel_borrows();
686+
687+
let Some(l_ty) = cx.typeck_results().expr_ty_opt(l) else {
688+
return;
689+
};
690+
let Some(r_ty) = cx.typeck_results().expr_ty_opt(r) else {
691+
return;
692+
};
693+
694+
let Some((l_ty_refs, l_inner_ty_is_dyn)) = ptr_unsized(l_ty) else {
695+
return;
696+
};
697+
let Some((r_ty_refs, r_inner_ty_is_dyn)) = ptr_unsized(r_ty) else {
698+
return;
699+
};
700+
701+
let (Some(l_span), Some(r_span)) =
702+
(l.span.find_ancestor_inside(e.span), r.span.find_ancestor_inside(e.span))
703+
else {
704+
return cx.emit_spanned_lint(
705+
AMBIGUOUS_WIDE_POINTER_COMPARISONS,
706+
e.span,
707+
AmbiguousWidePointerComparisons::Spanless,
708+
);
709+
};
710+
711+
let ne = if binop == hir::BinOpKind::Ne { "!" } else { "" };
712+
let is_eq_ne = matches!(binop, hir::BinOpKind::Eq | hir::BinOpKind::Ne);
713+
let is_dyn_comparison = l_inner_ty_is_dyn && r_inner_ty_is_dyn;
714+
715+
let left = e.span.shrink_to_lo().until(l_span.shrink_to_lo());
716+
let middle = l_span.shrink_to_hi().until(r_span.shrink_to_lo());
717+
let right = r_span.shrink_to_hi().until(e.span.shrink_to_hi());
718+
719+
let deref_left = &*"*".repeat(l_ty_refs);
720+
let deref_right = &*"*".repeat(r_ty_refs);
721+
722+
cx.emit_spanned_lint(
723+
AMBIGUOUS_WIDE_POINTER_COMPARISONS,
724+
e.span,
725+
AmbiguousWidePointerComparisons::Spanful {
726+
addr_metadata_suggestion: (is_eq_ne && !is_dyn_comparison).then(|| {
727+
AmbiguousWidePointerComparisonsAddrMetadataSuggestion {
728+
ne,
729+
deref_left,
730+
deref_right,
731+
left,
732+
middle,
733+
right,
734+
}
735+
}),
736+
addr_suggestion: if is_eq_ne {
737+
AmbiguousWidePointerComparisonsAddrSuggestion::AddrEq {
738+
ne,
739+
deref_left,
740+
deref_right,
741+
left,
742+
middle,
743+
right,
744+
}
745+
} else {
746+
AmbiguousWidePointerComparisonsAddrSuggestion::Cast {
747+
deref_left,
748+
deref_right,
749+
// those two Options are required for correctness as having
750+
// an empty span and an empty suggestion is not permitted
751+
left_before: (l_ty_refs != 0).then_some(left),
752+
right_before: (r_ty_refs != 0).then(|| r_span.shrink_to_lo()),
753+
left: l_span.shrink_to_hi(),
754+
right,
755+
}
756+
},
757+
},
758+
);
759+
}
760+
623761
impl<'tcx> LateLintPass<'tcx> for TypeLimits {
624762
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
625763
match e.kind {
@@ -636,10 +774,26 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
636774
cx.emit_spanned_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons);
637775
} else {
638776
lint_nan(cx, e, binop, l, r);
777+
lint_wide_pointer(cx, e, binop.node, l, r);
639778
}
640779
}
641780
}
642781
hir::ExprKind::Lit(lit) => lint_literal(cx, self, e, lit),
782+
hir::ExprKind::Call(path, [l, r])
783+
if let ExprKind::Path(ref qpath) = path.kind
784+
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
785+
&& let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
786+
&& let Some(binop) = partialeq_binop(diag_item) =>
787+
{
788+
lint_wide_pointer(cx, e, binop, l, r);
789+
}
790+
hir::ExprKind::MethodCall(_, l, [r], _)
791+
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
792+
&& let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
793+
&& let Some(binop) = partialeq_binop(diag_item) =>
794+
{
795+
lint_wide_pointer(cx, e, binop, l, r);
796+
}
643797
_ => {}
644798
};
645799

@@ -722,6 +876,16 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
722876
| hir::BinOpKind::Gt
723877
)
724878
}
879+
880+
fn partialeq_binop(diag_item: Symbol) -> Option<hir::BinOpKind> {
881+
if diag_item == sym::cmp_partialeq_eq {
882+
Some(hir::BinOpKind::Eq)
883+
} else if diag_item == sym::cmp_partialeq_ne {
884+
Some(hir::BinOpKind::Ne)
885+
} else {
886+
None
887+
}
888+
}
725889
}
726890
}
727891

‎compiler/rustc_span/src/symbol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,8 @@ symbols! {
520520
cmp,
521521
cmp_max,
522522
cmp_min,
523+
cmp_partialeq_eq,
524+
cmp_partialeq_ne,
523525
cmpxchg16b_target_feature,
524526
cmse_nonsecure_entry,
525527
coerce_unsized,

‎library/alloc/tests/vec.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1980,7 +1980,7 @@ fn vec_macro_repeating_null_raw_fat_pointer() {
19801980

19811981
let vec = vec![null_raw_dyn; 1];
19821982
dbg!(ptr_metadata(vec[0]));
1983-
assert!(vec[0] == null_raw_dyn);
1983+
assert!(std::ptr::eq(vec[0], null_raw_dyn));
19841984

19851985
// Polyfill for https://github.com/rust-lang/rfcs/pull/2580
19861986

‎library/core/src/cmp.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,15 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
230230
/// by `==`.
231231
#[must_use]
232232
#[stable(feature = "rust1", since = "1.0.0")]
233+
#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialeq_eq")]
233234
fn eq(&self, other: &Rhs) -> bool;
234235

235236
/// This method tests for `!=`. The default implementation is almost always
236237
/// sufficient, and should not be overridden without very good reason.
237238
#[inline]
238239
#[must_use]
239240
#[stable(feature = "rust1", since = "1.0.0")]
241+
#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialeq_ne")]
240242
fn ne(&self, other: &Rhs) -> bool {
241243
!self.eq(other)
242244
}

‎library/core/src/ptr/const_ptr.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,7 @@ impl<T> *const [T] {
17721772
#[stable(feature = "rust1", since = "1.0.0")]
17731773
impl<T: ?Sized> PartialEq for *const T {
17741774
#[inline]
1775+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
17751776
fn eq(&self, other: &*const T) -> bool {
17761777
*self == *other
17771778
}
@@ -1784,6 +1785,7 @@ impl<T: ?Sized> Eq for *const T {}
17841785
#[stable(feature = "rust1", since = "1.0.0")]
17851786
impl<T: ?Sized> Ord for *const T {
17861787
#[inline]
1788+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
17871789
fn cmp(&self, other: &*const T) -> Ordering {
17881790
if self < other {
17891791
Less
@@ -1803,21 +1805,25 @@ impl<T: ?Sized> PartialOrd for *const T {
18031805
}
18041806

18051807
#[inline]
1808+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
18061809
fn lt(&self, other: &*const T) -> bool {
18071810
*self < *other
18081811
}
18091812

18101813
#[inline]
1814+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
18111815
fn le(&self, other: &*const T) -> bool {
18121816
*self <= *other
18131817
}
18141818

18151819
#[inline]
1820+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
18161821
fn gt(&self, other: &*const T) -> bool {
18171822
*self > *other
18181823
}
18191824

18201825
#[inline]
1826+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
18211827
fn ge(&self, other: &*const T) -> bool {
18221828
*self >= *other
18231829
}

‎library/core/src/ptr/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,6 +1897,7 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
18971897
#[inline(always)]
18981898
#[must_use = "pointer comparison produces a value"]
18991899
#[rustc_diagnostic_item = "ptr_eq"]
1900+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))] // it's actually clear here
19001901
pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
19011902
a == b
19021903
}

‎library/core/src/ptr/mut_ptr.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,6 +2199,7 @@ impl<T> *mut [T] {
21992199
#[stable(feature = "rust1", since = "1.0.0")]
22002200
impl<T: ?Sized> PartialEq for *mut T {
22012201
#[inline(always)]
2202+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
22022203
fn eq(&self, other: &*mut T) -> bool {
22032204
*self == *other
22042205
}
@@ -2210,6 +2211,7 @@ impl<T: ?Sized> Eq for *mut T {}
22102211
#[stable(feature = "rust1", since = "1.0.0")]
22112212
impl<T: ?Sized> Ord for *mut T {
22122213
#[inline]
2214+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
22132215
fn cmp(&self, other: &*mut T) -> Ordering {
22142216
if self < other {
22152217
Less
@@ -2229,21 +2231,25 @@ impl<T: ?Sized> PartialOrd for *mut T {
22292231
}
22302232

22312233
#[inline(always)]
2234+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
22322235
fn lt(&self, other: &*mut T) -> bool {
22332236
*self < *other
22342237
}
22352238

22362239
#[inline(always)]
2240+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
22372241
fn le(&self, other: &*mut T) -> bool {
22382242
*self <= *other
22392243
}
22402244

22412245
#[inline(always)]
2246+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
22422247
fn gt(&self, other: &*mut T) -> bool {
22432248
*self > *other
22442249
}
22452250

22462251
#[inline(always)]
2252+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
22472253
fn ge(&self, other: &*mut T) -> bool {
22482254
*self >= *other
22492255
}

‎library/core/src/ptr/non_null.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1791,6 +1791,7 @@ impl<T: ?Sized> Eq for NonNull<T> {}
17911791
#[stable(feature = "nonnull", since = "1.25.0")]
17921792
impl<T: ?Sized> PartialEq for NonNull<T> {
17931793
#[inline]
1794+
#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
17941795
fn eq(&self, other: &Self) -> bool {
17951796
self.as_ptr() == other.as_ptr()
17961797
}

‎src/tools/clippy/clippy_lints/src/declared_lints.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
684684
crate::unit_types::UNIT_ARG_INFO,
685685
crate::unit_types::UNIT_CMP_INFO,
686686
crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO,
687-
crate::unnamed_address::VTABLE_ADDRESS_COMPARISONS_INFO,
688687
crate::unnecessary_box_returns::UNNECESSARY_BOX_RETURNS_INFO,
689688
crate::unnecessary_map_on_constructor::UNNECESSARY_MAP_ON_CONSTRUCTOR_INFO,
690689
crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,

‎src/tools/clippy/clippy_lints/src/renamed_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,5 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
5858
("clippy::undropped_manually_drops", "undropped_manually_drops"),
5959
("clippy::unknown_clippy_lints", "unknown_lints"),
6060
("clippy::unused_label", "unused_labels"),
61+
("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
6162
];

‎src/tools/clippy/clippy_lints/src/unnamed_address.rs

Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
1+
use clippy_utils::diagnostics::span_lint;
22
use rustc_hir::{BinOpKind, Expr, ExprKind};
33
use rustc_lint::{LateContext, LateLintPass};
44
use rustc_middle::ty;
55
use rustc_session::declare_lint_pass;
6-
use rustc_span::sym;
76

87
declare_clippy_lint! {
98
/// ### What it does
@@ -29,31 +28,7 @@ declare_clippy_lint! {
2928
"comparison with an address of a function item"
3029
}
3130

32-
declare_clippy_lint! {
33-
/// ### What it does
34-
/// Checks for comparisons with an address of a trait vtable.
35-
///
36-
/// ### Why is this bad?
37-
/// Comparing trait objects pointers compares an vtable addresses which
38-
/// are not guaranteed to be unique and could vary between different code generation units.
39-
/// Furthermore vtables for different types could have the same address after being merged
40-
/// together.
41-
///
42-
/// ### Example
43-
/// ```rust,ignore
44-
/// let a: Rc<dyn Trait> = ...
45-
/// let b: Rc<dyn Trait> = ...
46-
/// if Rc::ptr_eq(&a, &b) {
47-
/// ...
48-
/// }
49-
/// ```
50-
#[clippy::version = "1.44.0"]
51-
pub VTABLE_ADDRESS_COMPARISONS,
52-
correctness,
53-
"comparison with an address of a trait vtable"
54-
}
55-
56-
declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS, VTABLE_ADDRESS_COMPARISONS]);
31+
declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS]);
5732

5833
impl LateLintPass<'_> for UnnamedAddress {
5934
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
@@ -64,49 +39,10 @@ impl LateLintPass<'_> for UnnamedAddress {
6439
)
6540
}
6641

67-
fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
68-
match cx.typeck_results().expr_ty_adjusted(expr).kind() {
69-
ty::RawPtr(ty::TypeAndMut { ty, .. }) => ty.is_trait(),
70-
_ => false,
71-
}
72-
}
73-
7442
fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
7543
matches!(cx.typeck_results().expr_ty(expr).kind(), ty::FnDef(..))
7644
}
7745

78-
if let ExprKind::Binary(binop, left, right) = expr.kind
79-
&& is_comparison(binop.node)
80-
&& is_trait_ptr(cx, left)
81-
&& is_trait_ptr(cx, right)
82-
{
83-
span_lint_and_help(
84-
cx,
85-
VTABLE_ADDRESS_COMPARISONS,
86-
expr.span,
87-
"comparing trait object pointers compares a non-unique vtable address",
88-
None,
89-
"consider extracting and comparing data pointers only",
90-
);
91-
}
92-
93-
if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind
94-
&& let ExprKind::Path(ref func_qpath) = func.kind
95-
&& let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id()
96-
&& cx.tcx.is_diagnostic_item(sym::ptr_eq, def_id)
97-
&& let ty_param = cx.typeck_results().node_args(func.hir_id).type_at(0)
98-
&& ty_param.is_trait()
99-
{
100-
span_lint_and_help(
101-
cx,
102-
VTABLE_ADDRESS_COMPARISONS,
103-
expr.span,
104-
"comparing trait object pointers compares a non-unique vtable address",
105-
None,
106-
"consider extracting and comparing data pointers only",
107-
);
108-
}
109-
11046
if let ExprKind::Binary(binop, left, right) = expr.kind
11147
&& is_comparison(binop.node)
11248
&& cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr()

‎src/tools/clippy/tests/ui/rename.fixed

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#![allow(undropped_manually_drops)]
5252
#![allow(unknown_lints)]
5353
#![allow(unused_labels)]
54+
#![allow(ambiguous_wide_pointer_comparisons)]
5455
#![warn(clippy::almost_complete_range)]
5556
#![warn(clippy::disallowed_names)]
5657
#![warn(clippy::blocks_in_if_conditions)]
@@ -107,5 +108,6 @@
107108
#![warn(undropped_manually_drops)]
108109
#![warn(unknown_lints)]
109110
#![warn(unused_labels)]
111+
#![warn(ambiguous_wide_pointer_comparisons)]
110112

111113
fn main() {}

‎src/tools/clippy/tests/ui/rename.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#![allow(undropped_manually_drops)]
5252
#![allow(unknown_lints)]
5353
#![allow(unused_labels)]
54+
#![allow(ambiguous_wide_pointer_comparisons)]
5455
#![warn(clippy::almost_complete_letter_range)]
5556
#![warn(clippy::blacklisted_name)]
5657
#![warn(clippy::block_in_if_condition_expr)]
@@ -107,5 +108,6 @@
107108
#![warn(clippy::undropped_manually_drops)]
108109
#![warn(clippy::unknown_clippy_lints)]
109110
#![warn(clippy::unused_label)]
111+
#![warn(clippy::vtable_address_comparisons)]
110112

111113
fn main() {}

‎src/tools/clippy/tests/ui/rename.stderr

Lines changed: 63 additions & 57 deletions
Large diffs are not rendered by default.

‎src/tools/clippy/tests/ui/vtable_address_comparisons.rs

Lines changed: 0 additions & 52 deletions
This file was deleted.

‎src/tools/clippy/tests/ui/vtable_address_comparisons.stderr

Lines changed: 0 additions & 68 deletions
This file was deleted.

‎src/tools/miri/tests/pass/pointers.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//@[tree]compile-flags: -Zmiri-tree-borrows
33
//@compile-flags: -Zmiri-permissive-provenance
44
#![feature(ptr_metadata, const_raw_ptr_comparison)]
5+
#![allow(ambiguous_wide_pointer_comparisons)]
56

67
use std::mem::{self, transmute};
78
use std::ptr;

‎src/tools/miri/tests/pass/rc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//@compile-flags: -Zmiri-strict-provenance
44
#![feature(new_uninit)]
55
#![feature(get_mut_unchecked)]
6+
#![allow(ambiguous_wide_pointer_comparisons)]
67

78
use std::cell::{Cell, RefCell};
89
use std::fmt::Debug;

‎tests/ui/issues/issue-17336.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// build-pass
2+
23
#![allow(unused_must_use)]
4+
#![allow(ambiguous_wide_pointer_comparisons)]
5+
36
#[allow(dead_code)]
47
fn check(a: &str) {
58
let x = a as *const str;
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
// check-pass
2+
3+
use std::rc::Rc;
4+
use std::sync::Arc;
5+
use std::cmp::PartialEq;
6+
7+
struct A;
8+
struct B;
9+
10+
trait T {}
11+
impl T for A {}
12+
impl T for B {}
13+
14+
fn main() {
15+
let ab = (A, B);
16+
let a = &ab.0 as *const dyn T;
17+
let b = &ab.1 as *const dyn T;
18+
19+
let _ = a == b;
20+
//~^ WARN ambiguous wide pointer comparison
21+
let _ = a != b;
22+
//~^ WARN ambiguous wide pointer comparison
23+
let _ = a < b;
24+
//~^ WARN ambiguous wide pointer comparison
25+
let _ = a <= b;
26+
//~^ WARN ambiguous wide pointer comparison
27+
let _ = a > b;
28+
//~^ WARN ambiguous wide pointer comparison
29+
let _ = a >= b;
30+
//~^ WARN ambiguous wide pointer comparison
31+
32+
let _ = PartialEq::eq(&a, &b);
33+
//~^ WARN ambiguous wide pointer comparison
34+
let _ = PartialEq::ne(&a, &b);
35+
//~^ WARN ambiguous wide pointer comparison
36+
let _ = a.eq(&b);
37+
//~^ WARN ambiguous wide pointer comparison
38+
let _ = a.ne(&b);
39+
//~^ WARN ambiguous wide pointer comparison
40+
41+
{
42+
// &*const ?Sized
43+
let a = &a;
44+
let b = &b;
45+
46+
let _ = a == b;
47+
//~^ WARN ambiguous wide pointer comparison
48+
let _ = a != b;
49+
//~^ WARN ambiguous wide pointer comparison
50+
let _ = a < b;
51+
//~^ WARN ambiguous wide pointer comparison
52+
let _ = a <= b;
53+
//~^ WARN ambiguous wide pointer comparison
54+
let _ = a > b;
55+
//~^ WARN ambiguous wide pointer comparison
56+
let _ = a >= b;
57+
//~^ WARN ambiguous wide pointer comparison
58+
59+
let _ = PartialEq::eq(a, b);
60+
//~^ WARN ambiguous wide pointer comparison
61+
let _ = PartialEq::ne(a, b);
62+
//~^ WARN ambiguous wide pointer comparison
63+
let _ = PartialEq::eq(&a, &b);
64+
//~^ WARN ambiguous wide pointer comparison
65+
let _ = PartialEq::ne(&a, &b);
66+
//~^ WARN ambiguous wide pointer comparison
67+
let _ = a.eq(b);
68+
//~^ WARN ambiguous wide pointer comparison
69+
let _ = a.ne(b);
70+
//~^ WARN ambiguous wide pointer comparison
71+
}
72+
73+
let s = "" as *const str;
74+
let _ = s == s;
75+
//~^ WARN ambiguous wide pointer comparison
76+
77+
let s = &[8, 7][..] as *const [i32];
78+
let _ = s == s;
79+
//~^ WARN ambiguous wide pointer comparison
80+
81+
fn cmp<T: ?Sized>(a: *mut T, b: *mut T) -> bool {
82+
let _ = a == b;
83+
//~^ WARN ambiguous wide pointer comparison
84+
let _ = a != b;
85+
//~^ WARN ambiguous wide pointer comparison
86+
let _ = a < b;
87+
//~^ WARN ambiguous wide pointer comparison
88+
let _ = a <= b;
89+
//~^ WARN ambiguous wide pointer comparison
90+
let _ = a > b;
91+
//~^ WARN ambiguous wide pointer comparison
92+
let _ = a >= b;
93+
//~^ WARN ambiguous wide pointer comparison
94+
95+
let _ = PartialEq::eq(&a, &b);
96+
//~^ WARN ambiguous wide pointer comparison
97+
let _ = PartialEq::ne(&a, &b);
98+
//~^ WARN ambiguous wide pointer comparison
99+
let _ = a.eq(&b);
100+
//~^ WARN ambiguous wide pointer comparison
101+
let _ = a.ne(&b);
102+
//~^ WARN ambiguous wide pointer comparison
103+
104+
let a = &a;
105+
let b = &b;
106+
&*a == &*b
107+
//~^ WARN ambiguous wide pointer comparison
108+
}
109+
110+
{
111+
macro_rules! cmp {
112+
($a:ident, $b:ident) => { $a == $b }
113+
//~^ WARN ambiguous wide pointer comparison
114+
}
115+
116+
cmp!(a, b);
117+
}
118+
119+
{
120+
// this produce weird diagnostics
121+
macro_rules! cmp {
122+
($a:expr, $b:expr) => { $a == $b }
123+
//~^ WARN ambiguous wide pointer comparison
124+
}
125+
126+
cmp!(&a, &b);
127+
}
128+
129+
let _ = std::ptr::eq(a, b);
130+
let _ = std::ptr::addr_eq(a, b);
131+
let _ = a as *const () == b as *const ();
132+
133+
let a: Rc<dyn std::fmt::Debug> = Rc::new(1);
134+
Rc::ptr_eq(&a, &a);
135+
136+
let a: Arc<dyn std::fmt::Debug> = Arc::new(1);
137+
Arc::ptr_eq(&a, &a);
138+
}

‎tests/ui/lint/wide_pointer_comparisons.stderr

Lines changed: 452 additions & 0 deletions
Large diffs are not rendered by default.

‎tests/ui/mir/mir_raw_fat_ptr.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// run-pass
22
// check raw fat pointer ops in mir
33
// FIXME: please improve this when we get monomorphization support
4+
45
#![feature(raw_ref_op)]
6+
#![allow(ambiguous_wide_pointer_comparisons)]
57

68
use std::mem;
79

0 commit comments

Comments
 (0)
Please sign in to comment.