Skip to content

Commit 4120076

Browse files
committed
Add warn-by-default lint against unpredictable fn pointer comparisons
1 parent 8a37655 commit 4120076

File tree

5 files changed

+158
-2
lines changed

5 files changed

+158
-2
lines changed

compiler/rustc_lint/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,9 @@ lint_unknown_lint =
538538
lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
539539
.help = add `#![register_tool({$tool_name})]` to the crate root
540540
541+
lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
542+
.note = even foreign function pointers are not guaranteed to be unique and could vary between different code generation units
543+
541544
lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
542545
543546
lint_untranslatable_diag = diagnostics should be created using translatable messages

compiler/rustc_lint/src/lints.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1644,6 +1644,11 @@ pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
16441644
},
16451645
}
16461646

1647+
#[derive(LintDiagnostic)]
1648+
#[diag(lint_unpredictable_fn_pointer_comparisons)]
1649+
#[note]
1650+
pub struct UnpredictableFunctionPointerComparisons;
1651+
16471652
pub struct ImproperCTypes<'a> {
16481653
pub ty: Ty<'a>,
16491654
pub desc: &'a str,

compiler/rustc_lint/src/types.rs

+57-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use crate::{
77
InvalidNanComparisonsSuggestion, OnlyCastu8ToChar, OverflowingBinHex,
88
OverflowingBinHexSign, OverflowingBinHexSignBitSub, OverflowingBinHexSub, OverflowingInt,
99
OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, RangeEndpointOutOfRange,
10-
UnusedComparisons, UseInclusiveRange, VariantSizeDifferencesDiag,
10+
UnpredictableFunctionPointerComparisons, UnusedComparisons, UseInclusiveRange,
11+
VariantSizeDifferencesDiag,
1112
},
1213
};
1314
use crate::{LateContext, LateLintPass, LintContext};
@@ -169,6 +170,32 @@ declare_lint! {
169170
"detects ambiguous wide pointer comparisons"
170171
}
171172

173+
declare_lint! {
174+
/// The `unpredictable_function_pointer_comparisons` lint checks comparison
175+
/// of function pointer as the operands.
176+
///
177+
/// ### Example
178+
///
179+
/// ```rust
180+
/// fn foo() {}
181+
/// # let a = foo as fn();
182+
///
183+
/// let _ = a == foo;
184+
/// ```
185+
///
186+
/// {{produces}}
187+
///
188+
/// ### Explanation
189+
///
190+
/// Function pointers comparisons do not produce meaningful result since
191+
/// they are never guaranteed to be unique and could vary between different
192+
/// code generation units. Furthermore different function could have the
193+
/// same address after being merged together.
194+
UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
195+
Warn,
196+
"detects unpredictable function pointer comparisons"
197+
}
198+
172199
#[derive(Copy, Clone)]
173200
pub struct TypeLimits {
174201
/// Id of the last visited negated expression
@@ -181,7 +208,8 @@ impl_lint_pass!(TypeLimits => [
181208
UNUSED_COMPARISONS,
182209
OVERFLOWING_LITERALS,
183210
INVALID_NAN_COMPARISONS,
184-
AMBIGUOUS_WIDE_POINTER_COMPARISONS
211+
AMBIGUOUS_WIDE_POINTER_COMPARISONS,
212+
UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS
185213
]);
186214

187215
impl TypeLimits {
@@ -758,6 +786,30 @@ fn lint_wide_pointer<'tcx>(
758786
);
759787
}
760788

