Skip to content

Commit 290f079

Browse files
committed
Frontend bits for #2317, general const-expr classification.
1 parent bf8c773 commit 290f079

File tree

5 files changed

+208
-1
lines changed

5 files changed

+208
-1
lines changed

src/libsyntax/ast_util.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,9 @@ fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
469469
vfn(e.id);
470470
},
471471

472+
visit_expr_post: fn@(_e: @expr) {
473+
},
474+
472475
visit_ty: fn@(t: @ty) {
473476
alt t.node {
474477
ty_path(_, id) {

src/libsyntax/visit.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type visitor<E> =
5555
visit_pat: fn@(@pat, E, vt<E>),
5656
visit_decl: fn@(@decl, E, vt<E>),
5757
visit_expr: fn@(@expr, E, vt<E>),
58+
visit_expr_post: fn@(@expr, E, vt<E>),
5859
visit_ty: fn@(@ty, E, vt<E>),
5960
visit_ty_params: fn@(~[ty_param], E, vt<E>),
6061
visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id, E, vt<E>),
@@ -74,6 +75,7 @@ fn default_visitor<E>() -> visitor<E> {
7475
visit_pat: |a,b,c|visit_pat::<E>(a, b, c),
7576
visit_decl: |a,b,c|visit_decl::<E>(a, b, c),
7677
visit_expr: |a,b,c|visit_expr::<E>(a, b, c),
78+
visit_expr_post: |_a,_b,_c| (),
7779
visit_ty: |a,b,c|skip_ty::<E>(a, b, c),
7880
visit_ty_params: |a,b,c|visit_ty_params::<E>(a, b, c),
7981
visit_fn: |a,b,c,d,e,f,g|visit_fn::<E>(a, b, c, d, e, f, g),
@@ -428,6 +430,7 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
428430
}
429431
expr_mac(mac) { visit_mac(mac, e, v); }
430432
}
433+
v.visit_expr_post(ex, e, v);
431434
}
432435

433436
fn visit_arm<E>(a: arm, e: E, v: vt<E>) {
@@ -451,6 +454,7 @@ type simple_visitor =
451454
visit_pat: fn@(@pat),
452455
visit_decl: fn@(@decl),
453456
visit_expr: fn@(@expr),
457+
visit_expr_post: fn@(@expr),
454458
visit_ty: fn@(@ty),
455459
visit_ty_params: fn@(~[ty_param]),
456460
visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id),
@@ -472,6 +476,7 @@ fn default_simple_visitor() -> simple_visitor {
472476
visit_pat: fn@(_p: @pat) { },
473477
visit_decl: fn@(_d: @decl) { },
474478
visit_expr: fn@(_e: @expr) { },
479+
visit_expr_post: fn@(_e: @expr) { },
475480
visit_ty: simple_ignore_ty,
476481
visit_ty_params: fn@(_ps: ~[ty_param]) {},
477482
visit_fn: fn@(_fk: fn_kind, _d: fn_decl, _b: blk, _sp: span,
@@ -529,6 +534,9 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
529534
f(ex);
530535
visit_expr(ex, e, v);
531536
}
537+
fn v_expr_post(f: fn@(@expr), ex: @expr, &&_e: (), _v: vt<()>) {
538+
f(ex);
539+
}
532540
fn v_ty(f: fn@(@ty), ty: @ty, &&e: (), v: vt<()>) {
533541
f(ty);
534542
visit_ty(ty, e, v);
@@ -578,6 +586,8 @@ fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
578586
visit_pat: |a,b,c|v_pat(v.visit_pat, a, b, c),
579587
visit_decl: |a,b,c|v_decl(v.visit_decl, a, b, c),
580588
visit_expr: |a,b,c|v_expr(v.visit_expr, a, b, c),
589+
visit_expr_post: |a,b,c| v_expr_post(v.visit_expr_post,
590+
a, b, c),
581591
visit_ty: visit_ty,
582592
visit_ty_params: |a,b,c|
583593
v_ty_params(v.visit_ty_params, a, b, c),

src/rustc/driver/driver.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
197197
impl_map,
198198
trait_map,
199199
crate));
200+
// These next two const passes can probably be merged
201+
time(time_passes, ~"const marking", ||
202+
middle::const_eval::process_crate(crate, def_map, ty_cx));
200203

