#[deprecated] does nothing if placed on an impl item.

35e30c2
Opened by Sage Griffin at 2024-12-28 13:51:51

Given the following two crates:

#![crate_name = "foo"]

pub struct Foo;
pub struct Bar;

pub trait IntoBar {
    fn into_bar(self) -> Bar;
}

#[deprecated(note = "Just pass `Bar` instead")]
impl IntoBar for Foo {
    fn into_bar(self) -> Bar {
        Bar
    }
}
extern crate foo;

use foo::*;

fn main() {
    let _ = Foo.into_bar();
}

I would expect the second crate to see a deprecation warning on the use of Foo.into_bar(). Instead, both crates compile successfully with no errors. I think that allowing deprecations on impls is a useful option to provide to authors (one that I was looking to do, and found this while seeing if it would work). However, if we do not wish to provide that ability to library authors, placing the #[deprecated] attribute on an impl should result in a compiler error.

  1. This is unfortunately a limitation of stability today, it just doesn't work at all with trait impls. (we run into this all the time in libstd as well)

    Alex Crichton at 2017-02-21 15:03:24

  2. @alexcrichton Do we want to support stability on trait impls or not? I remember this being discussed elsewhere but I don't remember the conclusion.

    Austin Bonander at 2018-09-01 04:06:08

  3. It'd be nice yeah! At this point everyone just assumes it doesn't work, so there's likely lots of misannotated impls or unintended fallout from a "bugfix" change like this, but it'd be good to implement if possible!

    Alex Crichton at 2018-09-03 17:20:16

  4. I still think we should at least make this a compiler error until we can make it work. I disagree with the "everyone assumes it doesn't work" take, I think folks do assume it works, and never verify if their users are receiving a warning or not.

    Sage Griffin at 2018-09-10 22:39:34

  5. I still think we should at least make this a compiler error until we can make it work.

    A warning would be a gentler option. I agree that it's not good to let people put the deprecation attribute on and assume it will work.

    Mikhail Zabaluev at 2018-11-26 20:46:20

  6. I'm surprised this hasn't received more attention. It seems like a rather common occurrence that a library will have a type that implements a trait and you want to remove it but there is no way to direct users away from using the impl Trait. For instance, I have a type that implements Iterator, but I want to change it to instead have an fn iter().

    Cameron Steffen at 2020-07-15 14:50:28

  7. #78626 turned this into a compile error.

    ordian at 2021-01-04 09:28:45

  8. Given the current stable release:

    cargo -V -v cargo 1.82.0 (8f40fc59f 2024-08-21) release: 1.82.0 commit-hash: 8f40fc59fb0c8df91c97405785197f3c630304ea commit-date: 2024-08-21 host: aarch64-apple-darwin libgit2: 1.8.1 (sys:0.19.0 vendored) libcurl: 8.7.1 (sys:0.4.74+curl-8.9.0 system ssl:(SecureTransport) LibreSSL/3.3.6) ssl: OpenSSL 1.1.1w 11 Sep 2023 os: Mac OS 15.0.1 [64-bit]

    Then I am at least told that the deprecation is not going to work:

    cargo build Compiling foo v0.1.0 (/Users/rod/code/rust/triage/deprec/foo) error: this #[deprecated] annotation has no effect --> src/lib.rs:10:1 | 10 | #[deprecated(note = "Just pass Bar instead")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the unnecessary deprecation attribute | = note: #[deny(useless_deprecated)] on by default

    error: could not compile foo (lib) due to 1 previous error

    Rod at 2024-10-21 18:38:05