Skip to content

Commit e1c50c4

Browse files
kevinamarijnh
authored andcommitted
Don't evaluate discriminator value constants when parsing.
Remove disr_val from ast::variant_ and always use ty::variant_info when the value is needed. Move what was done during parsing into other passes, primary typeck.rs. This move also correctly type checks the disr. value expression; thus, fixing rustc --pretty=typed when disr. values are used.
1 parent edf11eb commit e1c50c4

File tree

10 files changed

+106
-51
lines changed

10 files changed

+106
-51
lines changed

src/comp/metadata/encoder.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ fn encode_tag_variant_info(ecx: @encode_ctxt, ebml_w: ebml::writer,
232232
id: node_id, variants: [variant],
233233
&index: [entry<int>], ty_params: [ty_param]) {
234234
let disr_val = 0;
235+
let i = 0;
236+
let vi = ty::tag_variants(ecx.ccx.tcx, {crate: local_crate, node: id});
235237
for variant: variant in variants {
236238
index += [{val: variant.node.id, pos: ebml_w.writer.tell()}];
237239
ebml::start_tag(ebml_w, tag_items_data_item);
@@ -244,13 +246,14 @@ fn encode_tag_variant_info(ecx: @encode_ctxt, ebml_w: ebml::writer,
244246
encode_symbol(ecx, ebml_w, variant.node.id);
245247
}
246248
encode_discriminant(ecx, ebml_w, variant.node.id);
247-
if variant.node.disr_val != disr_val {
248-
encode_disr_val(ecx, ebml_w, variant.node.disr_val);
249-
disr_val = variant.node.disr_val;
249+
if vi[i].disr_val != disr_val {
250+
encode_disr_val(ecx, ebml_w, vi[i].disr_val);
251+
disr_val = vi[i].disr_val;
250252
}
251253
encode_type_param_bounds(ebml_w, ecx, ty_params);
252254
ebml::end_tag(ebml_w);
253255
disr_val += 1;
256+
i += 1;
254257
}
255258
}
256259

src/comp/middle/check_const.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ fn check_crate(sess: session, crate: @crate) {
1515
fn check_item(it: @item, &&_is_const: bool, v: visit::vt<bool>) {
1616
alt it.node {
1717
item_const(_, ex) { v.visit_expr(ex, true, v); }
18+
item_tag(vs, _) {
19+
for var in vs {
20+
option::may(var.node.disr_expr) {|ex|
21+
v.visit_expr(ex, true, v);
22+
}
23+
}
24+
}
1825
_ { visit::visit_item(it, false, v); }
1926
}
2027
}

src/comp/middle/trans.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4543,7 +4543,7 @@ fn trans_res_ctor(cx: @local_ctxt, sp: span, dtor: ast::fn_decl,
45434543

45444544

45454545
fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
4546-
variant: ast::variant, is_degen: bool,
4546+
variant: ast::variant, disr: int, is_degen: bool,
45474547
ty_params: [ast::ty_param]) {
45484548
let ccx = cx.ccx;
45494549

@@ -4593,7 +4593,7 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
45934593
let lltagptr =
45944594
PointerCast(bcx, fcx.llretptr, T_opaque_tag_ptr(ccx));
45954595
let lldiscrimptr = GEPi(bcx, lltagptr, [0, 0]);
4596-
Store(bcx, C_int(ccx, variant.node.disr_val), lldiscrimptr);
4596+
Store(bcx, C_int(ccx, disr), lldiscrimptr);
45974597
GEPi(bcx, lltagptr, [0, 1])
45984598
};
45994599
i = 0u;
@@ -4938,8 +4938,13 @@ fn trans_item(cx: @local_ctxt, item: ast::item) {
49384938
ast::item_tag(variants, tps) {
49394939
let sub_cx = extend_path(cx, item.ident);
49404940
let degen = vec::len(variants) == 1u;
4941+
let vi = ty::tag_variants(cx.ccx.tcx, {crate: ast::local_crate,
4942+
node: item.id});
4943+
let i = 0;
49414944
for variant: ast::variant in variants {
4942-
trans_tag_variant(sub_cx, item.id, variant, degen, tps);
4945+
trans_tag_variant(sub_cx, item.id, variant,
4946+
vi[i].disr_val, degen, tps);
4947+
i += 1;
49434948
}
49444949
}
49454950
ast::item_const(_, expr) { trans_const(cx.ccx, expr, item.id); }
@@ -5268,10 +5273,13 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str],
52685273
visit::visit_item(it, new_pt, v);
52695274
alt it.node {
52705275
ast::item_tag(variants, _) {
5276+
let vi = ty::tag_variants(ccx.tcx, {crate: ast::local_crate,
5277+
node: it.id});
5278+
let i = 0;
52715279
for variant in variants {
52725280
let p = new_pt + [variant.node.name, "discrim"];
52735281
let s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
5274-
let disr_val = variant.node.disr_val;
5282+
let disr_val = vi[i].disr_val;
52755283
let discrim_gvar = str::as_buf(s, {|buf|
52765284
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
52775285
});
@@ -5280,6 +5288,7 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item, &&pt: [str],
52805288
ccx.discrims.insert(
52815289
ast_util::local_def(variant.node.id), discrim_gvar);
52825290
ccx.discrim_symbols.insert(variant.node.id, s);
5291+
i += 1;
52835292
}
52845293
}
52855294
ast::item_impl(tps, some(@{node: ast::ty_path(_, id), _}), _, ms) {

src/comp/middle/ty.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2631,17 +2631,30 @@ fn tag_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] {
26312631
let result = if ast::local_crate != id.crate {
26322632
@csearch::get_tag_variants(cx, id)
26332633
} else {
2634+
// FIXME: Now that the variants are run through the type checker (to
2635+
// check the disr_expr if one exists), this code should likely be
2636+
// moved there to avoid having to call eval_const_expr twice
26342637
alt cx.items.get(id.node) {
26352638
ast_map::node_item(@{node: ast::item_tag(variants, _), _}) {
2639+
let disr_val = -1;
26362640
@vec::map(variants, {|variant|
26372641
let ctor_ty = node_id_to_monotype(cx, variant.node.id);
26382642
let arg_tys = if vec::len(variant.node.args) > 0u {
26392643
vec::map(ty_fn_args(cx, ctor_ty), {|a| a.ty})
26402644
} else { [] };
2645+
alt variant.node.disr_expr {
2646+
some (ex) {
2647+
// FIXME: issue #1417
2648+
disr_val = alt syntax::ast_util::eval_const_expr(ex) {
2649+
ast_util::const_int(val) {val as int}
2650+
}
2651+
}
2652+
_ {disr_val += 1;}
2653+
}
26412654
@{args: arg_tys,
26422655
ctor_ty: ctor_ty,
26432656
id: ast_util::local_def(variant.node.id),
2644-
disr_val: variant.node.disr_val
2657+
disr_val: disr_val
26452658
}
26462659
})
26472660
}

src/comp/middle/typeck.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2461,6 +2461,55 @@ fn check_const(ccx: @crate_ctxt, _sp: span, e: @ast::expr, id: ast::node_id) {
24612461
demand::simple(fcx, e.span, declty, cty);
24622462
}
24632463

2464+
fn check_tag_variants(ccx: @crate_ctxt, _sp: span, vs: [ast::variant],
2465+
id: ast::node_id) {
2466+
// FIXME: this is kinda a kludge; we manufacture a fake function context
2467+
// and statement context for checking the initializer expression.
2468+
let rty = node_id_to_type(ccx.tcx, id);
2469+
let fixups: [ast::node_id] = [];
2470+
let fcx: @fn_ctxt =
2471+
@{ret_ty: rty,
2472+
purity: ast::pure_fn,
2473+
proto: ast::proto_box,
2474+
var_bindings: ty::unify::mk_var_bindings(),
2475+
locals: new_int_hash::<int>(),
2476+
next_var_id: @mutable 0,
2477+
mutable fixups: fixups,
2478+
ccx: ccx};
2479+
let disr_vals: [int] = [];
2480+
let disr_val = 0;
2481+
for v in vs {
2482+
alt v.node.disr_expr {
2483+
some(e) {
2484+
check_expr(fcx, e);
2485+
let cty = expr_ty(fcx.ccx.tcx, e);
2486+
let declty =ty::mk_int(fcx.ccx.tcx);
2487+
demand::simple(fcx, e.span, declty, cty);
2488+
// FIXME: issue #1417
2489+
// Also, check_expr (from check_const pass) doesn't guarantee that
2490+
// the expression in an form that eval_const_expr, so we may still
2491+
// get an internal compiler error
2492+
alt syntax::ast_util::eval_const_expr(e) {
2493+
syntax::ast_util::const_int(val) {
2494+
disr_val = val as int;
2495+
}
2496+
_ {
2497+
ccx.tcx.sess.span_err(e.span,
2498+
"expected signed integer constant");
2499+
}
2500+
}
2501+
}
2502+
_ {}
2503+
}
2504+
if vec::member(disr_val, disr_vals) {
2505+
ccx.tcx.sess.span_err(v.span,
2506+
"discriminator value already exists.");
2507+
}
2508+
disr_vals += [disr_val];
2509+
disr_val += 1;
2510+
}
2511+
}
2512+
24642513
// A generic function for checking the pred in a check
24652514
// or if-check
24662515
fn check_pred_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool {
@@ -2632,6 +2681,7 @@ fn check_method(ccx: @crate_ctxt, method: @ast::method) {
26322681
fn check_item(ccx: @crate_ctxt, it: @ast::item) {
26332682
alt it.node {
26342683
ast::item_const(_, e) { check_const(ccx, it.span, e, it.id); }
2684+
ast::item_tag(vs, _) { check_tag_variants(ccx, it.span, vs, it.id); }
26352685
ast::item_fn(decl, tps, body) {
26362686
check_fn(ccx, ast::proto_bare, decl, body, it.id, none);
26372687
}

src/comp/syntax/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ type native_mod =
409409
type variant_arg = {ty: @ty, id: node_id};
410410

411411
type variant_ = {name: ident, args: [variant_arg], id: node_id,
412-
disr_val: int, disr_expr: option::t<@expr>};
412+
disr_expr: option::t<@expr>};
413413

414414
type variant = spanned<variant_>;
415415

src/comp/syntax/ast_util.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,7 @@ tag const_val {
241241
const_str(str);
242242
}
243243

244-
// FIXME (#1417): any function that uses this function should likely be moved
245-
// into the middle end
244+
// FIXME: issue #1417
246245
fn eval_const_expr(e: @expr) -> const_val {
247246
fn fromb(b: bool) -> const_val { const_int(b as i64) }
248247
alt e.node {

src/comp/syntax/fold.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -432,21 +432,12 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
432432
}
433433
let fold_variant_arg = bind fold_variant_arg_(_, fld);
434434
let args = vec::map(v.args, fold_variant_arg);
435-
let (de, dv) = alt v.disr_expr {
436-
some(e) {
437-
let de = fld.fold_expr(e);
438-
// FIXME (#1417): see parser.rs
439-
let dv = alt syntax::ast_util::eval_const_expr(e) {
440-
ast_util::const_int(val) {
441-
val as int
442-
}
443-
};
444-
(some(de), dv)
445-
}
446-
none. { (none, v.disr_val) }
435+
let de = alt v.disr_expr {
436+
some(e) {some(fld.fold_expr(e))}
437+
none. {none}
447438
};
448439
ret {name: v.name, args: args, id: v.id,
449-
disr_val: dv, disr_expr: de};
440+
disr_expr: de};
450441
}
451442

452443
fn noop_fold_ident(&&i: ident, _fld: ast_fold) -> ident { ret i; }

src/comp/syntax/parse/parser.rs

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,15 +2023,13 @@ fn parse_item_tag(p: parser, attrs: [ast::attribute]) -> @ast::item {
20232023
{name: id,
20242024
args: [{ty: ty, id: p.get_id()}],
20252025
id: p.get_id(),
2026-
disr_val: 0,
20272026
disr_expr: none});
20282027
ret mk_item(p, lo, ty.span.hi, id,
20292028
ast::item_tag([variant], ty_params), attrs);
20302029
}
20312030
expect(p, token::LBRACE);
20322031
let all_nullary = true;
20332032
let have_disr = false;
2034-
let disr_val = 0;
20352033
while p.token != token::RBRACE {
20362034
let tok = p.token;
20372035
alt tok {
@@ -2056,38 +2054,15 @@ fn parse_item_tag(p: parser, attrs: [ast::attribute]) -> @ast::item {
20562054
token::EQ. {
20572055
have_disr = true;
20582056
p.bump();
2059-
let e = parse_expr(p);
2060-
// FIXME: eval_const_expr does no error checking, nor do I.
2061-
// Also, the parser is not the right place to do this; likely
2062-
// somewhere in the middle end so that constants can be
2063-
// refereed to, even if they are after the declaration for the
2064-
// type. Finally, eval_const_expr probably shouldn't exist as
2065-
// it Graydon puts it: "[I] am a little worried at its
2066-
// presence since it quasi-duplicates stuff that trans should
2067-
// probably be doing." (See issue #1417)
2068-
alt syntax::ast_util::eval_const_expr(e) {
2069-
syntax::ast_util::const_int(val) {
2070-
// FIXME: check that value is in range
2071-
disr_val = val as int;
2072-
}
2073-
}
2074-
if option::is_some
2075-
(vec::find
2076-
(variants, {|v| v.node.disr_val == disr_val}))
2077-
{
2078-
p.fatal("discriminator value " + /* str(disr_val) + */
2079-
"already exists.");
2080-
}
2081-
disr_expr = some(e);
2057+
disr_expr = some(parse_expr(p));
20822058
}
20832059
_ {/* empty */ }
20842060
}
20852061
expect(p, token::SEMI);
20862062
p.get_id();
20872063
let vr = {name: p.get_str(name), args: args, id: p.get_id(),
2088-
disr_val: disr_val, disr_expr: disr_expr};
2064+
disr_expr: disr_expr};
20892065
variants += [spanned(vlo, vhi, vr)];
2090-
disr_val += 1;
20912066
}
20922067
token::RBRACE. {/* empty */ }
20932068
_ {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//error-pattern: mismatched types
2+
3+
tag color {
4+
red = 1u;
5+
blue = 2;
6+
}
7+
8+
fn main() {}

0 commit comments

Comments
 (0)