So were doing totality checking on various
cfg combinations? This looks really good! A few scattered thoughts
I am reminded of the subset-std https://github.com/rust-lang/rust/issues/27701. The only worry for me on this plan is that it could compete with importing various combinations of crates beneath the facade someday.
#[scenario_requirements(..)]might not actually be needed? Is enough to assume the
cfgson public items, and trace their dependencies ensuring that all variations outside of the assumptions are covered? I forget if
#![cfg(...)]is a thing, but that would avoid the need to repeatedly label a bunch of items too. Also this means we can do the same totality check over platform attributes and cargo features alike.
Cargo should be made aware of scenario requirements. Specifically,
#![scenario_requirements(..)]should be duplicated in
Cargo.toml. Then Cargo can verify that dependencies respect the declared scenario requirements. Furthermore, https://github.com/rust-lang/rfcs/blob/master/text/1361-cargo-cfg-dependencies.md can be re-purposed to “unlock” non-portable items—conditional deps (and “re-added” normal deps) would have all items exposed portable up to the assumptions of the
[target.cfg(..).section]. An open question is how to combine the targets-/feature-assumptions of conditional deps listed in two places.
The obvious reason for the lint is because we’re trying to reuse std lib binaries in many contexts. At first I thought that with explicit std dependencies + rebuilding std every time, std simply wouldn’t contain insufficiently-portable items, and all would be good. But actually things are more complex: Since dependencies are shared, they must contain items sufficient for their most demanding consumer—but we should still ensure that other deps don’t actually overstep their portability constraints. Also note that this also applies to features. We therefore want the lint to make sure that each dependency only gets what it asks for. Here is an example: Consider
bar, a “diamond”. Consider also that
yof initial, but
baronly depends on
barshould not be able to use any items exposed by
With the above in place, it’s possible to build crates up to a large set of enabled non-portabilities and features in order to reuse the binaries—this applies both to a hypothetical global Cargo cache, and the way we build the std lib for the sysroot today. However there should always be a way opt-out of this for when the implementation details of features/exposed-platform-attributes matter. For example without
--gc-sections, unused impls in libcore would still cause linking problems, and some features (though presumably any of the ones in std) change the implementations of features in important ways without affecting their portability (the item exists whether or not the feature is used).