Skip to content

Avoid deriving bounds from FnPtr#156194

Open
sgasho wants to merge 1 commit intorust-lang:mainfrom
sgasho:143131-single-use-lifetimes
Open

Avoid deriving bounds from FnPtr#156194
sgasho wants to merge 1 commit intorust-lang:mainfrom
sgasho:143131-single-use-lifetimes

Conversation

@sgasho
Copy link
Copy Markdown
Contributor

@sgasho sgasho commented May 5, 2026

closes: #143131
closes: #155446

We don't need bounds for the inputs and outputs of function pointers.

for the code below, for example,

#![allow(dead_code)]
trait SomeTrait {
    type SomeType<'a>;
}

#[derive(Clone)]
struct Foo<T: SomeTrait> {
    x: fn(T::SomeType<'_>)
}

fn main() {}

Before
An error occurs for a lifetime.

rustc +nightly -Zunpretty=expanded main.rs
error[E0637]: `'_` cannot be used here
 --> main.rs:8:23
  |
8 |     x: fn(T::SomeType<'_>),
  |                       ^^ `'_` is a reserved lifetime name

#![feature(prelude_import)]
#![no_std]
#![allow(dead_code)]
extern crate std;
#[prelude_import]
use ::std::prelude::rust_2015::*;
trait SomeTrait {
    type SomeType<'a>;
}

struct Foo<T: SomeTrait> {
    x: fn(T::SomeType<'_>),
}
#[automatically_derived]
impl<T: ::core::clone::Clone + SomeTrait> ::core::clone::Clone for Foo<T>
    where T::SomeType<'_>: ::core::clone::Clone {
    #[inline]
    fn clone(&self) -> Foo<T> {
        Foo { x: ::core::clone::Clone::clone(&self.x) }
    }
}

fn main() {}

After
where T::SomeType<'_>: ::core::clone::Clone, which was incorrect, and unnecessary, has gone
No errors.

rustc +issue143131 -Zunpretty=expanded main.rs
#![feature(prelude_import)]
#![no_std]
#![allow(dead_code)]
extern crate std;
#[prelude_import]
use ::std::prelude::rust_2015::*;
trait SomeTrait {
    type SomeType<'a>;
}

struct Foo<T: SomeTrait> {
    x: fn(T::SomeType<'_>),
}
#[automatically_derived]
impl<T: ::core::clone::Clone + SomeTrait> ::core::clone::Clone for Foo<T> {
    #[inline]
    fn clone(&self) -> Foo<T> {
        Foo { x: ::core::clone::Clone::clone(&self.x) }
    }
}

fn main() {}

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 5, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented May 5, 2026

r? @chenyukang

rustbot has assigned @chenyukang.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 73 candidates
  • Random selection from 20 candidates

Copy link
Copy Markdown
Member

@chenyukang chenyukang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

according to the blame history, maybe r? @estebank need to confirm this change.

View changes since this review

@rustbot rustbot assigned estebank and unassigned chenyukang May 5, 2026
@fmease
Copy link
Copy Markdown
Member

fmease commented May 5, 2026

Can this lead to pass→fail regressions? Does this need crater? Is T-compiler really the right team or is it T-libs{-api} or T-lang?

@sgasho
Copy link
Copy Markdown
Contributor Author

sgasho commented May 5, 2026

Oh, I found a pass→fail case, but I think the new behavior is semantically correct.

code

trait SomeTrait {
    type SomeType<'a>;
}

#[derive(Clone)]
struct Concrete;

struct NotClone<'a>(&'a ());

impl SomeTrait for Concrete {
    type SomeType<'a> = NotClone<'a>;
}

#[derive(Clone)]
struct Foo<T: SomeTrait> {
    x: for<'a> fn(T::SomeType<'a>),
}

trait Local {}

impl<T: Clone> Local for T {}

// Before this PR: Foo<Concrete> does not satisfy Clone
// After this PR: it does -> impl conflicts

impl Local for Foo<Concrete> {}

fn main() {}

output

❯ rustc +issue143131 main.rs
error[E0119]: conflicting implementations of trait `Local` for type `Foo<Concrete>`
  --> main.rs:23:1
   |
21 | impl<T: Clone> Local for T {}
   | -------------------------- first implementation here
22 |
23 | impl Local for Foo<Concrete> {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Foo<Concrete>`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0119`.

This happens because the PR makes the derived Clone impl less constrained.
Some types that previously did not satisfy Clone can now satisfy it, which may expose coherence overlap with blanket impls.

The affected pattern seems quite narrow, but I agree that a crater run would be the safer way to measure the actual ecosystem impact.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

where T::Ty<'_>: Trait bounds false positive: single-use-lifetimes '_ is a reserved lifetime name

5 participants