Skip to content

Commit

Permalink
Rollup merge of rust-lang#37224 - petrochenkov:nz, r=eddyb
Browse files Browse the repository at this point in the history
Mark enums with non-zero discriminant as non-zero

cc rust-lang/rfcs#1230
r? @eddyb
  • Loading branch information
eddyb authored Oct 19, 2016
2 parents 82371f8 + 49e6b46 commit f399259
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 15 deletions.
32 changes: 17 additions & 15 deletions src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,8 @@ impl<'a, 'gcx, 'tcx> Struct {
-> Result<Option<FieldPath>, LayoutError<'gcx>> {
let tcx = infcx.tcx.global_tcx();
match (ty.layout(infcx)?, &ty.sty) {
(&Scalar { non_zero: true, .. }, _) => Ok(Some(vec![])),
(&Scalar { non_zero: true, .. }, _) |
(&CEnum { non_zero: true, .. }, _) => Ok(Some(vec![])),
(&FatPointer { non_zero: true, .. }, _) => {
Ok(Some(vec![FAT_PTR_ADDR as u32]))
}
Expand Down Expand Up @@ -769,6 +770,7 @@ pub enum Layout {
CEnum {
discr: Integer,
signed: bool,
non_zero: bool,
// Inclusive discriminant range.
// If min > max, it represents min...u64::MAX followed by 0...max.
// FIXME(eddyb) always use the shortest range, e.g. by finding
Expand Down Expand Up @@ -1002,9 +1004,10 @@ impl<'a, 'gcx, 'tcx> Layout {

if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) {
// All bodies empty -> intlike
let (mut min, mut max) = (i64::MAX, i64::MIN);
let (mut min, mut max, mut non_zero) = (i64::MAX, i64::MIN, true);
for v in &def.variants {
let x = v.disr_val.to_u64_unchecked() as i64;
if x == 0 { non_zero = false; }
if x < min { min = x; }
if x > max { max = x; }
}
Expand All @@ -1013,6 +1016,7 @@ impl<'a, 'gcx, 'tcx> Layout {
return success(CEnum {
discr: discr,
signed: signed,
non_zero: non_zero,
min: min as u64,
max: max as u64
});
Expand Down Expand Up @@ -1069,19 +1073,17 @@ impl<'a, 'gcx, 'tcx> Layout {

// FIXME(eddyb) should take advantage of a newtype.
if path == &[0] && variants[discr].len() == 1 {
match *variants[discr][0].layout(infcx)? {
Scalar { value, .. } => {
return success(RawNullablePointer {
nndiscr: discr as u64,
value: value
});
}
_ => {
bug!("Layout::compute: `{}`'s non-zero \
`{}` field not scalar?!",
ty, variants[discr][0])
}
}
let value = match *variants[discr][0].layout(infcx)? {
Scalar { value, .. } => value,
CEnum { discr, .. } => Int(discr),
_ => bug!("Layout::compute: `{}`'s non-zero \
`{}` field not scalar?!",
ty, variants[discr][0])
};
return success(RawNullablePointer {
nndiscr: discr as u64,
value: value,
});
}

path.push(0); // For GEP through a pointer.
Expand Down
39 changes: 39 additions & 0 deletions src/test/run-pass/nonzero-enum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::mem::size_of;

enum E {
A = 1,
B = 2,
C = 3,
}

struct S {
a: u16,
b: u8,
e: E,
}

fn main() {
assert_eq!(size_of::<E>(), 1);
assert_eq!(size_of::<Option<E>>(), 1);
assert_eq!(size_of::<Result<E, ()>>(), 1);
assert_eq!(size_of::<S>(), 4);
assert_eq!(size_of::<Option<S>>(), 4);
let enone = None::<E>;
let esome = Some(E::A);
if let Some(..) = enone {
panic!();
}
if let None = esome {
panic!();
}
}

0 comments on commit f399259

Please sign in to comment.