Skip to content

Commit 48f464b

Browse files
Add new function_casts_as_integer lint
1 parent d00435f commit 48f464b

File tree

5 files changed

+90
-1
lines changed

5 files changed

+90
-1
lines changed

compiler/rustc_lint/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,9 @@ lint_forgetting_copy_types = calls to `std::mem::forget` with a value that imple
285285
lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing
286286
.label = argument has type `{$arg_ty}`
287287
288+
lint_function_casts_as_integer = direct cast of function item into an integer
289+
.cast_as_fn = first cast to a function pointer `{$cast_from_ty}`
290+
288291
lint_hidden_glob_reexport = private item shadows public glob re-export
289292
.note_glob_reexport = the name `{$name}` in the {$namespace} namespace is supposed to be publicly re-exported here
290293
.note_private_item = but the private item here shadows it
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use rustc_hir as hir;
2+
use rustc_middle::ty;
3+
use rustc_session::{declare_lint, declare_lint_pass};
4+
use rustc_span::BytePos;
5+
6+
use crate::lints::{FunctionCastsAsIntegerDiag, FunctionCastsAsIntegerSugg};
7+
use crate::{LateContext, LateLintPass};
8+
9+
declare_lint! {
10+
/// The `function_casts_as_integer` lint detects cases where a function item is casted
11+
/// into an integer.
12+
///
13+
/// ### Example
14+
///
15+
/// ```rust
16+
/// fn foo() {}
17+
/// let x = foo as usize;
18+
/// ```
19+
///
20+
/// {{produces}}
21+
///
22+
/// ### Explanation
23+
///
24+
/// When casting a function item into an integer, it's implicitly creating a
25+
/// function pointer that will in turn be casted into an integer. By making
26+
/// it explicit, it improves readability of the code and prevents bugs.
27+
pub FUNCTION_CASTS_AS_INTEGER,
28+
Warn,
29+
"casting a function into an integer",
30+
}
31+
32+
declare_lint_pass!(
33+
/// Lint for casts of functions into integers.
34+
FunctionCastsAsInteger => [FUNCTION_CASTS_AS_INTEGER]
35+
);
36+
37+
impl<'tcx> LateLintPass<'tcx> for FunctionCastsAsInteger {
38+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
39+
let hir::ExprKind::Cast(cast_from_expr, cast_to_expr) = expr.kind else { return };
40+
let cast_to_ty = cx.typeck_results().expr_ty(expr);
41+
// Casting to a function (pointer?), so all good.
42+
if matches!(cast_to_ty.kind(), ty::FnDef(..) | ty::FnPtr(..)) {
43+
return;
44+
}
45+
let cast_from_ty = cx.typeck_results().expr_ty(cast_from_expr);
46+
if matches!(cast_from_ty.kind(), ty::FnDef(..)) {
47+
cx.tcx.emit_node_span_lint(
48+
FUNCTION_CASTS_AS_INTEGER,
49+
expr.hir_id,
50+
cast_to_expr.span.with_lo(cast_from_expr.span.hi() + BytePos(1)),
51+
FunctionCastsAsIntegerDiag {
52+
sugg: FunctionCastsAsIntegerSugg {
53+
suggestion: cast_from_expr.span.shrink_to_hi(),
54+
// We get the function pointer to have a nice display.
55+
cast_from_ty: cx.typeck_results().expr_ty_adjusted(cast_from_expr),
56+
cast_to_ty,
57+
},
58+
},
59+
);
60+
}
61+
}
62+
}

compiler/rustc_lint/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ mod errors;
4848
mod expect;
4949
mod for_loops_over_fallibles;
5050
mod foreign_modules;
51+
mod function_cast_as_integer;
5152
mod if_let_rescope;
5253
mod impl_trait_overcaptures;
5354
mod internal;
@@ -92,6 +93,7 @@ use deref_into_dyn_supertrait::*;
9293
use drop_forget_useless::*;
9394
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
9495
use for_loops_over_fallibles::*;
96+
use function_cast_as_integer::*;
9597
use if_let_rescope::IfLetRescope;
9698
use impl_trait_overcaptures::ImplTraitOvercaptures;
9799
use internal::*;
@@ -247,6 +249,7 @@ late_lint_methods!(
247249
IfLetRescope: IfLetRescope::default(),
248250
StaticMutRefs: StaticMutRefs,
249251
UnqualifiedLocalImports: UnqualifiedLocalImports,
252+
FunctionCastsAsInteger: FunctionCastsAsInteger,
250253
CheckTransmutes: CheckTransmutes,
251254
LifetimeSyntax: LifetimeSyntax,
252255
]

compiler/rustc_lint/src/lints.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3190,6 +3190,27 @@ pub(crate) struct ReservedMultihash {
31903190
pub suggestion: Span,
31913191
}
31923192

3193+
#[derive(LintDiagnostic)]
3194+
#[diag(lint_function_casts_as_integer)]
3195+
pub(crate) struct FunctionCastsAsIntegerDiag<'tcx> {
3196+
#[subdiagnostic]
3197+
pub(crate) sugg: FunctionCastsAsIntegerSugg<'tcx>,
3198+
}
3199+
3200+
#[derive(Subdiagnostic)]
3201+
#[suggestion(
3202+
lint_cast_as_fn,
3203+
code = " as {cast_from_ty}",
3204+
applicability = "machine-applicable",
3205+
style = "verbose"
3206+
)]
3207+
pub(crate) struct FunctionCastsAsIntegerSugg<'tcx> {
3208+
#[primary_span]
3209+
pub suggestion: Span,
3210+
pub cast_from_ty: Ty<'tcx>,
3211+
pub cast_to_ty: Ty<'tcx>,
3212+
}
3213+
31933214
#[derive(Debug)]
31943215
pub(crate) struct MismatchedLifetimeSyntaxes {
31953216
pub lifetime_name: String,

compiler/rustc_session/src/filesearch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
7373

7474
#[cfg(not(target_os = "aix"))]
7575
unsafe {
76-
let addr = current_dll_path as usize as *mut _;
76+
let addr = current_dll_path as fn() -> Result<PathBuf, String> as *mut _;
7777
let mut info = std::mem::zeroed();
7878
if libc::dladdr(addr, &mut info) == 0 {
7979
return Err("dladdr failed".into());

0 commit comments

Comments
 (0)