Skip to content

Commit

Permalink
Allow uint discriminants and store them as such
Browse files Browse the repository at this point in the history
Infers type of constants used as discriminants and ensures they are
integral, instead of forcing them to be a signed integer.

Also, stores discriminant values as uint instead of int interally and
deals with related fallout.

Fixes issue #7994
  • Loading branch information
kemurphy committed Jul 25, 2013
1 parent 4a726f0 commit 1c3dc29
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 55 deletions.
6 changes: 3 additions & 3 deletions src/librustc/metadata/decoder.rs
Expand Up @@ -23,7 +23,7 @@ use metadata::tydecode::{parse_ty_data, parse_def_id,
use middle::ty;

use std::hash::HashUtil;
use std::int;
use std::uint;
use std::io::WriterUtil;
use std::io;
use std::option;
Expand Down Expand Up @@ -200,9 +200,9 @@ fn each_reexport(d: ebml::Doc, f: &fn(ebml::Doc) -> bool) -> bool {
return true;
}

fn variant_disr_val(d: ebml::Doc) -> Option<int> {
fn variant_disr_val(d: ebml::Doc) -> Option<uint> {
do reader::maybe_get_doc(d, tag_disr_val).chain |val_doc| {
do reader::with_doc_data(val_doc) |data| { int::parse_bytes(data, 10u) }
do reader::with_doc_data(val_doc) |data| { uint::parse_bytes(data, 10u) }
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/librustc/metadata/encoder.rs
Expand Up @@ -21,7 +21,6 @@ use middle;

use std::hash::HashUtil;
use std::hashmap::{HashMap, HashSet};
use std::int;
use std::io;
use std::str;
use std::uint;
Expand Down Expand Up @@ -290,9 +289,9 @@ fn encode_discriminant(ecx: &EncodeContext,

fn encode_disr_val(_: &EncodeContext,
ebml_w: &mut writer::Encoder,
disr_val: int) {
disr_val: uint) {
ebml_w.start_tag(tag_disr_val);
let s = int::to_str(disr_val);
let s = uint::to_str(disr_val);
ebml_w.writer.write(s.as_bytes());
ebml_w.end_tag();
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/trans/_match.rs
Expand Up @@ -193,7 +193,7 @@ pub enum Lit {
// range)
pub enum Opt {
lit(Lit),
var(/* disr val */int, @adt::Repr),
var(/* disr val */ uint, @adt::Repr),
range(@ast::expr, @ast::expr),
vec_len_eq(uint),
vec_len_ge(uint, /* slice */uint)
Expand Down Expand Up @@ -874,7 +874,7 @@ pub struct ExtractedBlock {

pub fn extract_variant_args(bcx: @mut Block,
repr: &adt::Repr,
disr_val: int,
disr_val: uint,
val: ValueRef)
-> ExtractedBlock {
let _icx = push_ctxt("match::extract_variant_args");
Expand Down
62 changes: 33 additions & 29 deletions src/librustc/middle/trans/adt.rs
Expand Up @@ -64,7 +64,7 @@ use middle::trans::type_::Type;
/// Representations.
pub enum Repr {
/// C-like enums; basically an int.
CEnum(int, int), // discriminant range
CEnum(uint, uint), // discriminant range
/**
* Single-case variants, and structs/tuples/records.
*
Expand All @@ -89,7 +89,7 @@ pub enum Repr {
* is represented such that `None` is a null pointer and `Some` is the
* identity function.
*/
NullablePointer{ nonnull: Struct, nndiscr: int, ptrfield: uint,
NullablePointer{ nonnull: Struct, nndiscr: uint, ptrfield: uint,
nullfields: ~[ty::t] }
}

Expand Down Expand Up @@ -140,7 +140,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
return Univariant(mk_struct(cx, ftys, packed), dtor)
}
ty::ty_enum(def_id, ref substs) => {
struct Case { discr: int, tys: ~[ty::t] };
struct Case { discr: uint, tys: ~[ty::t] };
impl Case {
fn is_zerolen(&self, cx: &mut CrateContext) -> bool {
mk_struct(cx, self.tys, false).size == 0
Expand Down Expand Up @@ -177,7 +177,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
// Since there's at least one
// non-empty body, explicit discriminants should have
// been rejected by a checker before this point.
if !cases.iter().enumerate().all(|(i,c)| c.discr == (i as int)) {
if !cases.iter().enumerate().all(|(i,c)| c.discr == i) {
cx.sess.bug(fmt!("non-C-like enum %s with specified \
discriminants",
ty::item_path_str(cx.tcx, def_id)))
Expand Down Expand Up @@ -206,7 +206,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
}

// The general case.
let discr = ~[ty::mk_int()];
let discr = ~[ty::mk_uint()];
return General(cases.map(|c| mk_struct(cx, discr + c.tys, false)))
}
_ => cx.sess.bug("adt::represent_type called on non-ADT type")
Expand Down Expand Up @@ -305,17 +305,16 @@ pub fn trans_get_discr(bcx: @mut Block, r: &Repr, scrutinee: ValueRef)
-> ValueRef {
match *r {
CEnum(min, max) => load_discr(bcx, scrutinee, min, max),
Univariant(*) => C_int(bcx.ccx(), 0),
General(ref cases) => load_discr(bcx, scrutinee, 0,
(cases.len() - 1) as int),
Univariant(*) => C_uint(bcx.ccx(), 0),
General(ref cases) => load_discr(bcx, scrutinee, 0, cases.len() - 1),
NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => {
ZExt(bcx, nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee),
Type::enum_discrim(bcx.ccx()))
}
}
}

fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: int, ptrfield: uint,
fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: uint, ptrfield: uint,
scrutinee: ValueRef) -> ValueRef {
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
let llptr = Load(bcx, GEPi(bcx, scrutinee, [0, ptrfield]));
Expand All @@ -324,7 +323,7 @@ fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: int, ptrfield:
}

/// Helper for cases where the discriminant is simply loaded.
fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: int, max: int)
fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: uint, max: uint)
-> ValueRef {
let ptr = GEPi(bcx, scrutinee, [0, 0]);
if max + 1 == min {
Expand All @@ -348,16 +347,16 @@ fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: int, max: int)
*
* This should ideally be less tightly tied to `_match`.
*/
pub fn trans_case(bcx: @mut Block, r: &Repr, discr: int) -> _match::opt_result {
pub fn trans_case(bcx: @mut Block, r: &Repr, discr: uint) -> _match::opt_result {
match *r {
CEnum(*) => {
_match::single_result(rslt(bcx, C_int(bcx.ccx(), discr)))
_match::single_result(rslt(bcx, C_uint(bcx.ccx(), discr)))
}
Univariant(*) => {
bcx.ccx().sess.bug("no cases for univariants or structs")
}
General(*) => {
_match::single_result(rslt(bcx, C_int(bcx.ccx(), discr)))
_match::single_result(rslt(bcx, C_uint(bcx.ccx(), discr)))
}
NullablePointer{ _ } => {
assert!(discr == 0 || discr == 1);
Expand All @@ -371,11 +370,11 @@ pub fn trans_case(bcx: @mut Block, r: &Repr, discr: int) -> _match::opt_result {
* representation. The fields, if any, should then be initialized via
* `trans_field_ptr`.
*/
pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int) {
pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: uint) {
match *r {
CEnum(min, max) => {
assert!(min <= discr && discr <= max);
Store(bcx, C_int(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
Store(bcx, C_uint(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
}
Univariant(ref st, true) => {
assert_eq!(discr, 0);
Expand All @@ -386,7 +385,7 @@ pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int) {
assert_eq!(discr, 0);
}
General(*) => {
Store(bcx, C_int(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
Store(bcx, C_uint(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
}
NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => {
if discr != nndiscr {
Expand All @@ -402,22 +401,22 @@ pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int) {
* The number of fields in a given case; for use when obtaining this
* information from the type or definition is less convenient.
*/
pub fn num_args(r: &Repr, discr: int) -> uint {
pub fn num_args(r: &Repr, discr: uint) -> uint {
match *r {
CEnum(*) => 0,
Univariant(ref st, dtor) => {
assert_eq!(discr, 0);
st.fields.len() - (if dtor { 1 } else { 0 })
}
General(ref cases) => cases[discr as uint].fields.len() - 1,
General(ref cases) => cases[discr].fields.len() - 1,
NullablePointer{ nonnull: ref nonnull, nndiscr, nullfields: ref nullfields, _ } => {
if discr == nndiscr { nonnull.fields.len() } else { nullfields.len() }
}
}
}

/// Access a field, at a point when the value's case is known.
pub fn trans_field_ptr(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int,
pub fn trans_field_ptr(bcx: @mut Block, r: &Repr, val: ValueRef, discr: uint,
ix: uint) -> ValueRef {
// Note: if this ever needs to generate conditionals (e.g., if we
// decide to do some kind of cdr-coding-like non-unique repr
Expand All @@ -431,7 +430,7 @@ pub fn trans_field_ptr(bcx: @mut Block, r: &Repr, val: ValueRef, discr: int,
struct_field_ptr(bcx, st, val, ix, false)
}
General(ref cases) => {
struct_field_ptr(bcx, &cases[discr as uint], val, ix + 1, true)
struct_field_ptr(bcx, &cases[discr], val, ix + 1, true)
}
NullablePointer{ nonnull: ref nonnull, nullfields: ref nullfields, nndiscr, _ } => {
if (discr == nndiscr) {
Expand Down Expand Up @@ -495,22 +494,22 @@ pub fn trans_drop_flag_ptr(bcx: @mut Block, r: &Repr, val: ValueRef) -> ValueRef
* this could be changed in the future to avoid allocating unnecessary
* space after values of shorter-than-maximum cases.
*/
pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: int,
pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: uint,
vals: &[ValueRef]) -> ValueRef {
match *r {
CEnum(min, max) => {
assert_eq!(vals.len(), 0);
assert!(min <= discr && discr <= max);
C_int(ccx, discr)
C_uint(ccx, discr)
}
Univariant(ref st, _dro) => {
assert_eq!(discr, 0);
C_struct(build_const_struct(ccx, st, vals))
}
General(ref cases) => {
let case = &cases[discr as uint];
let case = &cases[discr];
let max_sz = cases.iter().transform(|x| x.size).max().unwrap();
let discr_ty = C_int(ccx, discr);
let discr_ty = C_uint(ccx, discr);
let contents = build_const_struct(ccx, case,
~[discr_ty] + vals);
C_struct(contents + &[padding(max_sz - case.size)])
Expand Down Expand Up @@ -582,13 +581,18 @@ fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a }

/// Get the discriminant of a constant value. (Not currently used.)
pub fn const_get_discrim(ccx: &mut CrateContext, r: &Repr, val: ValueRef)
-> int {
-> uint {
match *r {
CEnum(*) => const_to_int(val) as int,
CEnum(*) => const_to_uint(val) as uint,
Univariant(*) => 0,
General(*) => const_to_int(const_get_elt(ccx, val, [0])) as int,
General(*) => const_to_uint(const_get_elt(ccx, val, [0])) as uint,
NullablePointer{ nndiscr, ptrfield, _ } => {
if is_null(const_struct_field(ccx, val, ptrfield)) { 1 - nndiscr } else { nndiscr }
if is_null(const_struct_field(ccx, val, ptrfield)) {
/* subtraction as uint is ok because nndiscr is either 0 or 1 */
(1 - nndiscr) as uint
} else {
nndiscr
}
}
}
}
Expand All @@ -601,7 +605,7 @@ pub fn const_get_discrim(ccx: &mut CrateContext, r: &Repr, val: ValueRef)
* raw LLVM-level structs and arrays.)
*/
pub fn const_get_field(ccx: &mut CrateContext, r: &Repr, val: ValueRef,
_discr: int, ix: uint) -> ValueRef {
_discr: uint, ix: uint) -> ValueRef {
match *r {
CEnum(*) => ccx.sess.bug("element access in C-like enum const"),
Univariant(*) => const_struct_field(ccx, val, ix),
Expand Down
9 changes: 4 additions & 5 deletions src/librustc/middle/trans/base.rs
Expand Up @@ -67,7 +67,6 @@ use middle::trans::type_::Type;

use std::hash;
use std::hashmap::{HashMap, HashSet};
use std::int;
use std::io;
use std::libc::c_uint;
use std::uint;
Expand Down Expand Up @@ -732,7 +731,7 @@ pub fn iter_structural_ty(cx: @mut Block, av: ValueRef, t: ty::t,
for (*variants).iter().advance |variant| {
let variant_cx =
sub_block(cx, ~"enum-iter-variant-" +
int::to_str(variant.disr_val));
uint::to_str(variant.disr_val));
let variant_cx =
iter_variant(variant_cx, repr, av, *variant,
substs.tps, |x,y,z| f(x,y,z));
Expand Down Expand Up @@ -1979,7 +1978,7 @@ pub fn trans_enum_variant(ccx: @mut CrateContext,
_enum_id: ast::node_id,
variant: &ast::variant,
args: &[ast::variant_arg],
disr: int,
disr: uint,
param_substs: Option<@param_substs>,
llfndecl: ValueRef) {
let _icx = push_ctxt("trans_enum_variant");
Expand Down Expand Up @@ -2028,7 +2027,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
ccx: @mut CrateContext,
ctor_id: ast::node_id,
args: &[A],
disr: int,
disr: uint,
param_substs: Option<@param_substs>,
llfndecl: ValueRef)
{
Expand Down Expand Up @@ -2628,7 +2627,7 @@ pub fn trans_constant(ccx: &mut CrateContext, it: @ast::item) {
}
};
unsafe {
llvm::LLVMSetInitializer(discrim_gvar, C_int(ccx, disr_val));
llvm::LLVMSetInitializer(discrim_gvar, C_uint(ccx, disr_val));
llvm::LLVMSetGlobalConstant(discrim_gvar, True);
}
ccx.discrims.insert(
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/consts.rs
Expand Up @@ -446,7 +446,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::expr) -> ValueRef {
(expr::cast_enum, expr::cast_float) => {
let repr = adt::represent_type(cx, basety);
let discr = adt::const_get_discrim(cx, repr, v);
let iv = C_int(cx, discr);
let iv = C_uint(cx, discr);
let ety_cast = expr::cast_type_kind(ety);
match ety_cast {
expr::cast_integral => {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/trans/expr.rs
Expand Up @@ -1083,7 +1083,7 @@ pub fn trans_local_var(bcx: @mut Block, def: ast::def) -> Datum {
pub fn with_field_tys<R>(tcx: ty::ctxt,
ty: ty::t,
node_id_opt: Option<ast::node_id>,
op: &fn(int, (&[ty::field])) -> R) -> R {
op: &fn(uint, (&[ty::field])) -> R) -> R {
match ty::get(ty).sty {
ty::ty_struct(did, ref substs) => {
op(0, struct_fields(tcx, did, substs))
Expand Down Expand Up @@ -1200,7 +1200,7 @@ struct StructBaseInfo {
* - `optbase` contains information on the base struct (if any) from
* which remaining fields are copied; see comments on `StructBaseInfo`.
*/
fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: int,
fn trans_adt(bcx: @mut Block, repr: &adt::Repr, discr: uint,
fields: &[(uint, @ast::expr)],
optbase: Option<StructBaseInfo>,
dest: Dest) -> @mut Block {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/reflect.rs
Expand Up @@ -321,7 +321,7 @@ impl Reflector {
for variants.iter().enumerate().advance |(i, v)| {
let name = ccx.sess.str_of(v.name);
let variant_args = ~[this.c_uint(i),
this.c_int(v.disr_val),
this.c_uint(v.disr_val),
this.c_uint(v.args.len()),
this.c_slice(name)];
do this.bracketed("enum_variant", variant_args) |this| {
Expand Down
11 changes: 6 additions & 5 deletions src/librustc/middle/ty.rs
Expand Up @@ -49,7 +49,7 @@ use syntax::opt_vec;
use syntax::abi::AbiSet;
use syntax;

pub static INITIAL_DISCRIMINANT_VALUE: int = 0;
pub static INITIAL_DISCRIMINANT_VALUE: uint = 0;

// Data types

Expand Down Expand Up @@ -3689,7 +3689,7 @@ pub struct VariantInfo {
ctor_ty: t,
name: ast::ident,
id: ast::def_id,
disr_val: int,
disr_val: uint,
vis: visibility
}

Expand All @@ -3700,7 +3700,7 @@ impl VariantInfo {
/// Does not do any caching of the value in the type context.
pub fn from_ast_variant(cx: ctxt,
ast_variant: &ast::variant,
discriminant: int) -> VariantInfo {
discriminant: uint) -> VariantInfo {

let ctor_ty = node_id_to_type(cx, ast_variant.node.id);

Expand Down Expand Up @@ -3894,7 +3894,7 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[@VariantInfo] {
node: ast::item_enum(ref enum_definition, _),
_
}, _) => {
let mut last_discriminant: Option<int> = None;
let mut last_discriminant: Option<uint> = None;
@enum_definition.variants.iter().transform(|variant| {

let mut discriminant = match last_discriminant {
Expand All @@ -3904,7 +3904,8 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[@VariantInfo] {

match variant.node.disr_expr {
Some(e) => match const_eval::eval_const_expr_partial(&cx, e) {
Ok(const_eval::const_int(val)) => discriminant = val as int,
Ok(const_eval::const_int(val)) => discriminant = val as uint,
Ok(const_eval::const_uint(val)) => discriminant = val as uint,
Ok(_) => {
cx.sess.span_err(e.span, "expected signed integer constant");
}
Expand Down

0 comments on commit 1c3dc29

Please sign in to comment.