Skip to content

Commit 2be750b

Browse files
committed
Auto merge of #40188 - nikomatsakis:issue-40029, r=eddyb
inhibit enum layout optimizations under `#[repr(C)]` or `#[repr(u8)]` Fixes #40029
2 parents d095437 + 2b07d0d commit 2be750b

File tree

3 files changed

+69
-2
lines changed

3 files changed

+69
-2
lines changed

src/librustc/ty/layout.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,8 @@ impl<'a, 'gcx, 'tcx> Layout {
12011201
});
12021202
}
12031203

1204-
if !def.is_enum() || def.variants.len() == 1 {
1204+
if !def.is_enum() || (def.variants.len() == 1 &&
1205+
!def.repr.inhibit_enum_layout_opt()) {
12051206
// Struct, or union, or univariant enum equivalent to a struct.
12061207
// (Typechecking will reject discriminant-sizing attrs.)
12071208

@@ -1250,7 +1251,7 @@ impl<'a, 'gcx, 'tcx> Layout {
12501251
v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
12511252
}).collect::<Vec<_>>();
12521253

1253-
if variants.len() == 2 && !def.repr.c {
1254+
if variants.len() == 2 && !def.repr.inhibit_enum_layout_opt() {
12541255
// Nullable pointer optimization
12551256
for discr in 0..2 {
12561257
let other_fields = variants[1 - discr].iter().map(|ty| {

src/librustc/ty/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,13 @@ impl ReprOptions {
13911391
pub fn discr_type(&self) -> attr::IntType {
13921392
self.int.unwrap_or(attr::SignedInt(ast::IntTy::Is))
13931393
}
1394+
1395+
/// Returns true if this `#[repr()]` should inhabit "smart enum
1396+
/// layout" optimizations, such as representing `Foo<&T>` as a
1397+
/// single pointer.
1398+
pub fn inhibit_enum_layout_opt(&self) -> bool {
1399+
self.c || self.int.is_some()
1400+
}
13941401
}
13951402

13961403
impl<'a, 'gcx, 'tcx> AdtDef {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that we will do various size optimizations to enum layout, but
12+
// *not* if `#[repr(u8)]` or `#[repr(C)]` is passed. See also #40029.
13+
14+
#![allow(dead_code)]
15+
16+
use std::mem;
17+
18+
enum Nullable<T> {
19+
Alive(T),
20+
Dropped,
21+
}
22+
23+
#[repr(u8)]
24+
enum NullableU8<T> {
25+
Alive(T),
26+
Dropped,
27+
}
28+
29+
#[repr(C)]
30+
enum NullableC<T> {
31+
Alive(T),
32+
Dropped,
33+
}
34+
35+
struct StructNewtype<T>(T);
36+
37+
#[repr(C)]
38+
struct StructNewtypeC<T>(T);
39+
40+
enum EnumNewtype<T> { Variant(T) }
41+
42+
#[repr(u8)]
43+
enum EnumNewtypeU8<T> { Variant(T) }
44+
45+
#[repr(C)]
46+
enum EnumNewtypeC<T> { Variant(T) }
47+
48+
fn main() {
49+
assert!(mem::size_of::<Box<i32>>() == mem::size_of::<Nullable<Box<i32>>>());
50+
assert!(mem::size_of::<Box<i32>>() < mem::size_of::<NullableU8<Box<i32>>>());
51+
assert!(mem::size_of::<Box<i32>>() < mem::size_of::<NullableC<Box<i32>>>());
52+
53+
assert!(mem::size_of::<i32>() == mem::size_of::<StructNewtype<i32>>());
54+
assert!(mem::size_of::<i32>() == mem::size_of::<StructNewtypeC<i32>>());
55+
56+
assert!(mem::size_of::<i32>() == mem::size_of::<EnumNewtype<i32>>());
57+
assert!(mem::size_of::<i32>() < mem::size_of::<EnumNewtypeU8<i32>>());
58+
assert!(mem::size_of::<i32>() < mem::size_of::<EnumNewtypeC<i32>>());
59+
}

0 commit comments

Comments
 (0)