# Process for merging core/alloc/std

**URL:** https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613
**Category:** internals
**Created:** [September 24, 2026, 7:03am UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613 "2026-09-24T07:03:18Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)
#### Post date: [September 24, 2026, 7:03am UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/1 "2026-09-24T07:03:18Z")

</div>

Merging `core`, `alloc`, and `std` is something that has been thrown around on a number of occasions and has clear benefits (such as eliminating coherence hacks in the compiler among other things).

What would be the process to actually begin doing this? I _assume_ (naïvely) that it would involve creating `alloc` and `std` features inside of `core` and moving things over piecemeal. However, I have not the slightest clue how that would work with packaging things up for a toolchain release.

Perhaps more importantly, is this something teams are interested in? It's a cross-cutting concern, presumably involving libs (duh), lang (coherence), compiler (`rustc_` attrs), and release (packaging).

Strongly related: how could a situation such as `core::panic::PanicInfo` and `std::panic::PanicInfo` be handled? The two are surprisingly different types, which is something pointed out to me when I raised this in passing previously.

---

<div class="post-metadata">

### Author: ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)
#### Post date: [September 24, 2026, 9:00am UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/2 "2026-09-24T09:00:47Z")

</div>

It's still something libs is interested in doing. I think the best next step would be putting it on a libs meeting agenda (file an issue and libs-nominate it). We can talk through how we want to go about trying this as an experiment, and any blockers. Assuming we're prepared to go forward with it based on that, we can continue talking about the design specifics async on Zulip.

I expect we could handle the PanicInfo difference using feature flags, such that just-core gets one thing and std gets both with different paths. I can imagine a couple of ways to do that.

---

<div class="post-metadata">

### Author: ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)
#### Post date: [September 24, 2026, 9:17am UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/3 "2026-09-24T09:17:31Z")

</div>

I don't see how we can merge core, alloc and std without breaking changes. The precompiled standard library has to be compiled with alloc and std support enabled on most targets, but that would break `#![no_std]` programs that depend on libc not getting referenced or that use `#[panic_handler]`. Even just merging core and alloc would break `#[panic_handler]` without `-Zbuild-std` and mandating `-Zbuild-std` would break pretty much everyone who doesn't use cargo (and even cargo still wouldn't know whether to use `-Zbuild-std=core` or `-Zbuild-std=core,alloc` for a given program).

---

<div class="post-metadata">

### Author: ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)
#### Post date: [September 24, 2026, 9:23am UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/4 "2026-09-24T09:23:10Z")

</div>

My first guess is that we might need to have more than one pre-compiled library, or otherwise do something similar to what we already have to handle the split.

This experiment does not necessarily need to immediately start presenting things differently to the end user. It can start by trying to present an identical interface with a different underlying implementation.

---

<div class="post-metadata">

### Author: ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)
#### Post date: [September 24, 2026, 9:30am UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/5 "2026-09-24T09:30:11Z")

</div>

> [@josh](#):
>
> My first guess is that we might need to have more than one pre-compiled library, or otherwise do something similar to what we already have to handle the split.

But how would rustc know which to use when compiling the dependency? Because multiple precompiled standard libraries are not ABI compatible, rustc would need to make a guess which one the user wants in the end when compiling a dependency, but if that guess was wrong, compiling the leaf crate will give an error about duplicate lang items.

---

<div class="post-metadata">

### Author: ![Vorpal](https://avatars.discourse-cdn.com/v4/letter/v/aca169/32.png) [@Vorpal](https://internals.rust-lang.org/u/Vorpal)
#### Post date: [September 24, 2026, 9:46am UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/6 "2026-09-24T09:46:41Z")

</div>

As a user, a better solution would be to improve coherence so that STD doesn't need to have special hacks for it. I would rather see the ability to (soundly) define sets of crates that are in the same coherence domain, or something like that. This would help immensely outside std as well.

Furthermore, I want std to long term not be special. Yes, some parts in core do need special things that cannot be stabilised. But ideally everything alloc and std does should be possible for a normal crate to do.

---

<div class="post-metadata">

### Author: ![epage](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/epage/32/3171_2.png) [@epage](https://internals.rust-lang.org/u/epage)
#### Post date: [September 24, 2026, 12:33pm UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/7 "2026-09-24T12:33:33Z")

</div>

How would this fit into build-std? Would `core` just re-export `std`? Would we transition manifests to those features or keep using the specific crates?

---

<div class="post-metadata">

### Author: ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)
#### Post date: [September 24, 2026, 8:03pm UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/8 "2026-09-24T20:03:21Z")

</div>

> [@josh](#):
>
> My first guess is that we might need to have more than one pre-compiled library, or otherwise do something similar to what we already have to handle the split.
> 
> This experiment does not necessarily need to immediately start presenting things differently to the end user. It can start by trying to present an identical interface with a different underlying implementation.

This was my assumption as to how things would happen (hence marking the thread "internals"). The end user shouldn't care about this, at least for the time being.

- `core`: `--no-default-features`
- `alloc`: `--no-default-features --features alloc`
- `std`: (default)

All three would remain surfaced as-is to the end user, no guessing necessary. Further down the line we could _potentially_ eliminate the distinction altogether.

> [@Vorpal](#):
>
> As a user, a better solution would be to improve coherence so that STD doesn't need to have special hacks for it. I would rather see the ability to (soundly) define sets of crates that are in the same coherence domain, or something like that. This would help immensely outside std as well.

Agreed, but I don't see any way to do that soundly given that crate names are user-defined.

> [@Vorpal](#):
>
> Furthermore, I want std to long term not be special. Yes, some parts in core do need special things that cannot be stabilised. But ideally everything alloc and std does should be possible for a normal crate to do.

Three years ago now…

[![](https://img.youtube.com/vi/vPOlYFs6Bs0/maxresdefault.jpg "RustConf 2023 - The standard library is special. Let's change that.") ](https://www.youtube.com/watch?v=vPOlYFs6Bs0)

---

<div class="post-metadata">

### Author: ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)
#### Post date: [September 24, 2026, 8:07pm UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/9 "2026-09-24T20:07:39Z")

</div>

> [@jhpratt](#):
>
> This was my assumption as to how things would happen (hence marking the thread "internals"). The end user shouldn't care about this, at least for the time being.
> 
> - `core`: `--no-default-features`
> - `alloc`: `--no-default-features --features alloc`
> - `std`: (default)

The problem with this approach is that today, you don’t know whether a given crate depends on `std` until you start compiling it, so it’s not possible for Cargo to pick the right set of `std` features up front. So, this can’t be done until everyone migrates to a world where `Cargo.toml` includes `std` dependencies.

---

<div class="post-metadata">

### Author: ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)
#### Post date: [September 24, 2026, 8:16pm UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/10 "2026-09-24T20:16:06Z")

</div>

But we'd still be shipping three pre-packages libraries, so how is that an issue?

---

<div class="post-metadata">

### Author: ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)
#### Post date: [September 24, 2026, 8:22pm UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/11 "2026-09-24T20:22:15Z")

</div>

Suppose that crate `foo` depends on crates `bar` and `baz`, and crate `baz` is `#![no_std]`, but none of the others are. Then the build process might proceed as:

1. Compile `bar`, linked against full-feature `std`
2. Compile `baz`, linked against no-features `std`
3. Compile `foo`, linked against `bar` and `baz` ... oops, we have a conflict between two `std`s.

For today’s Cargo features, Cargo solves this problem by computing the features to activate based on `[dependencies]` info. But there is no such info for `no_std` — it can only be discovered by actually performing the build.

---

<div class="post-metadata">

### Author: ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)
#### Post date: [September 24, 2026, 8:32pm UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/12 "2026-09-24T20:32:04Z")

</div>

> [@jhpratt](#):
>
> Agreed, but I don't see any way to do that soundly given that crate names are user-defined.

If coherence domains are created by passing the same value to `-Ccoherence-domain` and in addition you need an extra rustc invocation after compiling all crates in the coherence domain that you pass all members of the coherence domain to for checking the coherence of all crates combined, producing a proof file, then it wouldn't be possible for users to cause conflicts. Cargo would give each coherence domain a unique name and in addition make sure no unintended crates end up in it by not passing them to the coherence check rustc invocation.

---

<div class="post-metadata">

### Author: ![Vorpal](https://avatars.discourse-cdn.com/v4/letter/v/aca169/32.png) [@Vorpal](https://internals.rust-lang.org/u/Vorpal)
#### Post date: [September 24, 2026, 8:54pm UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/13 "2026-09-24T20:54:27Z")

</div>

> [@kpreid](#):
>
> So, this can’t be done until everyone migrates to a world where `Cargo.toml` includes `std` dependencies.

That can approximately never happen, as you can keep using crates on old editions and made for old Rust versions. Which means this proposal is dead in the water from what I can tell (unless someone finds a solution by really thinking out of the box).

---

<div class="post-metadata">

### Author: ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)
#### Post date: [September 24, 2026, 10:50pm UTC](https://internals.rust-lang.org/t/process-for-merging-core-alloc-std/24613/14 "2026-09-24T22:50:18Z")

</div>

> [@kpreid](#):
>
> we have a conflict between two `std`s

The only thing that would affect is lang items, no? The compiler already handles re-exports of items from core in std, why wouldn't it be able to handle two identical definitions of lang items? Sure, there would need to be a way to declare them as identical, but that seems quite easy.