789+
fn lint_fn_pointer<'tcx>(
790+
cx: &LateContext<'tcx>,
791+
e: &'tcx hir::Expr<'tcx>,
792+
_binop: hir::BinOpKind,
793+
l: &'tcx hir::Expr<'tcx>,
794+
r: &'tcx hir::Expr<'tcx>,
795+
) {
796+
let Some(l_ty) = cx.typeck_results().expr_ty_opt(l) else { return };
797+
let Some(r_ty) = cx.typeck_results().expr_ty_opt(r) else { return };
798+
799+
let l_ty = l_ty.peel_refs();
800+
let r_ty = r_ty.peel_refs();
801+
802+
if !l_ty.is_fn() || !r_ty.is_fn() {
803+
return;
804+
}
805+
806+
cx.emit_spanned_lint(
807+
UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
808+
e.span,
809+
UnpredictableFunctionPointerComparisons,
810+
);
811+
}
812+
761813
impl<'tcx> LateLintPass<'tcx> for TypeLimits {
762814
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
763815
match e.kind {
@@ -775,6 +827,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
775827
} else {
776828
lint_nan(cx, e, binop, l, r);
777829
lint_wide_pointer(cx, e, binop.node, l, r);
830+
lint_fn_pointer(cx, e, binop.node, l, r);
778831
}
779832
}
780833
}
@@ -786,13 +839,15 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
786839
&& let Some(binop) = partialeq_binop(diag_item) =>
787840
{
788841
lint_wide_pointer(cx, e, binop, l, r);
842+
lint_fn_pointer(cx, e, binop, l, r);
789843
}
790844
hir::ExprKind::MethodCall(_, l, [r], _)
791845
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
792846
&& let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
793847
&& let Some(binop) = partialeq_binop(diag_item) =>
794848
{
795849
lint_wide_pointer(cx, e, binop, l, r);
850+
lint_fn_pointer(cx, e, binop, l, r);
796851
}
797852
_ => {}
798853
};

tests/ui/lint/fn-ptr-comparisons.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// check-pass
2+
3+
extern "C" {
4+
fn test();
5+
}
6+
7+
fn a() {}
8+
9+
extern "C" fn c() {}
10+
11+
fn main() {
12+
type F = fn();
13+
let f: F = a;
14+
let g: F = f;
15+
16+
let _ = f == a;
17+
//~^ WARN function pointer comparisons
18+
let _ = f != a;
19+
//~^ WARN function pointer comparisons
20+
let _ = f == g;
21+
//~^ WARN function pointer comparisons
22+
let _ = f == f;
23+
//~^ WARN function pointer comparisons
24+
let _ = g == g;
25+
//~^ WARN function pointer comparisons
26+
27+
let cfn: extern "C" fn() = c;
28+
let _ = cfn == c;
29+
//~^ WARN function pointer comparisons
30+
31+
let t: unsafe extern "C" fn() = test;
32+
let _ = t == test;
33+
//~^ WARN function pointer comparisons
34+
}
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
2+
--> $DIR/fn-ptr-comparisons.rs:16:13
3+
|
4+
LL | let _ = f == a;
5+
| ^^^^^^
6+
|
7+
= note: even foreign function pointers are not guaranteed to be unique and could vary between different code generation units
8+
= note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default
9+
10+
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
11+
--> $DIR/fn-ptr-comparisons.rs:18:13
12+
|
13+
LL | let _ = f != a;
14+
| ^^^^^^
15+
|
16+
= note: even foreign function pointers are not guaranteed to be unique and could vary between different code generation units
17+
18+
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
19+
--> $DIR/fn-ptr-comparisons.rs:20:13
20+
|
21+
LL | let _ = f == g;
22+
| ^^^^^^
23+
|
24+
= note: even foreign function pointers are not guaranteed to be unique and could vary between different code generation units
25+
26+
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
27+
--> $DIR/fn-ptr-comparisons.rs:22:13
28+
|
29+
LL | let _ = f == f;
30+
| ^^^^^^
31+
|
32+
= note: even foreign function pointers are not guaranteed to be unique and could vary between different code generation units
33+
34+
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
35+
--> $DIR/fn-ptr-comparisons.rs:24:13
36+
|
37+
LL | let _ = g == g;
38+
| ^^^^^^
39+
|
40+
= note: even foreign function pointers are not guaranteed to be unique and could vary between different code generation units
41+
42+
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
43+
--> $DIR/fn-ptr-comparisons.rs:28:13
44+
|
45+
LL | let _ = cfn == c;
46+
| ^^^^^^^^
47+
|
48+
= note: even foreign function pointers are not guaranteed to be unique and could vary between different code generation units
49+
50+
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
51+
--> $DIR/fn-ptr-comparisons.rs:32:13
52+
|
53+
LL | let _ = t == test;
54+
| ^^^^^^^^^
55+
|
56+
= note: even foreign function pointers are not guaranteed to be unique and could vary between different code generation units
57+
58+
warning: 7 warnings emitted
59+

0 commit comments

Comments
 (0)