RFC: naming groups of configuration with `cfg_alias`
This proposal introduces a way to name configuration predicates for easy reuse throughout a crate.
#![cfg_alias(x86_linux = all(
any(target_arch = "x86", target_arch = "x86_64"), target_os = "linux"
))]
#[cfg(x86_linux)]
fn foo() { /* ... */ }
#[cfg(not(x86_linux))]
fn foo() { /* ... */ }
Previous discussion:
- https://github.com/rust-lang/rfcs/issues/831
- https://github.com/rust-lang/rust/pull/130780#issuecomment-2822439922
- #t-lang > cfg aliases
- https://internals.rust-lang.org/t/pre-rfc-cfg-attribute-alias/7404/16
#![cfg_alias(some_alias = predicate)]
I'm against syntax cfg_alias(ident = predicate) and prefer cfg_alias(ident, predicate), because of consistency concerns:
- We already have a very similar
cfg_attr(predicate, meta)syntax.cfg_alias(ident, predicate)just flips it and identifier is also a validmeta. Using comma here is most natural and consistent design. path(ident = meta)is a completely new syntax that does not exist anywhere, and contradicts the status quo that=always follows an expression, adding cognitive complexity for human. See current "meta" grammar in reference. Not sure if it will introduce actual implementation complexity.- As mentioned above,
#![cfg_alias(name = target_os = "linux")]has two=with different meaning which is very confusing. Same situation can also occur when nestingcfg_aliasinside other attributes or vice versa.
This seems like a useful and practical feature. In some ways it can overlap with the use case for https://github.com/rust-lang/rfcs/pull/3697 declarative attribute macros, but I prefer being able to see #[cfg(...)] when an item might be configured out.
There is also some overlap with the nicer target(...) configuration tracked in https://github.com/rust-lang/rust/issues/96901. Personally I don't see why we can't have both.
@rfcbot fcp merge
@tmandry Hi, sorry, we had rfcbot breakage a bit earlier. Can you try proposing FCP again?
I'd like to see how this proposal is compared to crossfig.
I enjoy the match-like branch syntax to switch between rustc versions: code
crossfig::alias! {
// verify-rust-std
std: { #[cfg(feature = "std")] },
// Rust for Linux
rfl: { #[cfg(feature = "rfl")] },
// Asterinas OS
asterinas: { #[cfg(feature = "asterinas")] }
}
crossfig::switch! {
std => {
#[macro_use]
extern crate rustc_public;
use rustc_public::rustc_internal::internal;
}
_ => {
#[macro_use]
extern crate rustc_smir;
extern crate stable_mir;
use stable_mir as rustc_public;
use rustc_smir::rustc_internal::{self, internal};
}
}
crossfig::switch! {
crate::std => { let attrs = tcx.get_all_attrs(def_id).iter(); }
crate::rfl => { let attrs = tcx.get_all_attrs(def_id); }
crate::asterinas => { let attrs = tcx.get_attrs_unchecked(def_id).iter(); }
}
@tgross35 could you update the RFC to cover the prior art for third-party crates as well as integrating other discussions on this RFC, like https://github.com/rust-lang/rfcs/pull/3804#discussion_r2071644426 ?
Its a big help for the reviewing team to have everything summarized rather than assuming they will read all of an RFC thread.
@tmandry should FCP be held off until the RFC has been updated?
If the bot had picked up the proposed FCP, I was planning to file the following concerns, so it may be just as well that the bot missed it for now.
While I do like the general idea of this RFC, there are some things I'd like to see us first address in terms of its design and specification:
// @rfcbot concern settle-on-syntax
Before we get too far into checking boxes, I'd prefer for us to settle on the syntax. Right now, as specified, we'd accept:
#![cfg_alias(alias = target_os = "linux")]
Probably none of us want that. We could require parens, but it would still leave us with the basic problem that we'd be using the = in conflicting ways in attribute position. The main way it's used today, of course, is as a "set contains" operator.
Using a comma, e.g.,
#![cfg_alias(alias, target_os = "linux")]
while not beautiful, is consistent with what we do with cfg_attr.
I'd suggest that we hold off on trying to do something better than that for the day that we work out how to move away from using = for "set contains" in attribute position or when we otherwise come up with some broader plan for reworking this syntax.
(Another alternative would be to use => as a mapping operator -- we're mapping the name of the attribute to its body, in a similar way to how the unstable hash_map! macro maps keys to values. Some ecosystem solutions apparently work this way.)
// @rfcbot concern hygiene
I'd like to see the specification of this filled out to discuss the hygiene question that @joshtriplett raised in https://github.com/rust-lang/rfcs/pull/3804#discussion_r2062684394.
// @rfcbot concern why-module-level-only
I'd like to see an answer to the question I raised in https://github.com/rust-lang/rfcs/pull/3804#discussion_r2059182582. If there's not a reason to special-case which scopes to which this can apply, I'd prefer we accept this at other scopes where it would make sense.
// @rfcbot concern name-resolution
As raised by @mejrs in https://github.com/rust-lang/rfcs/pull/3804#discussion_r2058099468, I worry a bit about us adding something that can be defined in the source but that lives outside of our normal system for importing and exporting names. I'd like to see discussion, analysis, or experimentation on this. The idea that @tgross35 mentioned in https://github.com/rust-lang/rfcs/pull/3804#discussion_r2057208678 of framing this as a kind of macro has some appeal, and I'd be curious to know whether there's interest in exploring that further.