Pre-RFC: have_rustc cfg item

I'm currently working on a custom compiler for rust, and have run into a few diverging internal things. Some of this is easily fixed using stability attributes in the library, but some depend on knowledge of the underlying compiler (in particular, I have a custom internal lang item that isn't available on rustc, so it should only be a lang item on the custom compiler). I would like to generalize a planned feature for that compiler, which is the have_rustc cfg item. It would be used like the other cfg items, but would serve to check compiler features. I have two potential ways this could be implemented:

  • have_rustc="vendor", would apply only if vendor's rust compiler is in use. For example, the official compiler would have have_rustc="rustc", the custom one would have have_rustc="lccc" (lccc is the name of the project that includes this custom compiler). However, have_rustc="rustc" would not be available on lccc, even if lccc perfectly implements the internals of rustc. I would personally lean more towards this method.
  • have_rustc="vendor" would apply if the internal features (lang items, internal attributes, some unstable language features, and intrinsics are the primary ones) of the compiler provided by vendor are available, even if that compiler is not the exact one in use. In the above example, have_rustc="rustc" would be true on the lccc compiler when run in rustc compatibility mode (specifically, if it is called through a binary with path name rustc)

With either method, it should at least warn when used, as generally the only reason to use it would be internally, within a standard library implementation. There are a few additional reasons, which is why I don't believe this should necessarily be a purely internal attribute (for example, various compilers may be further ahead on implementing various unstable features, so it could be used to switch on those features with compilers in a significant state of development for those features).

I believe at least some of the use cases like this are meant to be covered by Tracking issue for RFC 2523, #[cfg(accessible(::path::to:thing))]. At least, most lang items that application code can meaningfully interact with involving going through a path to a thing, so I would expect that to apply. And lang items that standard library code interacts with are generally tied to a specific compiler/std version, since the compiler and std have to be deeply coupled and versioned as a pair anyway, so if this only affects your custom toolchain's std I don't see why we'd want something new in rustc for it.

Would that cover your use case? If not, can you tell us more about it so we can understand why not? (we definitely would like to avoid "compiler sniffing" if it's not truly necessary)

2 Likes

So the specific case I'm refering to here is that I'm adding an internal lccc_unwrapping_deref lang item to un-magic some of Box, so I can make it ready for what wg-allocator is doing. Obviously, I can't do this on regular rustc which doesn't have said lang item (its lccc internal, after all), so I need a way to kill the lang_item when not on lccc (I may need to be able to do this on rustc, to bootstrap into the lccc compiler, depending on how the bootstrap process is, I am not able to double-compile any single executable without hackyness, as the overall project is cmake). The other obvious point would be implementations of unstable features, such as const generics. As I am also working on a C++ compiler for this project, I will have a library available that will implement C++ templates. Rust generics are not too different from C++ templates when you consider concepts, and C++ has non-type template parameters. If it happened that this was more stable and complete then rustc's const-generics, a rust program, especially a low-level ones, could benefit from such an implementation, and enable const-generics, but on less-stable implementations, would default to macro expanding for array types in particular. The inverse could be true for features which are less focused on for lccc, but nearly complete in rustc. A futher use would be to check for unstable features which are only available on one (I have a few features in mind that I would test on lccc before proposing to rust itself) This is the primary reason this shouldn't necessarily be an internal item, but rather available (if recommended against using, using a lint of some sort).

I don't think it makes sense to standardize a mechanism for detecting non-standard Rust reimplementations. Rather, it might make sense for such an implementation to define a special feature flag by default, such that code can detect that feature flag, and then use some other construct provided by that compiler if and only if that feature flag is set.

That was my first consideration (rustc allows you to define arbitrary cfg items on the command line, so it stands to reason rust would allow a different compiler to do so automatically). However, there would be benefit in standardization, as (especially when a full specification exists for rust) different compilers could communicate its internal features/completeness using a standardized mechanism so there would be less divergence where such a mechanism is reasonably used (such as my example of testing for a more complete const-generics implementation, before switching the feature on, otherwise falling back to a standard mechanism)

Please test features, rather than vendors. For example many of the chrome experiments would work fine in firefox, but are blocked by the site, because it checks for chrome, rather than the feature used in the experiment

7 Likes

That would be a nice feature as an alternative. Something like has_feature="const_generics". However, the question would be if it would apply when the feature is available (and you can use #![feature(const_generics)]), or when the feature is complete and tested (IE. unlikely to cause internal errors/ICEs). I could probably communicate the existance of lccc internl language items via has_feature="lccc_lang_items". Further, would this open up to has_feature="rust-version", or similar, which tests for the stable features of a particular version of rust, or would there be a stable variant of has_feature, which tests if a particular feature is available and stable? Coming from a C++ background, I'd lean more towards the former. C++20 feature test macros test for the completeness of a feature, then the standard version macro (__cplusplus) is used to test for the stability of all features from that version.

Well, this is exactly why I linked #[cfg(accessible)]. That's basically the only concrete proposal for feature testing that's ever been made, and likely the only one worth the ROI in the near term where there's only one major Rust implementation. The same RFC also included #[cfg(version)] stuff, but everyone involved in those discussions seems to agree that accessible should be strongly preferred wherever possible. For now it's unclear whether testing for const generics will have to be a version or if there will be some magical function like is_constant_evaluated stabilized at the same time so you can do an accessible check for the whole thing.

So AFAICT everything you're saying is already in that proposal, except for unstable feature testing, which would need a lot more motivation (again, unstable features seem pretty deeply tied to a specific compiler implementation, by definition).

1 Like

So AFAICT everything you're saying is already in that proposal, except for unstable feature testing, which would need a lot more motivation (again, unstable features seem pretty deeply tied to a specific compiler implementation, by definition).

Not necessarily. Any compiler that is targetting a rust spec (even one simply invented by deriving it from the reference and rustdoc) would have an interest in providing gated unstable features, as it means that they can have it available soon after it does become stabalized. Further, even for non-standard unstable features, other compilers may provide them for various reasons. That's why I consider that testing for unstable features is a good idea. It also holds the same internal motivations as above.