Add warn-by-default lint against unpredictable fn pointer comparisons
This commit is contained in:
parent
3bff51ea91
commit
9d1f790594
8 changed files with 521 additions and 4 deletions
|
@ -882,6 +882,12 @@ lint_unnameable_test_items = cannot test inner items
|
||||||
lint_unnecessary_qualification = unnecessary qualification
|
lint_unnecessary_qualification = unnecessary qualification
|
||||||
.suggestion = remove the unnecessary path segments
|
.suggestion = remove the unnecessary path segments
|
||||||
|
|
||||||
|
lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
.note_duplicated_fn = the address of the same function can vary between different codegen units
|
||||||
|
.note_deduplicated_fn = furthermore, different functions could have the same address after being merged together
|
||||||
|
.note_visit_fn_addr_eq = for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
.fn_addr_eq_suggestion = refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
||||||
lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::`
|
lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::`
|
||||||
|
|
||||||
lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
|
lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
|
||||||
|
|
|
@ -1810,6 +1810,42 @@ pub(crate) enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
pub(crate) enum UnpredictableFunctionPointerComparisons<'a> {
|
||||||
|
#[diag(lint_unpredictable_fn_pointer_comparisons)]
|
||||||
|
#[note(lint_note_duplicated_fn)]
|
||||||
|
#[note(lint_note_deduplicated_fn)]
|
||||||
|
#[note(lint_note_visit_fn_addr_eq)]
|
||||||
|
Suggestion {
|
||||||
|
#[subdiagnostic]
|
||||||
|
sugg: UnpredictableFunctionPointerComparisonsSuggestion<'a>,
|
||||||
|
},
|
||||||
|
#[diag(lint_unpredictable_fn_pointer_comparisons)]
|
||||||
|
#[note(lint_note_duplicated_fn)]
|
||||||
|
#[note(lint_note_deduplicated_fn)]
|
||||||
|
#[note(lint_note_visit_fn_addr_eq)]
|
||||||
|
Warn,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(
|
||||||
|
lint_fn_addr_eq_suggestion,
|
||||||
|
style = "verbose",
|
||||||
|
applicability = "maybe-incorrect"
|
||||||
|
)]
|
||||||
|
pub(crate) struct UnpredictableFunctionPointerComparisonsSuggestion<'a> {
|
||||||
|
pub ne: &'a str,
|
||||||
|
pub cast_right: String,
|
||||||
|
pub deref_left: &'a str,
|
||||||
|
pub deref_right: &'a str,
|
||||||
|
#[suggestion_part(code = "{ne}std::ptr::fn_addr_eq({deref_left}")]
|
||||||
|
pub left: Span,
|
||||||
|
#[suggestion_part(code = ", {deref_right}")]
|
||||||
|
pub middle: Span,
|
||||||
|
#[suggestion_part(code = "{cast_right})")]
|
||||||
|
pub right: Span,
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct ImproperCTypes<'a> {
|
pub(crate) struct ImproperCTypes<'a> {
|
||||||
pub ty: Ty<'a>,
|
pub ty: Ty<'a>,
|
||||||
pub desc: &'a str,
|
pub desc: &'a str,
|
||||||
|
|
|
@ -23,7 +23,9 @@ use crate::lints::{
|
||||||
AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
|
AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
|
||||||
AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
|
AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
|
||||||
AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
|
AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
|
||||||
InvalidNanComparisonsSuggestion, UnusedComparisons, VariantSizeDifferencesDiag,
|
InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
|
||||||
|
UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
|
||||||
|
VariantSizeDifferencesDiag,
|
||||||
};
|
};
|
||||||
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
|
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
|
||||||
|
|
||||||
|
@ -166,6 +168,35 @@ declare_lint! {
|
||||||
"detects ambiguous wide pointer comparisons"
|
"detects ambiguous wide pointer comparisons"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `unpredictable_function_pointer_comparisons` lint checks comparison
|
||||||
|
/// of function pointer as the operands.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// fn a() {}
|
||||||
|
/// fn b() {}
|
||||||
|
///
|
||||||
|
/// let f: fn() = a;
|
||||||
|
/// let g: fn() = b;
|
||||||
|
///
|
||||||
|
/// let _ = f == g;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Function pointers comparisons do not produce meaningful result since
|
||||||
|
/// they are never guaranteed to be unique and could vary between different
|
||||||
|
/// code generation units. Furthermore, different functions could have the
|
||||||
|
/// same address after being merged together.
|
||||||
|
UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
|
||||||
|
Warn,
|
||||||
|
"detects unpredictable function pointer comparisons"
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default)]
|
#[derive(Copy, Clone, Default)]
|
||||||
pub(crate) struct TypeLimits {
|
pub(crate) struct TypeLimits {
|
||||||
/// Id of the last visited negated expression
|
/// Id of the last visited negated expression
|
||||||
|
@ -178,7 +209,8 @@ impl_lint_pass!(TypeLimits => [
|
||||||
UNUSED_COMPARISONS,
|
UNUSED_COMPARISONS,
|
||||||
OVERFLOWING_LITERALS,
|
OVERFLOWING_LITERALS,
|
||||||
INVALID_NAN_COMPARISONS,
|
INVALID_NAN_COMPARISONS,
|
||||||
AMBIGUOUS_WIDE_POINTER_COMPARISONS
|
AMBIGUOUS_WIDE_POINTER_COMPARISONS,
|
||||||
|
UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS
|
||||||
]);
|
]);
|
||||||
|
|
||||||
impl TypeLimits {
|
impl TypeLimits {
|
||||||
|
@ -255,7 +287,7 @@ fn lint_nan<'tcx>(
|
||||||
cx.emit_span_lint(INVALID_NAN_COMPARISONS, e.span, lint);
|
cx.emit_span_lint(INVALID_NAN_COMPARISONS, e.span, lint);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
enum ComparisonOp {
|
enum ComparisonOp {
|
||||||
BinOp(hir::BinOpKind),
|
BinOp(hir::BinOpKind),
|
||||||
Other,
|
Other,
|
||||||
|
@ -383,6 +415,100 @@ fn lint_wide_pointer<'tcx>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lint_fn_pointer<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
e: &'tcx hir::Expr<'tcx>,
|
||||||
|
cmpop: ComparisonOp,
|
||||||
|
l: &'tcx hir::Expr<'tcx>,
|
||||||
|
r: &'tcx hir::Expr<'tcx>,
|
||||||
|
) {
|
||||||
|
let peel_refs = |mut ty: Ty<'tcx>| -> (Ty<'tcx>, usize) {
|
||||||
|
let mut refs = 0;
|
||||||
|
|
||||||
|
while let ty::Ref(_, inner_ty, _) = ty.kind() {
|
||||||
|
ty = *inner_ty;
|
||||||
|
refs += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
(ty, refs)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Left and right operands can have borrows, remove them
|
||||||
|
let l = l.peel_borrows();
|
||||||
|
let r = r.peel_borrows();
|
||||||
|
|
||||||
|
let Some(l_ty) = cx.typeck_results().expr_ty_opt(l) else { return };
|
||||||
|
let Some(r_ty) = cx.typeck_results().expr_ty_opt(r) else { return };
|
||||||
|
|
||||||
|
// Remove any references as `==` will deref through them (and count the
|
||||||
|
// number of references removed, for latter).
|
||||||
|
let (l_ty, l_ty_refs) = peel_refs(l_ty);
|
||||||
|
let (r_ty, r_ty_refs) = peel_refs(r_ty);
|
||||||
|
|
||||||
|
if !l_ty.is_fn() || !r_ty.is_fn() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's try to suggest `ptr::fn_addr_eq` if/when possible.
|
||||||
|
|
||||||
|
let is_eq_ne = matches!(cmpop, ComparisonOp::BinOp(hir::BinOpKind::Eq | hir::BinOpKind::Ne));
|
||||||
|
|
||||||
|
if !is_eq_ne {
|
||||||
|
// Neither `==` nor `!=`, we can't suggest `ptr::fn_addr_eq`, just show the warning.
|
||||||
|
return cx.emit_span_lint(
|
||||||
|
UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
|
||||||
|
e.span,
|
||||||
|
UnpredictableFunctionPointerComparisons::Warn,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (Some(l_span), Some(r_span)) =
|
||||||
|
(l.span.find_ancestor_inside(e.span), r.span.find_ancestor_inside(e.span))
|
||||||
|
else {
|
||||||
|
// No appropriate spans for the left and right operands, just show the warning.
|
||||||
|
return cx.emit_span_lint(
|
||||||
|
UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
|
||||||
|
e.span,
|
||||||
|
UnpredictableFunctionPointerComparisons::Warn,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let ne = if cmpop == ComparisonOp::BinOp(hir::BinOpKind::Ne) { "!" } else { "" };
|
||||||
|
|
||||||
|
// `ptr::fn_addr_eq` only works with raw pointer, deref any references.
|
||||||
|
let deref_left = &*"*".repeat(l_ty_refs);
|
||||||
|
let deref_right = &*"*".repeat(r_ty_refs);
|
||||||
|
|
||||||
|
let left = e.span.shrink_to_lo().until(l_span.shrink_to_lo());
|
||||||
|
let middle = l_span.shrink_to_hi().until(r_span.shrink_to_lo());
|
||||||
|
let right = r_span.shrink_to_hi().until(e.span.shrink_to_hi());
|
||||||
|
|
||||||
|
// We only check for a right cast as `FnDef` == `FnPtr` is not possible,
|
||||||
|
// only `FnPtr == FnDef` is possible.
|
||||||
|
let cast_right = if !r_ty.is_fn_ptr() {
|
||||||
|
let fn_sig = r_ty.fn_sig(cx.tcx);
|
||||||
|
format!(" as {fn_sig}")
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
cx.emit_span_lint(
|
||||||
|
UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
|
||||||
|
e.span,
|
||||||
|
UnpredictableFunctionPointerComparisons::Suggestion {
|
||||||
|
sugg: UnpredictableFunctionPointerComparisonsSuggestion {
|
||||||
|
ne,
|
||||||
|
deref_left,
|
||||||
|
deref_right,
|
||||||
|
left,
|
||||||
|
middle,
|
||||||
|
right,
|
||||||
|
cast_right,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for TypeLimits {
|
impl<'tcx> LateLintPass<'tcx> for TypeLimits {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
|
||||||
match e.kind {
|
match e.kind {
|
||||||
|
@ -399,7 +525,9 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
|
||||||
cx.emit_span_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons);
|
cx.emit_span_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons);
|
||||||
} else {
|
} else {
|
||||||
lint_nan(cx, e, binop, l, r);
|
lint_nan(cx, e, binop, l, r);
|
||||||
lint_wide_pointer(cx, e, ComparisonOp::BinOp(binop.node), l, r);
|
let cmpop = ComparisonOp::BinOp(binop.node);
|
||||||
|
lint_wide_pointer(cx, e, cmpop, l, r);
|
||||||
|
lint_fn_pointer(cx, e, cmpop, l, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -411,6 +539,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
|
||||||
&& let Some(cmpop) = diag_item_cmpop(diag_item) =>
|
&& let Some(cmpop) = diag_item_cmpop(diag_item) =>
|
||||||
{
|
{
|
||||||
lint_wide_pointer(cx, e, cmpop, l, r);
|
lint_wide_pointer(cx, e, cmpop, l, r);
|
||||||
|
lint_fn_pointer(cx, e, cmpop, l, r);
|
||||||
}
|
}
|
||||||
hir::ExprKind::MethodCall(_, l, [r], _)
|
hir::ExprKind::MethodCall(_, l, [r], _)
|
||||||
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
|
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
|
||||||
|
@ -418,6 +547,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
|
||||||
&& let Some(cmpop) = diag_item_cmpop(diag_item) =>
|
&& let Some(cmpop) = diag_item_cmpop(diag_item) =>
|
||||||
{
|
{
|
||||||
lint_wide_pointer(cx, e, cmpop, l, r);
|
lint_wide_pointer(cx, e, cmpop, l, r);
|
||||||
|
lint_fn_pointer(cx, e, cmpop, l, r);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
15
tests/ui/lint/fn-ptr-comparisons-weird.rs
Normal file
15
tests/ui/lint/fn-ptr-comparisons-weird.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let f: fn() = main;
|
||||||
|
let g: fn() = main;
|
||||||
|
|
||||||
|
let _ = f > g;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = f >= g;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = f <= g;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = f < g;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
}
|
43
tests/ui/lint/fn-ptr-comparisons-weird.stderr
Normal file
43
tests/ui/lint/fn-ptr-comparisons-weird.stderr
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons-weird.rs:7:13
|
||||||
|
|
|
||||||
|
LL | let _ = f > g;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
= note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons-weird.rs:9:13
|
||||||
|
|
|
||||||
|
LL | let _ = f >= g;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons-weird.rs:11:13
|
||||||
|
|
|
||||||
|
LL | let _ = f <= g;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons-weird.rs:13:13
|
||||||
|
|
|
||||||
|
LL | let _ = f < g;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
|
||||||
|
warning: 4 warnings emitted
|
||||||
|
|
58
tests/ui/lint/fn-ptr-comparisons.fixed
Normal file
58
tests/ui/lint/fn-ptr-comparisons.fixed
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
//@ check-pass
|
||||||
|
//@ run-rustfix
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn test();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a() {}
|
||||||
|
|
||||||
|
extern "C" fn c() {}
|
||||||
|
|
||||||
|
extern "C" fn args(_a: i32) -> i32 { 0 }
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
struct A {
|
||||||
|
f: fn(),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let f: fn() = a;
|
||||||
|
let g: fn() = f;
|
||||||
|
|
||||||
|
let a1 = A { f };
|
||||||
|
let a2 = A { f };
|
||||||
|
|
||||||
|
let _ = std::ptr::fn_addr_eq(f, a as fn());
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = !std::ptr::fn_addr_eq(f, a as fn());
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = std::ptr::fn_addr_eq(f, g);
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = std::ptr::fn_addr_eq(f, f);
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = std::ptr::fn_addr_eq(g, g);
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = std::ptr::fn_addr_eq(g, g);
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = std::ptr::fn_addr_eq(g, g);
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = std::ptr::fn_addr_eq(a as fn(), g);
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
|
||||||
|
let cfn: extern "C" fn() = c;
|
||||||
|
let _ = std::ptr::fn_addr_eq(cfn, c as extern "C" fn());
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
|
||||||
|
let argsfn: extern "C" fn(i32) -> i32 = args;
|
||||||
|
let _ = std::ptr::fn_addr_eq(argsfn, args as extern "C" fn(i32) -> i32);
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
|
||||||
|
let t: unsafe extern "C" fn() = test;
|
||||||
|
let _ = std::ptr::fn_addr_eq(t, test as unsafe extern "C" fn());
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
|
||||||
|
let _ = a1 == a2; // should not warn
|
||||||
|
let _ = std::ptr::fn_addr_eq(a1.f, a2.f);
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
}
|
58
tests/ui/lint/fn-ptr-comparisons.rs
Normal file
58
tests/ui/lint/fn-ptr-comparisons.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
//@ check-pass
|
||||||
|
//@ run-rustfix
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn test();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a() {}
|
||||||
|
|
||||||
|
extern "C" fn c() {}
|
||||||
|
|
||||||
|
extern "C" fn args(_a: i32) -> i32 { 0 }
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
struct A {
|
||||||
|
f: fn(),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let f: fn() = a;
|
||||||
|
let g: fn() = f;
|
||||||
|
|
||||||
|
let a1 = A { f };
|
||||||
|
let a2 = A { f };
|
||||||
|
|
||||||
|
let _ = f == a;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = f != a;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = f == g;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = f == f;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = g == g;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = g == g;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = &g == &g;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
let _ = a as fn() == g;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
|
||||||
|
let cfn: extern "C" fn() = c;
|
||||||
|
let _ = cfn == c;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
|
||||||
|
let argsfn: extern "C" fn(i32) -> i32 = args;
|
||||||
|
let _ = argsfn == args;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
|
||||||
|
let t: unsafe extern "C" fn() = test;
|
||||||
|
let _ = t == test;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
|
||||||
|
let _ = a1 == a2; // should not warn
|
||||||
|
let _ = a1.f == a2.f;
|
||||||
|
//~^ WARN function pointer comparisons
|
||||||
|
}
|
171
tests/ui/lint/fn-ptr-comparisons.stderr
Normal file
171
tests/ui/lint/fn-ptr-comparisons.stderr
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:26:13
|
||||||
|
|
|
||||||
|
LL | let _ = f == a;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
= note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::fn_addr_eq(f, a as fn());
|
||||||
|
| +++++++++++++++++++++ ~ ++++++++
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:28:13
|
||||||
|
|
|
||||||
|
LL | let _ = f != a;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = !std::ptr::fn_addr_eq(f, a as fn());
|
||||||
|
| ++++++++++++++++++++++ ~ ++++++++
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:30:13
|
||||||
|
|
|
||||||
|
LL | let _ = f == g;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::fn_addr_eq(f, g);
|
||||||
|
| +++++++++++++++++++++ ~ +
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:32:13
|
||||||
|
|
|
||||||
|
LL | let _ = f == f;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::fn_addr_eq(f, f);
|
||||||
|
| +++++++++++++++++++++ ~ +
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:34:13
|
||||||
|
|
|
||||||
|
LL | let _ = g == g;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::fn_addr_eq(g, g);
|
||||||
|
| +++++++++++++++++++++ ~ +
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:36:13
|
||||||
|
|
|
||||||
|
LL | let _ = g == g;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::fn_addr_eq(g, g);
|
||||||
|
| +++++++++++++++++++++ ~ +
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:38:13
|
||||||
|
|
|
||||||
|
LL | let _ = &g == &g;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::fn_addr_eq(g, g);
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~ ~ +
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:40:13
|
||||||
|
|
|
||||||
|
LL | let _ = a as fn() == g;
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::fn_addr_eq(a as fn(), g);
|
||||||
|
| +++++++++++++++++++++ ~ +
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:44:13
|
||||||
|
|
|
||||||
|
LL | let _ = cfn == c;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::fn_addr_eq(cfn, c as extern "C" fn());
|
||||||
|
| +++++++++++++++++++++ ~ +++++++++++++++++++
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:48:13
|
||||||
|
|
|
||||||
|
LL | let _ = argsfn == args;
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::fn_addr_eq(argsfn, args as extern "C" fn(i32) -> i32);
|
||||||
|
| +++++++++++++++++++++ ~ +++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:52:13
|
||||||
|
|
|
||||||
|
LL | let _ = t == test;
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::fn_addr_eq(t, test as unsafe extern "C" fn());
|
||||||
|
| +++++++++++++++++++++ ~ ++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||||
|
--> $DIR/fn-ptr-comparisons.rs:56:13
|
||||||
|
|
|
||||||
|
LL | let _ = a1.f == a2.f;
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the address of the same function can vary between different codegen units
|
||||||
|
= note: furthermore, different functions could have the same address after being merged together
|
||||||
|
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||||
|
help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
|
||||||
|
|
|
||||||
|
LL | let _ = std::ptr::fn_addr_eq(a1.f, a2.f);
|
||||||
|
| +++++++++++++++++++++ ~ +
|
||||||
|
|
||||||
|
warning: 12 warnings emitted
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue