From 5e9dca942e3199372459d3d9f043aa53b31df518 Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Fri, 25 Sep 2026 17:52:52 +0000 Subject: [PATCH 1/3] cache results in improper_ctypes lint --- .../rustc_lint/src/types/improper_ctypes.rs | 57 ++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index e7fa0fe2960db..2d42e9fdd05da 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -1,3 +1,4 @@ +use std::cell::RefCell; use std::iter; use std::ops::ControlFlow; @@ -5,10 +6,11 @@ use bitflags::bitflags; use rustc_abi::VariantIdx; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{DiagMessage, msg}; +use rustc_hashes::Hash128; use rustc_hir::def::CtorKind; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, AmbigArg}; -use rustc_lint_defs::{declare_lint, declare_lint_pass}; +use rustc_lint_defs::{declare_lint, impl_lint_pass}; use rustc_middle::ty::{ self, Adt, AdtDef, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, Unnormalized, @@ -131,7 +133,25 @@ declare_lint! { "Structs do not follow the power alignment rule under repr(C)" } -declare_lint_pass!(ImproperCTypesLint => [ +/// Remembers types we already checked and found FFI-safe, so we don't check the +/// same type again every time it shows up in another function. +/// We only remember "safe" types, never "unsafe" ones. That way we never need to +/// keep the actual type around, just a fingerprint of it. +#[derive(Default)] +pub(crate) struct ImproperCTypesLint { + /// A fingerprint of the type, not the type itself. Uses a big 128-bit + /// fingerprint (not a smaller 64-bit one) so two different types can't + /// accidentally get treated as the same one. + known_safe: RefCell>, +} + +impl<'tcx> ImproperCTypesLint { + fn cache_key(cx: &LateContext<'tcx>, ty: Ty<'tcx>, flags: RootUseFlags) -> (Hash128, u8) { + (cx.tcx.type_id_hash(ty), flags.bits()) + } +} + +impl_lint_pass!(ImproperCTypesLint => [ IMPROPER_CTYPES, IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT @@ -1102,8 +1122,16 @@ impl<'tcx> ImproperCTypesLint { fn check_foreign_static(&mut self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) { let ty = cx.tcx.type_of(id).instantiate_identity(); + let state = VisitorState::static_entry_point(); + let key = Self::cache_key(cx, ty.skip_norm_wip(), state.root_use_flags); + if self.known_safe.borrow().contains(&key) { + return; + } let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration); - let ffi_res = visitor.check_type(VisitorState::static_entry_point(), ty); + let ffi_res = visitor.check_type(state, ty); + if matches!(ffi_res, FfiResult::FfiSafe) { + self.known_safe.borrow_mut().insert(key); + } self.process_ffi_result(cx, span, ffi_res, CItemKind::Declaration); } @@ -1119,19 +1147,32 @@ impl<'tcx> ImproperCTypesLint { let sig = cx.tcx.instantiate_bound_regions_with_erased(sig); for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { - let input_ty = Unnormalized::new_wip(*input_ty); let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg); + let key = Self::cache_key(cx, *input_ty, state.root_use_flags); + if self.known_safe.borrow().contains(&key) { + continue; + } + let input_ty = Unnormalized::new_wip(*input_ty); let mut visitor = ImproperCTypesVisitor::new(cx, input_ty, fn_mode); let ffi_res = visitor.check_type(state, input_ty); + if matches!(ffi_res, FfiResult::FfiSafe) { + self.known_safe.borrow_mut().insert(key); + } self.process_ffi_result(cx, input_hir.span, ffi_res, fn_mode); } if let hir::FnRetTy::Return(ret_hir) = decl.output { - let output_ty = Unnormalized::new_wip(sig.output()); let state = VisitorState::fn_entry_point(fn_mode, FnPos::Ret); - let mut visitor = ImproperCTypesVisitor::new(cx, output_ty, fn_mode); - let ffi_res = visitor.check_type(state, output_ty); - self.process_ffi_result(cx, ret_hir.span, ffi_res, fn_mode); + let key = Self::cache_key(cx, sig.output(), state.root_use_flags); + if !self.known_safe.borrow().contains(&key) { + let output_ty = Unnormalized::new_wip(sig.output()); + let mut visitor = ImproperCTypesVisitor::new(cx, output_ty, fn_mode); + let ffi_res = visitor.check_type(state, output_ty); + if matches!(ffi_res, FfiResult::FfiSafe) { + self.known_safe.borrow_mut().insert(key); + } + self.process_ffi_result(cx, ret_hir.span, ffi_res, fn_mode); + } } } From fa3bfde261f62d8a8acb3dd0da2133ca0e92164d Mon Sep 17 00:00:00 2001 From: xonx4l Date: Thu, 1 Oct 2026 16:44:49 +0530 Subject: [PATCH 2/3] fix build errors --- Cargo.lock | 1 + compiler/rustc_lint/Cargo.toml | 1 + compiler/rustc_lint/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 5e57835c9cfef..5183eb88a437f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4334,6 +4334,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_feature", + "rustc_hashes", "rustc_hir", "rustc_index", "rustc_infer", diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index a672f242449e4..5fc0b333eccad 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -14,6 +14,7 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_hashes = { path = "../rustc_hashes" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 95033707cf110..9a91e14fbdcb0 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -238,7 +238,7 @@ late_lint_methods!( ImplTraitOvercaptures: ImplTraitOvercaptures, ImplicitAutorefs: ImplicitAutorefs, ImplicitProvenanceCasts: ImplicitProvenanceCasts, - ImproperCTypesLint: ImproperCTypesLint, + ImproperCTypesLint: ImproperCTypesLint::default(), ImproperGpuKernelLint: ImproperGpuKernelLint, InteriorMutableConsts: InteriorMutableConsts, InternalEqTraitMethodImpls: InternalEqTraitMethodImpls, From 54a6d2e4c750c76885dc444ec5eb97a30e85a695 Mon Sep 17 00:00:00 2001 From: xonx4l Date: Mon, 5 Oct 2026 23:29:44 +0530 Subject: [PATCH 3/3] factor out as check_ffi_type method --- .../rustc_lint/src/types/improper_ctypes.rs | 64 ++++++++++--------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 2d42e9fdd05da..04b381261e428 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -149,6 +149,29 @@ impl<'tcx> ImproperCTypesLint { fn cache_key(cx: &LateContext<'tcx>, ty: Ty<'tcx>, flags: RootUseFlags) -> (Hash128, u8) { (cx.tcx.type_id_hash(ty), flags.bits()) } + + fn check_ffi_type( + &self, + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + state: VisitorState, + span: Span, + mode: CItemKind, + check: impl FnOnce() -> FfiResult<'tcx>, + ) { + let key = Self::cache_key(cx, ty, state.root_use_flags); + if self.known_safe.borrow().contains(&key) { + return; + } + + let ffi_res = check(); + + if matches!(ffi_res, FfiResult::FfiSafe) { + self.known_safe.borrow_mut().insert(key); + } + + self.process_ffi_result(cx, span, ffi_res, mode); + } } impl_lint_pass!(ImproperCTypesLint => [ @@ -1123,16 +1146,10 @@ impl<'tcx> ImproperCTypesLint { fn check_foreign_static(&mut self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) { let ty = cx.tcx.type_of(id).instantiate_identity(); let state = VisitorState::static_entry_point(); - let key = Self::cache_key(cx, ty.skip_norm_wip(), state.root_use_flags); - if self.known_safe.borrow().contains(&key) { - return; - } - let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration); - let ffi_res = visitor.check_type(state, ty); - if matches!(ffi_res, FfiResult::FfiSafe) { - self.known_safe.borrow_mut().insert(key); - } - self.process_ffi_result(cx, span, ffi_res, CItemKind::Declaration); + self.check_ffi_type(cx, ty.skip_norm_wip(), state, span, CItemKind::Declaration, || { + let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration); + visitor.check_type(state, ty) + }); } /// Check if a function's argument types and result type are "ffi-safe". @@ -1148,31 +1165,20 @@ impl<'tcx> ImproperCTypesLint { for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg); - let key = Self::cache_key(cx, *input_ty, state.root_use_flags); - if self.known_safe.borrow().contains(&key) { - continue; - } - let input_ty = Unnormalized::new_wip(*input_ty); - let mut visitor = ImproperCTypesVisitor::new(cx, input_ty, fn_mode); - let ffi_res = visitor.check_type(state, input_ty); - if matches!(ffi_res, FfiResult::FfiSafe) { - self.known_safe.borrow_mut().insert(key); - } - self.process_ffi_result(cx, input_hir.span, ffi_res, fn_mode); + self.check_ffi_type(cx, *input_ty, state, input_hir.span, fn_mode, || { + let input_ty = Unnormalized::new_wip(*input_ty); + let mut visitor = ImproperCTypesVisitor::new(cx, input_ty, fn_mode); + visitor.check_type(state, input_ty) + }); } if let hir::FnRetTy::Return(ret_hir) = decl.output { let state = VisitorState::fn_entry_point(fn_mode, FnPos::Ret); - let key = Self::cache_key(cx, sig.output(), state.root_use_flags); - if !self.known_safe.borrow().contains(&key) { + self.check_ffi_type(cx, sig.output(), state, ret_hir.span, fn_mode, || { let output_ty = Unnormalized::new_wip(sig.output()); let mut visitor = ImproperCTypesVisitor::new(cx, output_ty, fn_mode); - let ffi_res = visitor.check_type(state, output_ty); - if matches!(ffi_res, FfiResult::FfiSafe) { - self.known_safe.borrow_mut().insert(key); - } - self.process_ffi_result(cx, ret_hir.span, ffi_res, fn_mode); - } + visitor.check_type(state, output_ty) + }); } }