Skip to content

unstable target_feature can be used in cfg(target_feature) and -Ctarget-feature on nightly without any kind of opt-in / feature gate #76842

Open

Description

@mystor

I tried this code: playpen

#[cfg(target_feature="mmx")]
compile_fail!("we have mmx");

I expected to see this happen:

This code uses a feature-gated cfg(, without enabling the feature. I would expect this to produce a build warning about using an unstable cfg gate, and produce no build error on all channels.

(target_feature="mmx" is currently gated behind mmx_target_feature as far as I can tell)

("mmx", Some(sym::mmx_target_feature)),

Instead, this happened:

On stable, the gate was ignored as expected, but on the nightly channel the cfg check passed, causing the compile_fail! to be included in the source. The lack of a feature gate enabling mmx_target_feature was ignored, only considering the current release channel.

I believe this is occurring due to the feature gate logic for the target_feature config flag not being checked within the compiler. This mismatch lead me to believe that an unstable target_feature flag was actually stable, and write code using it, before realizing it won't function outside of the nightly channel.

Meta

rustc --version --verbose:
stable:

rustc 1.46.0 (04488afe3 2020-08-24)
binary: rustc
commit-hash: 04488afe34512aa4c33566eb16d8c912a3ae04f9
commit-date: 2020-08-24
host: x86_64-unknown-linux-gnu
release: 1.46.0
LLVM version: 10.0

nightly:

rustc 1.47.0-nightly (bf4342114 2020-08-25)
binary: rustc
commit-hash: bf4342114e357f2934d59e12e31e94532ddb2adf
commit-date: 2020-08-25
host: x86_64-unknown-linux-gnu
release: 1.47.0-nightly
LLVM version: 11.0

(this also occurs on rust-playpen at time of filing: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=4c58960ac6fc536a2da930d6c0b3d8e9)

Activity

  1. m-ou-se commented on Sep 17, 2020

    @m-ou-se
    Member

    Looks like all feature gated target_features are made available on nightly regardless of enabled features, here:

    supported_target_features(sess)
    .iter()
    .filter_map(|&(feature, gate)| {
    if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
    Some(feature)
    } else {
    None
    }
    })

  2. added
    requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.
    A-stabilityArea: `#[stable]`, `#[unstable]` etc.
    on Sep 17, 2020
  3. changed the title [-]Feature gate for unstable target_feature values not being checked[/-] [+]Feature gate for unstable target_feature values not being checked on nightly[/+] on Sep 17, 2020
  4. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Sep 17, 2020
  5. m-ou-se commented on Sep 17, 2020

    @m-ou-se
    Member

    It seems like all target_features were always available on nightly when cfg_target_feature was still unstable. So, cfg(target_feature = "mmx") was not gated behind mmx_target_feature, but only behind cfg_target_feature. #49664 stabilized cfg_target_feature, and added the lines I quoted above to let only stable target_features (not mmx) through on stable, but didn't change the behaviour on nightly. So that's when the 'unstable' cfg(target_feature = "mmx") suddenly became ungated.

  6. RalfJung commented on Oct 23, 2026

    @RalfJung
    Member

    On nightly rustc, all unstable target features get added to cfg(target_feature), and -Ctarget-feature accepts all unstable target features, without any kind of opt-in via -Z or #![feature] or so.

    This is tricky to fix because #![feature] is parsed too late to affect cfg or -C parsing. Do we have any other cfg where the values of the cfg should differ based on whether one uses a nightly rustc? This is quite different from requiring nightly to use a particular cfg variable at all -- using target_feature is obviously fine, but whether or not it is populated with unstable target features should somehow be opt-in. Not sure how that could be done.
    Cc @Urgau @bjorn3

  7. changed the title [-]Feature gate for unstable target_feature values not being checked on nightly[/-] [+]unstable target_feature can be used in `cfg(target_feature)` and `-Ctarget-feature` on nightly without any kind of opt-in / feature gate[/+] on Oct 23, 2026
  8. Urgau commented on Oct 23, 2026

    @Urgau
    Member

    Do we have any other cfg where the values of the cfg should differ based on whether one uses a nightly rustc?

    We have multiple cfgs who are only set on nightly (not sure if they count towards your question): fmt_debug, target_has_atomic/target_has_atomic_load_store and relocation_model.

  9. RalfJung commented on Oct 24, 2026

    @RalfJung
    Member

    Looking at fmt_debug I see that's guarded by -Zfmt-debug. So maybe we should just have -Zunstable-target-features which then has two effects

    • unstable target features are added to cfg(target_feature)
    • we allow -Ctarget-feature with unstable target features

    This would ignore the actual nightly feature that is associated with that target feature. We'd still require that for #[target_feature]. We could have people say -Zunstable-target-features=riscv_target_feature but that seems kind of annoying.

    @rust-lang/lang does that seem reasonable to you? And would you prefer the variant with -Zunstable-target-features unlocking all unstable target features or with having to list feature gates?

  10. RalfJung commented on Oct 24, 2026

    @RalfJung
    Member

    OTOH for target_has_atomic, just the mere fact that one uses nightly already changes the value of the cfg. That does not seem great? EDIT: Ah, that is #133295.

    relocation_model seems to have a check elsewhere that rejects looking at it without feature(cfg_relocation_model). So while the coe makes no justification for why it's okay to have nightly-dependent behavior here, it seems to be fine.

  11. added
    I-lang-radarItems that are on lang's radar and will need eventual work or consideration.
    P-lang-drag-1Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang
    on Oct 28, 2026
  12. Mark-Simulacrum commented on Oct 28, 2026

    @Mark-Simulacrum
    Member

    For in-code cfgs, it seems like we should be able to use the same principle we use for gating unstable syntax to gate cfgs. Is there a reason we can't / don't do that, to allow #![feature(...)] to gate these cfgs "as expected"? Lang generally felt that this would be desirable to do if possible. (This would feature-gate regardless of whether the feature is actually set).

    For the command-line enabling, we felt that is possibly more of a compiler question but requiring some -Z flag felt not-unreasonable.

  13. RalfJung commented on Oct 28, 2026

    @RalfJung
    Member

    We currently gate some cfg variables but not some cfg values. Values are an open-ended set. So today you can write cfg(target_feature = "foobar") (it always evaluates to false) but if tomorrow an architecture adds a "foobar" target feature then we break such code by requiring a feature gate? What if "foobar" is stable on x86-64 but unstable on aarch64, do we have target-dependent stability checking?

  14. Mark-Simulacrum commented on Nov 4, 2026

    @Mark-Simulacrum
    Member

    Lang discussed again. We generally felt that it may not be a bad idea to have both target-dependent feature checking and to ban writing target_feature = "foobar" (as unstable / not permitted syntax). That has some tradeoffs (as you note) around cross-target testing and the extent to which users need extra annotation / cfg_attr etc.

    That said, we'd like to see a Crater run to see what the maximally-restrictive rule here is going to mean for the ecosystem, to see how much flexibility we have in defining the rules. Ideally, that rule would feature-gate cfgs even in short-circuit position (e.g., any(true, target_feature = "not yet stable") should get a feature gate error).

  15. RalfJung commented on Nov 4, 2026

    @RalfJung
    Member

    (e.g., any(true, target_feature = "not yet stable") should get a feature gate error).

    And what about target_feature = "does not exist today but may exist in the future"?
    That would also have to error, otherwise adding an unstable feature becomes a breaking change. Basically, you seem to be saying that unknown_cfgs should become a hard error for target_feature?

  16. RalfJung commented on Nov 4, 2026

    @RalfJung
    Member

    Also, what about target_feature = "stable on one architecture but unstable on another"?
    I don't really see how stability checks are supposed to work here. Note that stability is a function of target features and architectures, but when we see a target_feature = "foo" in a program, we don't have a good way to find out which architecture the programmer means. Often this will be in a context like all(target_arch = "...", target_feature = "..."), but those two checks can be arbitrarily far away from each other, and sometimes programmers forget them and assume that the target feature only exists for a single architecture.

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-stabilityArea: `#[stable]`, `#[unstable]` etc.C-bugCategory: This is a bug.I-lang-nominatedNominated for discussion during a lang team meeting.I-lang-radarItems that are on lang's radar and will need eventual work or consideration.P-lang-drag-1Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-langT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions