Skip to content

Enums don't utilize niches across multiple data-carrying variants #121333

Open
@LunarLambda

Description

@LunarLambda

Tested on latest stable and nightly.

I wanted to build an enum X such that

enum X {
    Inline(MyType /* size: 24, align: 8 */),
    Heap(Vec<MyType>),
}

is 24 bytes large.

I tried various things to exploit Vec's niches (0/null on ptr, > isize::MAX on capacity), including using explicit-zero padding.
Unfortunately for this very specific case it seems Vec lacks alignment niches on its pointer field to make this work, and/or I can't make a niche that's big enough for the compiler to prove the two variants are fully "disjoint" in their valid bit patterns.

However, even testing with much simpler types with much simpler niches I could not get the compiler to produce an optimal enum layout:

#[repr(u64)]
enum AlwaysZero {
    VALUE = 0
}

enum X {
    A(AlwaysZero),
    B(std::num::NonZeroU64)
}

X is 16 bytes here, even though AlwaysZero and NonZeroU64's niches are exact opposites of each other, so the entire enum should just be 8 bytes. It would be nice if rustc could support at least simple two-variant cases like this. I can see it coming in handy for things like Result and possibly Cow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-layoutArea: Memory layout of typesC-bugCategory: This is a bug.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchS-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions