From 2a976af03d8799885b97728f05c69a4555db8676 Mon Sep 17 00:00:00 2001 From: sgasho Date: Tue, 5 May 2026 22:44:39 +0900 Subject: [PATCH] Avoid deriving bounds from FnPtr --- .../src/deriving/generic/mod.rs | 12 ++---- ...n-pointer-with-placeholder-lifetime-run.rs | 39 +++++++++++++++++++ ...ne-fn-pointer-with-placeholder-lifetime.rs | 16 ++++++++ ...ed-fn-pointer-with-placeholder-lifetime.rs | 16 ++++++++ 4 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 tests/ui/derives/derive-clone-fn-pointer-with-placeholder-lifetime-run.rs create mode 100644 tests/ui/derives/derive-clone-fn-pointer-with-placeholder-lifetime.rs create mode 100644 tests/ui/derives/derive-clone-nested-fn-pointer-with-placeholder-lifetime.rs diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index ace4048af26c1..585f67aa65745 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -422,13 +422,10 @@ fn find_type_parameters( impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { fn visit_ty(&mut self, ty: &'a ast::Ty) { - let stack_len = self.bound_generic_params_stack.len(); - if let ast::TyKind::FnPtr(fn_ptr) = &ty.kind - && !fn_ptr.generic_params.is_empty() - { - // Given a field `x: for<'a> fn(T::SomeType<'a>)`, we wan't to account for `'a` so - // that we generate `where for<'a> T::SomeType<'a>: ::core::clone::Clone`. #122622 - self.bound_generic_params_stack.extend(fn_ptr.generic_params.iter().cloned()); + // Cloning a function pointer copies the pointer value and never clones values + // of the input or output types, so they should not contribute derived bounds. + if let ast::TyKind::FnPtr(_) = &ty.kind { + return; } if let ast::TyKind::Path(_, path) = &ty.kind @@ -442,7 +439,6 @@ fn find_type_parameters( } visit::walk_ty(self, ty); - self.bound_generic_params_stack.truncate(stack_len); } // Place bound generic params on a stack, to extract them when a type is encountered. diff --git a/tests/ui/derives/derive-clone-fn-pointer-with-placeholder-lifetime-run.rs b/tests/ui/derives/derive-clone-fn-pointer-with-placeholder-lifetime-run.rs new file mode 100644 index 0000000000000..d58a9831de39f --- /dev/null +++ b/tests/ui/derives/derive-clone-fn-pointer-with-placeholder-lifetime-run.rs @@ -0,0 +1,39 @@ +//@ run-pass +// Cloned function pointer fields works fine even when the function's +// input type is not Clone. + +#![allow(dead_code)] + +trait SomeTrait { + type SomeType<'a>; +} + +#[derive(Clone)] +struct Concrete; + +struct NotClone<'a> { + value: &'a u32, +} + +impl SomeTrait for Concrete { + type SomeType<'a> = NotClone<'a>; +} + +fn read_value(x: NotClone<'_>) -> u32 { + *x.value +} + +#[derive(Clone)] +struct Foo { + x: fn(T::SomeType<'_>) -> u32, + explicit: for<'a> fn(T::SomeType<'a>) -> u32, +} + +fn main() { + let foo = Foo:: { x: read_value, explicit: read_value }; + let cloned = foo.clone(); + + let n = 42; + assert_eq!((cloned.x)(NotClone { value: &n }), 42); + assert_eq!((cloned.explicit)(NotClone { value: &n }), 42); +} diff --git a/tests/ui/derives/derive-clone-fn-pointer-with-placeholder-lifetime.rs b/tests/ui/derives/derive-clone-fn-pointer-with-placeholder-lifetime.rs new file mode 100644 index 0000000000000..8dc5d51fd116d --- /dev/null +++ b/tests/ui/derives/derive-clone-fn-pointer-with-placeholder-lifetime.rs @@ -0,0 +1,16 @@ +//@ check-pass +// Issue #143131: `#[derive(Clone)]` should accept a function pointer field whose +// input type contains a placeholder lifetime. + +#![allow(dead_code)] + +trait SomeTrait { + type SomeType<'a>; +} + +#[derive(Clone)] +struct Foo { + x: fn(T::SomeType<'_>), +} + +fn main() {} diff --git a/tests/ui/derives/derive-clone-nested-fn-pointer-with-placeholder-lifetime.rs b/tests/ui/derives/derive-clone-nested-fn-pointer-with-placeholder-lifetime.rs new file mode 100644 index 0000000000000..ab36f6dd9d0b2 --- /dev/null +++ b/tests/ui/derives/derive-clone-nested-fn-pointer-with-placeholder-lifetime.rs @@ -0,0 +1,16 @@ +//@ check-pass +// Type parameters inside nested function pointer signatures should not +// contribute bounds for derived Clone impls. + +#![allow(dead_code)] + +trait SomeTrait { + type SomeType<'a>; +} + +#[derive(Clone)] +struct Foo { + x: Option)>>, +} + +fn main() {}