From 9965ad76201dec64cbc83e925ee8005c275461e8 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 19 Dec 2024 21:59:37 +0100 Subject: [PATCH] Also lint on option of function pointer comparisons --- compiler/rustc_lint/src/types.rs | 22 ++++++++++++++++++-- tests/ui/lint/fn-ptr-comparisons-some.rs | 17 +++++++++++++++ tests/ui/lint/fn-ptr-comparisons-some.stderr | 13 ++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 tests/ui/lint/fn-ptr-comparisons-some.rs create mode 100644 tests/ui/lint/fn-ptr-comparisons-some.stderr diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 33d31d27c738f..b9f0d778e3596 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -4,7 +4,7 @@ use std::ops::ControlFlow; use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, Variants, WrappingRange}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton}; use rustc_middle::ty::{ @@ -445,7 +445,25 @@ fn lint_fn_pointer<'tcx>( 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() { + if l_ty.is_fn() && r_ty.is_fn() { + // both operands are function pointers, fallthrough + } else if let ty::Adt(l_def, l_args) = l_ty.kind() + && let ty::Adt(r_def, r_args) = r_ty.kind() + && cx.tcx.is_lang_item(l_def.did(), LangItem::Option) + && cx.tcx.is_lang_item(r_def.did(), LangItem::Option) + && let Some(l_some_arg) = l_args.get(0) + && let Some(r_some_arg) = r_args.get(0) + && l_some_arg.expect_ty().is_fn() + && r_some_arg.expect_ty().is_fn() + { + // both operands are `Option<{function ptr}>` + return cx.emit_span_lint( + UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS, + e.span, + UnpredictableFunctionPointerComparisons::Warn, + ); + } else { + // types are not function pointers, nothing to do return; } diff --git a/tests/ui/lint/fn-ptr-comparisons-some.rs b/tests/ui/lint/fn-ptr-comparisons-some.rs new file mode 100644 index 0000000000000..152e16b9884ba --- /dev/null +++ b/tests/ui/lint/fn-ptr-comparisons-some.rs @@ -0,0 +1,17 @@ +// This test checks that we lint on Option of fn ptr. +// +// https://github.com/rust-lang/rust/issues/134527. +// +//@ check-pass + +unsafe extern "C" fn func() {} + +type FnPtr = unsafe extern "C" fn(); + +fn main() { + let _ = Some::(func) == Some(func as unsafe extern "C" fn()); + //~^ WARN function pointer comparisons + + // Undecided as of https://github.com/rust-lang/rust/pull/134536 + assert_eq!(Some::(func), Some(func as unsafe extern "C" fn())); +} diff --git a/tests/ui/lint/fn-ptr-comparisons-some.stderr b/tests/ui/lint/fn-ptr-comparisons-some.stderr new file mode 100644 index 0000000000000..eefad05b676de --- /dev/null +++ b/tests/ui/lint/fn-ptr-comparisons-some.stderr @@ -0,0 +1,13 @@ +warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique + --> $DIR/fn-ptr-comparisons-some.rs:12:13 + | +LL | let _ = Some::(func) == Some(func as unsafe extern "C" fn()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 + = note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default + +warning: 1 warning emitted +