Setting a 4 byte enum variant results in a 64k memcopy!



I noticed that if I have an enum with a large and a small variant, creating a value using the small variant still zeros out the rest of the memory in the enum.

pub enum MyEnum {
    B([u8; 65536]),

pub fn set_enum_a(e: &mut MyEnum) {
    *e = MyEnum::A(35);

In this case initialising an enum variant ‘A’ results in a 64k memcopy, even though the variant only takes up 4 bytes. Generated assembler:

	lea	rsi, [rip + const2970]
	mov	edx, 1028
	jmp	memcpy@PLT
	.byte	0
	.zero	3
	.long	35
	.zero	65532
	.size	const2970, 65540

What’s the reason for this?
(e.g. is there a way to ‘change’ the variant of the enum and thus get access to uninitialized data?).

Thanks v much,



The behaviour you’re seeing seems to be an unfortunate consequence of the new value being a constant expression (i.e. the whole value can be evaluated and placed in static memory at compile time), making it dynamic avoids the memcpy:

pub fn set_enum_a(e: &mut MyEnum, x: u32) {
    *e = MyEnum::A(x);
	movb	$0, (%rdi)
	movl	%esi, 4(%rdi)

The constant-value-in-static is actually an explicit decision on the part of rustc, so it seems we should be tweaking that to avoid massive deoptimisations like this. I opened #28398.


Ah awesome, thanks Huon. it didn’t occur to me that this would behave differently with a dynamic expression