201204
time(time_passes, ~"const checking", ||
202205
middle::check_const::check_crate(sess, crate, ast_map, def_map,

src/rustc/middle/const_eval.rs

Lines changed: 188 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,182 @@
1-
import syntax::ast::*;
1+
import syntax::{ast,ast_util,visit};
2+
import ast::*;
3+
4+
//
5+
// This pass classifies expressions by their constant-ness.
6+
//
7+
// Constant-ness comes in 3 flavours:
8+
//
9+
// - Integer-constants: can be evaluated by the frontend all the way down
10+
// to their actual value. They are used in a few places (enum
11+
// discriminants, switch arms) and are a subset of
12+
// general-constants. They cover all the integer and integer-ish
13+
// literals (nil, bool, int, uint, char, iNN, uNN) and all integer
14+
// operators and copies applied to them.
15+
//
16+
// - General-constants: can be evaluated by LLVM but not necessarily by
17+
// the frontend; usually due to reliance on target-specific stuff such
18+
// as "where in memory the value goes" or "what floating point mode the
19+
// target uses". This _includes_ integer-constants, plus the following
20+
// constructors:
21+
//
22+
// fixed-size vectors and strings: []/_ and ""/_
23+
// vector and string slices: &[] and &""
24+
// tuples: (,)
25+
// records: {...}
26+
// enums: foo(...)
27+
// floating point literals and operators
28+
// & and * pointers
29+
// copies of general constants
30+
//
31+
// (in theory, probably not at first: if/alt on integer-const
32+
// conditions / descriminants)
33+
//
34+
// - Non-constants: everything else.
35+
//
36+
37+
enum constness {
38+
integral_const,
39+
general_const,
40+
non_const
41+
}
42+
43+
fn join(a: constness, b: constness) -> constness {
44+
alt (a,b) {
45+
(integral_const, integral_const) { integral_const }
46+
(integral_const, general_const)
47+
| (general_const, integral_const)
48+
| (general_const, general_const) { general_const }
49+
_ { non_const }
50+
}
51+
}
52+
53+
fn join_all(cs: &[constness]) -> constness {
54+
vec::foldl(integral_const, cs, join)
55+
}
56+
57+
fn classify(e: @expr,
58+
def_map: resolve3::DefMap,
59+
tcx: ty::ctxt) -> constness {
60+
let did = ast_util::local_def(e.id);
61+
alt tcx.ccache.find(did) {
62+
some(x) { x }
63+
none {
64+
let cn =
65+
alt e.node {
66+
ast::expr_lit(lit) {
67+
alt lit.node {
68+
ast::lit_str(*) |
69+
ast::lit_float(*) { general_const }
70+
_ { integral_const }
71+
}
72+
}
73+
74+
ast::expr_copy(inner) |
75+
ast::expr_unary(_, inner) {
76+
classify(inner, def_map, tcx)
77+
}
78+
79+
ast::expr_binary(_, a, b) {
80+
join(classify(a, def_map, tcx),
81+
classify(b, def_map, tcx))
82+
}
83+
84+
ast::expr_tup(es) |
85+
ast::expr_vec(es, ast::m_imm) {
86+
join_all(vec::map(es, |e| classify(e, def_map, tcx)))
87+
}
88+
89+
ast::expr_vstore(e, vstore) {
90+
alt vstore {
91+
ast::vstore_fixed(_) |
92+
ast::vstore_slice(_) { classify(e, def_map, tcx) }
93+
ast::vstore_uniq |
94+
ast::vstore_box { non_const }
95+
}
96+
}
97+
98+
ast::expr_rec(fs, none) {
99+
let cs = do vec::map(fs) |f| {
100+
if f.node.mutbl == ast::m_imm {
101+
classify(f.node.expr, def_map, tcx)
102+
} else {
103+
non_const
104+
}
105+
};
106+
join_all(cs)
107+
}
108+
109+
ast::expr_cast(base, _) {
110+
let ty = ty::expr_ty(tcx, e);
111+
let base = classify(base, def_map, tcx);
112+
if ty::type_is_integral(ty) {
113+
join(integral_const, base)
114+
} else if ty::type_is_fp(ty) {
115+
join(general_const, base)
116+
} else {
117+
non_const
118+
}
119+
}
120+
121+
ast::expr_field(base, _, _) {
122+
classify(base, def_map, tcx)
123+
}
124+
125+
ast::expr_index(base, idx) {
126+
join(classify(base, def_map, tcx),
127+
classify(idx, def_map, tcx))
128+
}
129+
130+
ast::expr_addr_of(ast::m_imm, base) {
131+
classify(base, def_map, tcx)
132+
}
133+
134+
// FIXME: #1272, we can probably do something CCI-ish
135+
// surrounding nonlocal constants. But we don't yet.
136+
ast::expr_path(_) {
137+
alt def_map.find(e.id) {
138+
some(ast::def_const(def_id)) {
139+
if ast_util::is_local(def_id) {
140+
let ty = ty::expr_ty(tcx, e);
141+
if ty::type_is_integral(ty) {
142+
integral_const
143+
} else {
144+
general_const
145+
}
146+
} else {
147+
non_const
148+
}
149+
}
150+
some(_) {
151+
non_const
152+
}
153+
none {
154+
tcx.sess.span_bug(e.span,
155+
~"unknown path when \
156+
classifying constants");
157+
}
158+
}
159+
}
160+
161+
_ { non_const }
162+
};
163+
tcx.ccache.insert(did, cn);
164+
cn
165+
}
166+
}
167+
}
168+
169+
fn process_crate(crate: @ast::crate,
170+
def_map: resolve3::DefMap,
171+
tcx: ty::ctxt) {
172+
let v = visit::mk_simple_visitor(@{
173+
visit_expr_post: |e| { classify(e, def_map, tcx); }
174+
with *visit::default_simple_visitor()
175+
});
176+
visit::visit_crate(*crate, (), v);
177+
tcx.sess.abort_if_errors();
178+
}
179+
2180

3181
// FIXME (#33): this doesn't handle big integer/float literals correctly
4182
// (nor does the rest of our literal handling).
@@ -175,3 +353,12 @@ fn lit_expr_eq(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> bool {
175353
fn lit_eq(a: @lit, b: @lit) -> bool {
176354
compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0
177355
}
356+
357+
358+
// Local Variables:
359+
// mode: rust
360+
// fill-column: 78;
361+
// indent-tabs-mode: nil
362+
// c-basic-offset: 4
363+
// buffer-file-coding-system: utf-8-unix
364+
// End:

src/rustc/middle/ty.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ type ctxt =
249249
freevars: freevars::freevar_map,
250250
tcache: type_cache,
251251
rcache: creader_cache,
252+
ccache: constness_cache,
252253
short_names_cache: hashmap<t, @~str>,
253254
needs_drop_cache: hashmap<t, bool>,
254255
needs_unwind_cleanup_cache: hashmap<t, bool>,
@@ -534,6 +535,8 @@ type ty_param_bounds_and_ty = {bounds: @~[param_bounds],
534535

535536
type type_cache = hashmap<ast::def_id, ty_param_bounds_and_ty>;
536537

538+
type constness_cache = hashmap<ast::def_id, const_eval::constness>;
539+
537540
type node_type_table = @smallintmap::smallintmap<t>;
538541

539542
fn mk_rcache() -> creader_cache {
@@ -581,6 +584,7 @@ fn mk_ctxt(s: session::session,
581584
freevars: freevars,
582585
tcache: ast_util::new_def_hash(),
583586
rcache: mk_rcache(),
587+
ccache: ast_util::new_def_hash(),
584588
short_names_cache: new_ty_hash(),
585589
needs_drop_cache: new_ty_hash(),
586590
needs_unwind_cleanup_cache: new_ty_hash(),

0 commit comments

Comments
 (0)