Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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<T: SomeTrait> {
x: fn(T::SomeType<'_>) -> u32,
explicit: for<'a> fn(T::SomeType<'a>) -> u32,
}

fn main() {
let foo = Foo::<Concrete> { 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);
}
Original file line number Diff line number Diff line change
@@ -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<T: SomeTrait> {
x: fn(T::SomeType<'_>),
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -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<T: SomeTrait> {
x: Option<Result<u32, fn(T::SomeType<'_>)>>,
}

fn main() {}
Loading