Skip to content

add an internal lint for nightly-channel-only features without a feature gate #139892

Open
@jyn514

Description

@jyn514

we really should not have features that are available only on nightly but do not have a feature gate. this leads to people unknowingly using unstable features, which in turn leads to situations where we have no choice but to stabilize features unchanged because otherwise we break too much of the ecosystem. it also defeats the whole point of -Z allow-features.

we should do two things:

  • audit all existing features to make sure they have a feature gate. @jieyouxu tells me that at least #[cfg(target_has_atomic)] does not.
  • add an internal lint against UnstableFeatures::is_nightly_build. basically the only reason it's valid to check this is for diagnostics, or very early in session building, and both of those can add an explicit allow().

@rustbot label A-stability

Activity

added
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on Apr 16, 2025
added
C-enhancementCategory: An issue proposing an enhancement or a PR with one.
A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
and removed
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on Apr 16, 2025
Zalathar

Zalathar commented on Apr 16, 2025

@Zalathar
Contributor

There are a few different ways for arbitrary compiler code to check whether the compiler is nightly:

  • Session::is_nightly_build (on tcx.sess)
  • UnstableFeatures::is_nightly_build (obtained via UnstableFeatures::from_environment)
  • Functions in nightly_options

So it would be useful to audit all of these.

I could also imagine splitting some of these APIs into diagnostic-only and non-diagnostic variants, so that it's easier to audit the legitimate exceptions.

RalfJung

RalfJung commented on Apr 16, 2025

@RalfJung
Member

FWIW, cfg(target_feature) also changes behavior on nighty by adding information about nightly target features. I think the reason is the lack of a good discoverable alternative: we don't really have a way to gate cfg(target_feature = "nightly_feature") specifically; that expression compiles fine on stable, it just always evaluates to false. We could say you have to set #[feature(nightly_target_features)], or set the feature gate guarding that specific nightly target feature, but then cfg(target_feature = "nightly_feature") would just silently become "false" and users wouldn't know they have to set a feature gate.

bjorn3

bjorn3 commented on Apr 16, 2025

@bjorn3
Member

All unstable cfg's are implicitly available on the nightly channel. Note that cargo needs to know which cfg's are set before compiling a single line of rust code (so #![feature] wouldn't work for it) and rustc doesn't know which features are enabled until the cfg's for the crate root are evaluated.

jyn514

jyn514 commented on Apr 16, 2025

@jyn514
MemberAuthor

Note that cargo needs to know which cfg's are set before compiling a single line of rust code

what does cargo need this information for? my understanding is that this is an internal feature that is only used by libstd - we shouldn't have [cfg.'target_has_atomic'.dependencies] or anything like that.

rustc doesn't know which features are enabled until the cfg's for the crate root are evaluated.

we should ban unstable cfgs at the crate root IMO.

we don't really have a way to gate cfg(target_feature = "nightly_feature") specifically; that expression compiles fine on stable, it just always evaluates to false. We could say you have to set #[feature(nightly_target_features)], or set the feature gate guarding that specific nightly target feature, but then cfg(target_feature = "nightly_feature") would just silently become "false" and users wouldn't know they have to set a feature gate.

that makes sense to me and is a little trickier - perhaps it could continue to be "false", but not silently? where we give a future-incompat lint that the behavior may change, and you can use feature() to opt in today?

bjorn3

bjorn3 commented on Apr 16, 2025

@bjorn3
Member

my understanding is that this is an internal feature that is only used by libstd

target_has_atomic_load_store and target_has_atomic_equal_alignment are not the only unstable cfgs (target_has_atomic is stable by the way). The example Ralf gave of cfg(target_feature = "nightly_feature") is another one which will become stable in the future. And target_has_atomic_load_store seems like it would be useful to stabilize in the future. And some code (especially those that use inline asm) needs cfg(relocation_model).

jyn514

jyn514 commented on Apr 16, 2025

@jyn514
MemberAuthor

got it, that makes sense. i still think "continues to evaluate to false until you enable a feature gate, warns if the gate is disabled" is a reasonable solution and better than enabling unconditionally on nightly.

target_has_atomic

target_has_atomic with a value (e.g. 16) is stable, but target_has_atomic without a value is not.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.A-stabilityArea: `#[stable]`, `#[unstable]` etc.C-enhancementCategory: An issue proposing an enhancement or a PR with one.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @RalfJung@bjorn3@Zalathar@jyn514@jieyouxu

        Issue actions

          add an internal lint for nightly-channel-only features without a feature gate · Issue #139892 · rust-lang/rust