← Back to index
PR #3365Work-in-progress preview from an open pull request.View on GitHub ↗
REVIEW
#3365

(fill me in with a unique ident, reexport-stdlib-macros)

Authoryoshuawuyts
CreatedJan 4 2023
UpdatedJun 10 2023
Rust Issue

This RFC proposed we start re-exporting macros currently exposed in core::* from submodules. We define a mapping of which macros to re-export from which submodules, though in some cases it makes most sense to keep the macros exported from core.

This RFC does not yet propose we deprecate or migrate any code, that is left up to future RFCs.

Motivation

Right now the Rust stdlib exports over 70 macros, most of which exist only in the crate root - despite providing a wide range of functionality. This has negative consequences for the stdlib's root: not only are there countless submodules, there are also an overwhelming number of macros doing an assortment of things. But it also has negative consequences for the individual submodules: they will often only tell part of a story, and often leave out crucial information on how they should actually be used.

Take for example the std::panic submodule. It includes various methods to inspect, catch, and even modify panic behavior. But it includes no facilities to actually trigger panics. Experienced rustaceans will know that this can be done using panic!, todo!, unimplemented! and the like. But for someone new to Rust, this information is not made readily available.

When macros are available from submodules we can begin to paint a more complete picture of how those submodules are intended to be used. Up until recently it wasn't possible to expose macros from submodules, but now that it is we should take the opportunity to start making use of it.

Mapping re-exports

The following table covers which macro we're talking about, which sub-module it should be made available from, whether that's a new sub-module, and whether the macro is unstable. Macros which are unstable can be moved rather than just re-exported.

Macro nameProposed modNew exports?Unstable?
assertcore::panic
assert_eqcore::panic
assert_matches::assert_matchescore::panic
assert_matches::debug_assert_matchescore::panic
assert_necore::panic
cfgcore
clone::Clonecore::clone
cmp::Eqcore::cmp
cmp::Ordcore::cmp
cmp::PartialEqcore::cmp
cmp::PartialOrdcore::cmp
columncore
compile_errorcore
concatcore
concat_bytescore
concat_identscore
const_format_argscore::fmt
dbgcore::io
debug_assertcore::panic
debug_assert_eqcore::panic
debug_assert_necore::panic
default::Defaultcore::default
envcore
eprintcore::io
eprintlncore::io
filecore
fmt::Debugcore::fmt
formatcore::fmt
format_argscore::fmt
format_args_nlcore::fmt
future::joincore
hash::Hashcore::hash::Hash
includecore
include_bytescore
include_strcore
is_aarch64_feature_detectedcore::arch
is_arm_feature_detectedcore::arch
is_mips64_feature_detectedcore::arch
is_mips_feature_detectedcore::arch
is_powerpc64_feature_detectedcore::arch
is_powerpc_feature_detectedcore::arch
is_riscv_feature_detectedcore::arch
is_x86_feature_detectedcore::arch
linecore
llvm_asmcore
log_syntaxcore
marker::Copycore::marker
matchescore
module_pathcore
option_envcore
paniccore::panic
prelude::v1::benchcore::prelude::v1
prelude::v1::cfg_accessiblecore::prelude::v1
prelude::v1::cfg_evalcore::prelude::v1
prelude::v1::derivecore::prelude::v1
prelude::v1::global_allocatorcore::prelude::v1
prelude::v1::testcore::prelude::v1
prelude::v1::test_casecore::prelude::v1
printcore::io
printlncore::io
ptr::addr_ofcore::ptr
ptr::addr_of_mutcore::ptr
simd::simd_swizzlecore::simd
stringifycore
task::readycore::task
thread_localcore::thread
todocore::panic
trace_macroscore
trycore
unimplementedcore::panic
unreachablecore::panic
veccore::vec
writecore
writelncore

Reference-level explanation

The implementation of this RFC should be no more than adding a re-export from the submodule to the existing macro found in the crate root. Say we're re-exporting core::assert from core::panic::assert, we could imagine it being done along these lines:

pub mod core {
    /// Panics the current thread.
    #[macro_export]
    macro_rules! panic { ... }

    pub mod panic {
        pub use crate::panic;
    }
}

Some of these macros such as panic! will be built-ins, meaning that changing their implementations might have implications for the compiler. Because this RFC only proposes we re-export macros and not migrate macros (see "future possibilities"), simply creating an alias for the macro from the submodule is enough.

Prior art

It was only up to recently that it wasn't possible to export macros from submodules. New macros being added to the stdlib are already available from submodules (e.g. std::ptr::addr_of, std::task::ready). And derive-macros have always been available from submodules (e.g. std::clone::Clone, std::hash::Hash).

Now that the technical restriction has been lifted, we can finally look at the existing macros and start to re-export them from their logical submodules.

Unresolved questions

write/writeln

Both the write and writeln macros call a method named write on a type, as exists in the stdlib as std::fmt::Write and std::io::Write.

Because write/writeln both need to be available from core, they would need to at least be available from core::fmt - there is no core::io. But when considering the std docs it might make sense to expose them from both. One point in favor of doing it from both locations is that it would enable both the fmt and io docs to be more self-contained. But it's unclear what the best option would be. What should we do here?

Future possibilities

Deprecate macros in stdlib root

Once we have the macros re-exported from their respective submodules, we can start looking at what to do with the macros currently still in the stdlib's root. Should we deprecate them over an edition? Should we change the way they're shown in the docs? Because having 50 or so deprecated items in the crate root seems like a lot.

It's likely we'll want to do something here, but it's unclear what exactly. Therefor we're leaving this as an open question which should be explored in the future, but for now is out of the scope of this RFC.

API Guidlines

It might be helpful for the stdlib's API guidelines to include a section explaining when to export macros from existing submodules, when to export them from newly created submodules, and when to export them from the crate root.