I've been working on some projects requiring conditional compilation and have run into a number of inconsistencies or gaps in coverage in where you can and can't use #[cfg] in Rust code. This is a pretty important tool to be able to use in a lot of places, and so I'd like to help bridge some of these gaps where possible. Awhile back I proposed RFC 3399, which was accepted, and am currently proposing RFC 3532.
RFC 3532 addresses this particular inconsistency with tuples:
Legal:
fn main() {
let x = (2, "string", #[cfg(condition)] false); // OK!
}
Legal:
pub struct MyTupleStruct(SomeA, SomeB, #[cfg(condition)] SomeC); // OK!
Illegal:
type SomeTuple = (SomeA, SomeB, #[cfg(condition)] SomeC); // Not OK!
// ^^^^^^^^^^^^^^^^^ - Can't use cfg here
I've actually hit this issue in a use case in my library, gecs, which I have been working on trying to convert to use fewer proc macros and instead use type inference from tuples, but I can't do it if I can't ergonomically support conditional compilation there.
I've come across another similar issue recently that has another familiar inconsistency, but haven't done any sort of write-up for it yet:
Legal:
fn something<T0, #[cfg(condition)] T1>(a: T0, #[cfg(condition)] b: T1) {} // OK!
Legal:
fn main() {
something(1, #[cfg(condition)] 2); // OK!
}
Illegal:
fn main() {
something::<u32, #[cfg(condition)] i32>(1, #[cfg(condition)] 2); // Not OK!
// ^^^^^^^^^^^^^^^^^ - Can't use cfg here
}
These inconsistencies defy expectation in fairly unintuitive ways and can lead to frustrating workarounds and boilerplate. They can require wholesale duplication of a lot of code for cfg-branching, which gets even worse when you have multiple cfg-attribute conditions interacting on the same line or block as the result is combinatorial. This is an area where locality of annotation is very important, and the farther removed your cfg-attribute code annotation is from the code you actually intend to gate behind a flag, the more likely you are to lose details and create bugs.
Is there some sort of global decision-making here, or are these just oversights in the grammar? I'm inclined to continue writing RFCs to fix these sorts of inconsistencies, but it's a considerable effort and I'd like to see if there's a better way to have a more holistic discussion about how important cfg-attribute flexibility is first, especially as new features and syntax are added to the language that may need to account for cfg support.
So, what's the best course of action here?