From 746e4eff263527ba8960552ea62db11ab9821644 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 12 Mar 2024 07:00:01 +0000 Subject: [PATCH] Test and implement reachability for trait objects and generic parameters of functions --- Cargo.lock | 1 + compiler/rustc_passes/Cargo.toml | 1 + compiler/rustc_passes/src/reachable.rs | 35 ++++++++++++++++--- compiler/rustc_privacy/src/lib.rs | 4 +-- .../cross-crate/auxiliary/static_init_aux.rs | 21 +++++++++++ tests/ui/cross-crate/static-init.rs | 4 +++ 6 files changed, 60 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16aed3dc49c..94e2570ebaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4400,6 +4400,7 @@ dependencies = [ "rustc_lexer", "rustc_macros", "rustc_middle", + "rustc_privacy", "rustc_session", "rustc_span", "rustc_target", diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index 6abfa08c530..b45a8dae277 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -18,6 +18,7 @@ rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } +rustc_privacy = { path = "../rustc_privacy" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 0dd3185fc83..718c2345397 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -16,7 +16,8 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs} use rustc_middle::middle::privacy::{self, Level}; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc}; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, ExistentialTraitRef, TyCtxt}; +use rustc_privacy::DefIdVisitor; use rustc_session::config::CrateType; use rustc_target::spec::abi::Abi; @@ -272,13 +273,22 @@ impl<'tcx> ReachableContext<'tcx> { self.propagate_item(Res::Def(self.tcx.def_kind(def_id), def_id)) } GlobalAlloc::Function(instance) => { + // Manually visit to actually see the instance's `DefId`. Type visitors won't see it self.propagate_item(Res::Def( self.tcx.def_kind(instance.def_id()), instance.def_id(), - )) - // TODO: walk generic args + )); + self.visit(instance.args); + } + GlobalAlloc::VTable(ty, trait_ref) => { + self.visit(ty); + // Manually visit to actually see the trait's `DefId`. Type visitors won't see it + if let Some(trait_ref) = trait_ref { + let ExistentialTraitRef { def_id, args } = trait_ref.skip_binder(); + self.visit_def_id(def_id, "", &""); + self.visit(args); + } } - GlobalAlloc::VTable(ty, trait_ref) => todo!("{ty:?}, {trait_ref:?}"), GlobalAlloc::Memory(alloc) => self.propagate_from_alloc(alloc), } } @@ -318,6 +328,23 @@ impl<'tcx> ReachableContext<'tcx> { } } +impl<'tcx> DefIdVisitor<'tcx> for ReachableContext<'tcx> { + type Result = (); + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_def_id( + &mut self, + def_id: DefId, + _kind: &str, + _descr: &dyn std::fmt::Display, + ) -> Self::Result { + self.propagate_item(Res::Def(self.tcx.def_kind(def_id), def_id)) + } +} + fn check_item<'tcx>( tcx: TyCtxt<'tcx>, id: hir::ItemId, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9f8cb8fcb41..073982ca5c3 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -67,7 +67,7 @@ impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> { /// First, it doesn't have overridable `fn visit_trait_ref`, so we have to catch trait `DefId`s /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits /// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`. -trait DefIdVisitor<'tcx> { +pub trait DefIdVisitor<'tcx> { type Result: VisitorResult = (); const SHALLOW: bool = false; const SKIP_ASSOC_TYS: bool = false; @@ -98,7 +98,7 @@ trait DefIdVisitor<'tcx> { } } -struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> { +pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> { def_id_visitor: &'v mut V, visited_opaque_tys: FxHashSet, dummy: PhantomData>, diff --git a/tests/ui/cross-crate/auxiliary/static_init_aux.rs b/tests/ui/cross-crate/auxiliary/static_init_aux.rs index 5e172ef3198..dca708733b9 100644 --- a/tests/ui/cross-crate/auxiliary/static_init_aux.rs +++ b/tests/ui/cross-crate/auxiliary/static_init_aux.rs @@ -1,6 +1,8 @@ pub static V: &u32 = &X; pub static F: fn() = f; pub static G: fn() = G0; +pub static H: &(dyn Fn() + Sync) = &h; +pub static I: fn() = Helper(j).mk(); static X: u32 = 42; static G0: fn() = g; @@ -12,3 +14,22 @@ pub fn v() -> *const u32 { fn f() {} fn g() {} + +fn h() {} + +#[derive(Copy, Clone)] +struct Helper(T); + +impl Helper { + const fn mk(self) -> fn() { + i:: + } +} + +fn i() { + assert_eq!(std::mem::size_of::(), 0); + // unsafe to work around the lack of a `Default` impl for function items + unsafe { (std::mem::transmute_copy::<(), T>(&()))() } +} + +fn j() {} diff --git a/tests/ui/cross-crate/static-init.rs b/tests/ui/cross-crate/static-init.rs index 090ad5f810e..c4697a1d010 100644 --- a/tests/ui/cross-crate/static-init.rs +++ b/tests/ui/cross-crate/static-init.rs @@ -6,6 +6,8 @@ extern crate static_init_aux as aux; static V: &u32 = aux::V; static F: fn() = aux::F; static G: fn() = aux::G; +static H: &(dyn Fn() + Sync) = aux::H; +static I: fn() = aux::I; fn v() -> *const u32 { V @@ -15,4 +17,6 @@ fn main() { assert_eq!(aux::v(), crate::v()); F(); G(); + H(); + I(); }