18

Let's assume I have the following feature defined in Cargo.toml:

[features]
my_feature = []

And the following code lives in src/lib.rs:

#[cfg(feature = "my_feature")]
fn f() { /* ... */ }

#[cfg(not(feature = "my_faeture"))] // <-- Mind the typo!
fn f() { /* ... */ }

How can I enforce, that the feature-strings are matched against the list of both explicitly defined and implicitly available features in Cargo.toml so that for instance typos could be avoided?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Peter Varo
  • 11,726
  • 7
  • 55
  • 77
  • 1
    Something Clippy ought to have a lint for, but apparently doesn't. – eggyal Oct 12 '21 at 07:40
  • 1
    I strongly believe this should be the responsibility of `rustc`. For instance you could pass down a set of features that you wish the compiler to enforce, instead of pushing this responsibility further to a linter, which is very much optional to use. – Peter Varo Oct 12 '21 at 07:43
  • 2
    rustc doesn't know anything about `Cargo.toml`. The set of features defined there (and then selected for a compilation) are simply turned into `--cfg` arguments to the rustc invocation: rustc won't know about any that exist but aren't enabled, nor is Cargo's use of `feature` as a cfg key in any way special to rustc. – eggyal Oct 12 '21 at 07:45
  • Exactly, that's why `cargo` would pass down the flags to `rustc` if it would be able to take in feature flags for strict checking. – Peter Varo Oct 12 '21 at 07:45
  • It really seems to me that this is a peculiarity of the build tool, not of rustc per se. A different build tool might use `option` as a cfg identifier instead of `feature`; might give each such feature its own cfg identifier each with a boolean value (to indicate whether or not it's enabled); or indeed might do something completely different. Requiring the compiler to offer a validator for the whims of each possible build tool seems unnecessarily complex, and anything else would be coupling it a little too tightly to one particular approach? – eggyal Oct 12 '21 at 07:58
  • Since Cargo cannot do much on its own, I think the right approach would be for the compiler to either optionally take features which needs to be strictly checked, or would offer a flag to turn this check on for all the already passed down features. I don't think this approach would introduce strong-coupling with a specific wrapper: the word `feature` is used by `core`'s `cfg`. – Peter Varo Oct 12 '21 at 08:05
  • Either way, I'm not sure how this thread actually helps my question. I'm quite happy to continue this discussion here: https://chat.stackoverflow.com/rooms/62927/rust – Peter Varo Oct 12 '21 at 08:06

1 Answers1

14

When RFC 3013, "Checking conditional compilation at compile time", is implemented, there will be warnings for a #[cfg] referring to a feature name that is not declared by Cargo, just as you're asking for. However, the implementation only just got started (Sep 28, 2021).

The means of operation described in the RFC is just as you suggested, ‘cargo would pass down the flags to rustc’.


It may be worth noting that this will not check all conditions appearing in the source text; as described in the RFC:

This lint will not be able to detect invalid #[cfg] tests that are within modules that are not compiled, presumably because an ancestor mod is disabled.

So, it will not confirm that all #[cfg(feature)] are valid on a single cargo check — you will need to test with your various features or combinations of features. But those are the same combinations that you would need anyway to check for compile errors in all of the regular source code that could be enabled; once you do that, the lint will assure you that you don't have any #[cfg(feature)] that are never enabled due to a typo.

Kevin Reid
  • 37,492
  • 13
  • 80
  • 108