You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Private deprecated items should not be expected to have since #17893
deprecated_attributes_without_since (just added in #17609) currently applies to deprecated items that are not visible outside the crate. It should not, since such items are not part of the versioned API, and work addressing the deprecation would not have any necessary relationship to the version of the crate.
warning: `deprecated` attribute without specifying what version of the crate deprecated the item
--> src/lib.rs:3:5
|
3 | #[deprecated]
| ^^^^^^^^^^^^^ help: add a version: `#[deprecated(since = /* version */)]`
Hey, so I traced the issue to deprecated_attributes_without_fields::check_fields. Would a simple visibility check be enough here, or would it be better to move the since check to a late pass?
My understanding is that the first approach would still lint pub items inside private modules.
I don’t have enough experience with Clippy to say what the correct implementation is, but I think that it should respect effective visibility. For example, even without private modules involved:
structFoo;implFoo{#[deprecated]pubfnbar(&self){}}
bar's written visibility is public but certainly should not trigger the lint, since Foo is not public.
I'm a little confused as to why this would be an issue, and kind of disagree that it's a false positive at all. The point of #[deprecated] is to communicate to people writing code. I see two ways to look at this:
You only care about communicating this information to end-users. In which case, why are you deprecating things that aren't part of your external API at all? Just remove them.
You want to communicate these things internally too. In which case, you might as well document what version the deprecation happened in. You're effectively treating yourself as an end-user. It's pedantic for a reason, yeah? You can always allow/expect cases you disagree with, or even just satisfy it with #[deprecated(since = "TBD")].
In any case, if this is going to be treated as something to be "fixed", I'd ask that it be a configuration option rather than a change in behavior. I want the current behavior. I consider it the correct behavior, and I'd consider the proposed behavior a false-negative.
What version would an internal item even be deprecated in? Unlike public API items which have a first version containing the deprecation, private items are deprecated immediately in whatever commit added the attribute.
The practical benefit is also lost for private items. As documentation it tells you which release notes to check for more info. For tooling it helps guide when it should complain about the deprecation. Neither of these apply to internal items. For everything else you have the reason field or just comments on the item. Both work for internal development notes.
What version would an internal item even be deprecated in? Unlike public API items which have a first version containing the deprecation, private items are deprecated immediately in whatever commit added the attribute.
I'd say the same version that they would have been if they weren't private. It isn't exactly correct, as you said, but it's still giving you a rough idea of when the deprecation happened at a glance.
The practical benefit is also lost for private items. As documentation it tells you which release notes to check for more info. For tooling it helps guide when it should complain about the deprecation. Neither of these apply to internal items. For everything else you have the reason field or just comments on the item. Both work for internal development notes.
The practical benefit is that I don't have to do the whole song and dance with git blame and git tag --contains every time I'd like to figure out roughly when something was deprecated. I also wouldn't want that information to end up lost or confused through some series of history rewrites.
In which case, why are you deprecating things that aren't part of your external API at all? Just remove them.
This supposes that there is a straightforward replacement for the deprecated item, rather than each call site requiring further engineering to stop needing the deprecated item. As I see it, the point of bothering to use #[deprecated] at all for private items is to keep track of the nontrivial cases.
You want to communicate these things internally too. In which case, you might as well document what version the deprecation happened in.
If the goal is to finish removing the item before the next published release, then this means one has to write “this has been deprecated since [next version, that hasn’t been published yet]”, which seems to me more like busywork than useful record-keeping.
That said, I can see that other users might want since everywhere, and a configuration option seems like a reasonable solution.
The practical benefit is that I don't have to do the whole song and dance with git blame and git tag --contains every time I'd like to figure out roughly when something was deprecated. I also wouldn't want that information to end up lost or confused through some series of history rewrites.
If all you want is to have a date then putting it in there and calling it a day works. If you're actually tracking the deprecation there are many options that do that better. That said, the bar for putting this behind a config option isn't really that high. It isn't hard to implement and it's straightforward to describe what the option does.
error: the since field must contain a semver-compliant version
--> src/lib.rs:3:14
|
3 | #[deprecated(since = "2026-10-31")]
| ^^^^^^^^^^^^^^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/main/index.html#deprecated_semver
= note: `#[deny(clippy::deprecated_semver)]` on by default
since is defined to contain the version of the crate at the time of deprecating the item, following the semver scheme. Rustc does not know about versions, thus the content of this field is not checked (but will be by external lints, e.g. rust-clippy.
So, deprecated_semver is working as intended — since is not intended be a date rather than a version. (The RFC does not mention anything about applying #[deprecated] to non-public items.) That leaves the following possibilities:
#[deprecated] simply should not be put on non-public items at all. (This seems worse than all the alternatives.)
since should always be filled with a version, even for private items. (@hashcatHitman’s position.)
since should not be required for private items. (My original position.)
deprecated_semver should allow since to be anything for private items, so that deprecated_attributes_without_since can be satisfied by a date or other non-semver string. (Making your suggestion work.)
Even more relaxed but optionally: a configuration option which disables bothdeprecated_semver and deprecated_attributes_without_since for private items. This is overkill for my original request, but consistently fits a frame of “do what you want if it’s private”.
You forgot the secret 6th option: write the date in calVer notation. I'm pretty sure it'd be accepted? But that could lead to problems later if we make lints actually use that information, as was the intention.
Activity
osguzik commentedon Oct 18, 2026
I'd like to work on this.
@rustbot claim
osguzik commentedon Oct 19, 2026
Hey, so I traced the issue to
deprecated_attributes_without_fields::check_fields. Would a simple visibility check be enough here, or would it be better to move thesincecheck to a late pass?My understanding is that the first approach would still lint
pubitems inside private modules.kpreid commentedon Oct 25, 2026
I don’t have enough experience with Clippy to say what the correct implementation is, but I think that it should respect effective visibility. For example, even without private modules involved:
bar's written visibility is public but certainly should not trigger the lint, sinceFoois not public.hashcatHitman commentedon Oct 25, 2026
I'm a little confused as to why this would be an issue, and kind of disagree that it's a false positive at all. The point of
#[deprecated]is to communicate to people writing code. I see two ways to look at this:allow/expectcases you disagree with, or even just satisfy it with#[deprecated(since = "TBD")].In any case, if this is going to be treated as something to be "fixed", I'd ask that it be a configuration option rather than a change in behavior. I want the current behavior. I consider it the correct behavior, and I'd consider the proposed behavior a false-negative.
Jarcho commentedon Oct 25, 2026
What version would an internal item even be deprecated in? Unlike public API items which have a first version containing the deprecation, private items are deprecated immediately in whatever commit added the attribute.
The practical benefit is also lost for private items. As documentation it tells you which release notes to check for more info. For tooling it helps guide when it should complain about the deprecation. Neither of these apply to internal items. For everything else you have the
reasonfield or just comments on the item. Both work for internal development notes.osguzik commentedon Oct 25, 2026
@rustbot unclaim
hashcatHitman commentedon Oct 26, 2026
I'd say the same version that they would have been if they weren't private. It isn't exactly correct, as you said, but it's still giving you a rough idea of when the deprecation happened at a glance.
The practical benefit is that I don't have to do the whole song and dance with
git blameandgit tag --containsevery time I'd like to figure out roughly when something was deprecated. I also wouldn't want that information to end up lost or confused through some series of history rewrites.kpreid commentedon Oct 26, 2026
This supposes that there is a straightforward replacement for the deprecated item, rather than each call site requiring further engineering to stop needing the deprecated item. As I see it, the point of bothering to use
#[deprecated]at all for private items is to keep track of the nontrivial cases.If the goal is to finish removing the item before the next published release, then this means one has to write “this has been deprecated since [next version, that hasn’t been published yet]”, which seems to me more like busywork than useful record-keeping.
That said, I can see that other users might want
sinceeverywhere, and a configuration option seems like a reasonable solution.Jarcho commentedon Oct 26, 2026
If all you want is to have a date then putting it in there and calling it a day works. If you're actually tracking the deprecation there are many options that do that better. That said, the bar for putting this behind a config option isn't really that high. It isn't hard to implement and it's straightforward to describe what the option does.
kpreid commentedon Oct 31, 2026
Clippy denies that by default:
RFC 1790 specifically mentions that
So,
deprecated_semveris working as intended —sinceis not intended be a date rather than a version. (The RFC does not mention anything about applying#[deprecated]to non-public items.) That leaves the following possibilities:#[deprecated]simply should not be put on non-public items at all. (This seems worse than all the alternatives.)sinceshould always be filled with a version, even for private items. (@hashcatHitman’s position.)sinceshould not be required for private items. (My original position.)deprecated_semvershould allowsinceto be anything for private items, so thatdeprecated_attributes_without_sincecan be satisfied by a date or other non-semver string. (Making your suggestion work.)deprecated_semveranddeprecated_attributes_without_sincefor private items. This is overkill for my original request, but consistently fits a frame of “do what you want if it’s private”.hashcatHitman commentedon Oct 31, 2026
You forgot the secret 6th option: write the date in calVer notation. I'm pretty sure it'd be accepted? But that could lead to problems later if we make lints actually use that information, as was the intention.
So like this:
(unless it actually checks that you have a tag matching... which would surprise me, but isn't impossible)
Lint: Fix lint found by nightly Clippy.