Skip to content

Commit 52fb0fc

Browse files
committed
Check repr attribute consistency at check time, not translation.
Note that raising an error during trans doesn't stop the compile or cause rustc to exit with a failure status, currently, so this is of more than cosmetic importance.
1 parent 8811bfa commit 52fb0fc

File tree

3 files changed

+63
-17
lines changed

3 files changed

+63
-17
lines changed

src/librustc/middle/trans/adt.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
150150

151151
if cases.len() == 0 {
152152
// Uninhabitable; represent as unit
153+
assert_eq!(hint, attr::ReprAny);
153154
return Univariant(mk_struct(cx, [], false), false);
154155
}
155156

@@ -165,13 +166,6 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
165166
return mk_cenum(cx, hint, &bounds);
166167
}
167168

168-
if cases.len() == 1 {
169-
// Equivalent to a struct/tuple/newtype.
170-
// FIXME: should this conflict with a discriminant size hint?
171-
assert_eq!(cases[0].discr, 0);
172-
return Univariant(mk_struct(cx, cases[0].tys, false), false)
173-
}
174-
175169
// Since there's at least one
176170
// non-empty body, explicit discriminants should have
177171
// been rejected by a checker before this point.
@@ -181,8 +175,14 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
181175
ty::item_path_str(cx.tcx, def_id)))
182176
}
183177

184-
if cases.len() == 2 {
185-
// FIXME: disable if size hint present?
178+
if cases.len() == 1 {
179+
// Equivalent to a struct/tuple/newtype.
180+
assert_eq!(hint, attr::ReprAny);
181+
return Univariant(mk_struct(cx, cases[0].tys, false), false)
182+
}
183+
184+
if cases.len() == 2 && hint == attr::ReprAny {
185+
// Nullable pointer optimization
186186
let mut discr = 0;
187187
while discr < 2 {
188188
if cases[1 - discr].is_zerolen(cx) {
@@ -205,7 +205,6 @@ fn represent_type_uncached(cx: &mut CrateContext, t: ty::t) -> Repr {
205205
}
206206

207207
// The general case.
208-
let hint = ty::lookup_repr_hint(cx.tcx, def_id);
209208
assert!((cases.len() - 1) as i64 >= 0);
210209
let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64,
211210
slo: 0, shi: (cases.len() - 1) as i64 };
@@ -307,7 +306,7 @@ fn range_to_inttype(cx: &mut CrateContext, hint: Hint, bounds: &IntBounds) -> In
307306
match hint {
308307
attr::ReprInt(span, ity) => {
309308
if !bounds_usable(cx, ity, bounds) {
310-
cx.sess.span_err(span, "representation hint insufficient for discriminant range")
309+
cx.sess.span_bug(span, "representation hint insufficient for discriminant range")
311310
}
312311
return ity;
313312
}
@@ -365,6 +364,7 @@ fn ty_of_inttype(ity: IntType) -> ty::t {
365364
}
366365
}
367366

367+
368368
/**
369369
* Returns the fields of a struct for the given representation.
370370
* All nominal types are LLVM structs, in order to be able to use

src/librustc/middle/typeck/check/mod.rs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ use syntax::ast;
122122
use syntax::ast_map;
123123
use syntax::ast_util::local_def;
124124
use syntax::ast_util;
125+
use syntax::attr;
125126
use syntax::codemap::Span;
126127
use syntax::codemap;
127128
use syntax::opt_vec::OptVec;
@@ -3160,9 +3161,38 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt,
31603161
sp: Span,
31613162
vs: &[ast::variant],
31623163
id: ast::NodeId) {
3164+
3165+
fn disr_in_range(ccx: @mut CrateCtxt,
3166+
ty: attr::IntType,
3167+
disr: ty::Disr) -> bool {
3168+
fn uint_in_range(ccx: @mut CrateCtxt, ty: ast::uint_ty, disr: ty::Disr) -> bool {
3169+
match ty {
3170+
ast::ty_u8 => disr as u8 as Disr == disr,
3171+
ast::ty_u16 => disr as u16 as Disr == disr,
3172+
ast::ty_u32 => disr as u32 as Disr == disr,
3173+
ast::ty_u64 => disr as u64 as Disr == disr,
3174+
ast::ty_u => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
3175+
}
3176+
}
3177+
fn int_in_range(ccx: @mut CrateCtxt, ty: ast::int_ty, disr: ty::Disr) -> bool {
3178+
match ty {
3179+
ast::ty_i8 => disr as i8 as Disr == disr,
3180+
ast::ty_i16 => disr as i16 as Disr == disr,
3181+
ast::ty_i32 => disr as i32 as Disr == disr,
3182+
ast::ty_i64 => disr as i64 as Disr == disr,
3183+
ast::ty_i => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
3184+
}
3185+
}
3186+
match ty {
3187+
attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
3188+
attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
3189+
}
3190+
}
3191+
31633192
fn do_check(ccx: @mut CrateCtxt,
31643193
vs: &[ast::variant],
3165-
id: ast::NodeId)
3194+
id: ast::NodeId,
3195+
hint: attr::ReprAttr)
31663196
-> ~[@ty::VariantInfo] {
31673197

31683198
let rty = ty::node_id_to_type(ccx.tcx, id);
@@ -3204,9 +3234,20 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt,
32043234
None => ()
32053235
};
32063236

3207-
// Check for duplicate discriminator values
3237+
// Check for duplicate discriminant values
32083238
if disr_vals.contains(&current_disr_val) {
3209-
ccx.tcx.sess.span_err(v.span, "discriminator value already exists");
3239+
ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
3240+
}
3241+
// Check for unrepresentable discriminant values
3242+
match hint {
3243+
attr::ReprAny | attr::ReprExtern => (),
3244+
attr::ReprInt(sp, ity) => {
3245+
if !disr_in_range(ccx, ity, current_disr_val) {
3246+
ccx.tcx.sess.span_err(v.span,
3247+
"discriminant value outside specified type");
3248+
ccx.tcx.sess.span_note(sp, "discriminant type specified here");
3249+
}
3250+
}
32103251
}
32113252
disr_vals.push(current_disr_val);
32123253

@@ -3220,8 +3261,13 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt,
32203261
}
32213262

32223263
let rty = ty::node_id_to_type(ccx.tcx, id);
3264+
let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { crate: ast::LOCAL_CRATE, node: id });
3265+
if hint != attr::ReprAny && vs.len() <= 1 {
3266+
ccx.tcx.sess.span_err(sp, fmt!("unsupported representation for %svariant enum",
3267+
if vs.len() == 1 { "uni" } else { "zero-" }))
3268+
}
32233269

3224-
let variants = do_check(ccx, vs, id);
3270+
let variants = do_check(ccx, vs, id, hint);
32253271

32263272
// cache so that ty::enum_variants won't repeat this work
32273273
ccx.tcx.enum_var_cache.insert(local_def(id), @variants);

src/test/compile-fail/tag-variant-disr-dup.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//error-pattern:discriminator value already exists
11+
//error-pattern:discriminant value already exists
1212

1313
// black and white have the same discriminator value ...
1414

@@ -20,4 +20,4 @@ enum color {
2020
white = 0x000000,
2121
}
2222

23-
fn main() { }
23+
fn main() { }

0 commit comments

Comments
 (0)