Skip to content

Commit 9965ad7

Browse files
committed
Also lint on option of function pointer comparisons
1 parent a4cb3c8 commit 9965ad7

File tree

3 files changed

+50
-2
lines changed

3 files changed

+50
-2
lines changed

compiler/rustc_lint/src/types.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::ops::ControlFlow;
44
use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, Variants, WrappingRange};
55
use rustc_data_structures::fx::FxHashSet;
66
use rustc_errors::DiagMessage;
7-
use rustc_hir::{Expr, ExprKind};
7+
use rustc_hir::{Expr, ExprKind, LangItem};
88
use rustc_middle::bug;
99
use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
1010
use rustc_middle::ty::{
@@ -445,7 +445,25 @@ fn lint_fn_pointer<'tcx>(
445445
let (l_ty, l_ty_refs) = peel_refs(l_ty);
446446
let (r_ty, r_ty_refs) = peel_refs(r_ty);
447447

448-
if !l_ty.is_fn() || !r_ty.is_fn() {
448+
if l_ty.is_fn() && r_ty.is_fn() {
449+
// both operands are function pointers, fallthrough
450+
} else if let ty::Adt(l_def, l_args) = l_ty.kind()
451+
&& let ty::Adt(r_def, r_args) = r_ty.kind()
452+
&& cx.tcx.is_lang_item(l_def.did(), LangItem::Option)
453+
&& cx.tcx.is_lang_item(r_def.did(), LangItem::Option)
454+
&& let Some(l_some_arg) = l_args.get(0)
455+
&& let Some(r_some_arg) = r_args.get(0)
456+
&& l_some_arg.expect_ty().is_fn()
457+
&& r_some_arg.expect_ty().is_fn()
458+
{
459+
// both operands are `Option<{function ptr}>`
460+
return cx.emit_span_lint(
461+
UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
462+
e.span,
463+
UnpredictableFunctionPointerComparisons::Warn,
464+
);
465+
} else {
466+
// types are not function pointers, nothing to do
449467
return;
450468
}
451469

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// This test checks that we lint on Option of fn ptr.
2+
//
3+
// https://github.com/rust-lang/rust/issues/134527.
4+
//
5+
//@ check-pass
6+
7+
unsafe extern "C" fn func() {}
8+
9+
type FnPtr = unsafe extern "C" fn();
10+
11+
fn main() {
12+
let _ = Some::<FnPtr>(func) == Some(func as unsafe extern "C" fn());
13+
//~^ WARN function pointer comparisons
14+
15+
// Undecided as of https://github.com/rust-lang/rust/pull/134536
16+
assert_eq!(Some::<FnPtr>(func), Some(func as unsafe extern "C" fn()));
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
2+
--> $DIR/fn-ptr-comparisons-some.rs:12:13
3+
|
4+
LL | let _ = Some::<FnPtr>(func) == Some(func as unsafe extern "C" fn());
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: the address of the same function can vary between different codegen units
8+
= note: furthermore, different functions could have the same address after being merged together
9+
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
10+
= note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default
11+
12+
warning: 1 warning emitted
13+

0 commit comments

Comments
 (0)