Frontend bits for #2317, general const-expr classification.
This commit is contained in:
parent
bf8c773936
commit
290f079474
@ -469,6 +469,9 @@ fn id_visitor(vfn: fn@(node_id)) -> visit::vt<()> {
|
||||
vfn(e.id);
|
||||
},
|
||||
|
||||
visit_expr_post: fn@(_e: @expr) {
|
||||
},
|
||||
|
||||
visit_ty: fn@(t: @ty) {
|
||||
alt t.node {
|
||||
ty_path(_, id) {
|
||||
|
@ -55,6 +55,7 @@ fn tps_of_fn(fk: fn_kind) -> ~[ty_param] {
|
||||
visit_pat: fn@(@pat, E, vt<E>),
|
||||
visit_decl: fn@(@decl, E, vt<E>),
|
||||
visit_expr: fn@(@expr, E, vt<E>),
|
||||
visit_expr_post: fn@(@expr, E, vt<E>),
|
||||
visit_ty: fn@(@ty, E, vt<E>),
|
||||
visit_ty_params: fn@(~[ty_param], E, vt<E>),
|
||||
visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id, E, vt<E>),
|
||||
@ -74,6 +75,7 @@ fn default_visitor<E>() -> visitor<E> {
|
||||
visit_pat: |a,b,c|visit_pat::<E>(a, b, c),
|
||||
visit_decl: |a,b,c|visit_decl::<E>(a, b, c),
|
||||
visit_expr: |a,b,c|visit_expr::<E>(a, b, c),
|
||||
visit_expr_post: |_a,_b,_c| (),
|
||||
visit_ty: |a,b,c|skip_ty::<E>(a, b, c),
|
||||
visit_ty_params: |a,b,c|visit_ty_params::<E>(a, b, c),
|
||||
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>) {
|
||||
}
|
||||
expr_mac(mac) { visit_mac(mac, e, v); }
|
||||
}
|
||||
v.visit_expr_post(ex, e, v);
|
||||
}
|
||||
|
||||
fn visit_arm<E>(a: arm, e: E, v: vt<E>) {
|
||||
@ -451,6 +454,7 @@ fn visit_arm<E>(a: arm, e: E, v: vt<E>) {
|
||||
visit_pat: fn@(@pat),
|
||||
visit_decl: fn@(@decl),
|
||||
visit_expr: fn@(@expr),
|
||||
visit_expr_post: fn@(@expr),
|
||||
visit_ty: fn@(@ty),
|
||||
visit_ty_params: fn@(~[ty_param]),
|
||||
visit_fn: fn@(fn_kind, fn_decl, blk, span, node_id),
|
||||
@ -472,6 +476,7 @@ fn default_simple_visitor() -> simple_visitor {
|
||||
visit_pat: fn@(_p: @pat) { },
|
||||
visit_decl: fn@(_d: @decl) { },
|
||||
visit_expr: fn@(_e: @expr) { },
|
||||
visit_expr_post: fn@(_e: @expr) { },
|
||||
visit_ty: simple_ignore_ty,
|
||||
visit_ty_params: fn@(_ps: ~[ty_param]) {},
|
||||
visit_fn: fn@(_fk: fn_kind, _d: fn_decl, _b: blk, _sp: span,
|
||||
@ -529,6 +534,9 @@ fn v_expr(f: fn@(@expr), ex: @expr, &&e: (), v: vt<()>) {
|
||||
f(ex);
|
||||
visit_expr(ex, e, v);
|
||||
}
|
||||
fn v_expr_post(f: fn@(@expr), ex: @expr, &&_e: (), _v: vt<()>) {
|
||||
f(ex);
|
||||
}
|
||||
fn v_ty(f: fn@(@ty), ty: @ty, &&e: (), v: vt<()>) {
|
||||
f(ty);
|
||||
visit_ty(ty, e, v);
|
||||
@ -578,6 +586,8 @@ fn v_class_item(f: fn@(@class_member),
|
||||
visit_pat: |a,b,c|v_pat(v.visit_pat, a, b, c),
|
||||
visit_decl: |a,b,c|v_decl(v.visit_decl, a, b, c),
|
||||
visit_expr: |a,b,c|v_expr(v.visit_expr, a, b, c),
|
||||
visit_expr_post: |a,b,c| v_expr_post(v.visit_expr_post,
|
||||
a, b, c),
|
||||
visit_ty: visit_ty,
|
||||
visit_ty_params: |a,b,c|
|
||||
v_ty_params(v.visit_ty_params, a, b, c),
|
||||
|
@ -197,6 +197,9 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
|
||||
impl_map,
|
||||
trait_map,
|
||||
crate));
|
||||
// These next two const passes can probably be merged
|
||||
time(time_passes, ~"const marking", ||
|
||||
middle::const_eval::process_crate(crate, def_map, ty_cx));
|
||||
|
||||
time(time_passes, ~"const checking", ||
|
||||
middle::check_const::check_crate(sess, crate, ast_map, def_map,
|
||||
|
@ -1,4 +1,182 @@
|
||||
import syntax::ast::*;
|
||||
import syntax::{ast,ast_util,visit};
|
||||
import ast::*;
|
||||
|
||||
//
|
||||
// This pass classifies expressions by their constant-ness.
|
||||
//
|
||||
// Constant-ness comes in 3 flavours:
|
||||
//
|
||||
// - Integer-constants: can be evaluated by the frontend all the way down
|
||||
// to their actual value. They are used in a few places (enum
|
||||
// discriminants, switch arms) and are a subset of
|
||||
// general-constants. They cover all the integer and integer-ish
|
||||
// literals (nil, bool, int, uint, char, iNN, uNN) and all integer
|
||||
// operators and copies applied to them.
|
||||
//
|
||||
// - General-constants: can be evaluated by LLVM but not necessarily by
|
||||
// the frontend; usually due to reliance on target-specific stuff such
|
||||
// as "where in memory the value goes" or "what floating point mode the
|
||||
// target uses". This _includes_ integer-constants, plus the following
|
||||
// constructors:
|
||||
//
|
||||
// fixed-size vectors and strings: []/_ and ""/_
|
||||
// vector and string slices: &[] and &""
|
||||
// tuples: (,)
|
||||
// records: {...}
|
||||
// enums: foo(...)
|
||||
// floating point literals and operators
|
||||
// & and * pointers
|
||||
// copies of general constants
|
||||
//
|
||||
// (in theory, probably not at first: if/alt on integer-const
|
||||
// conditions / descriminants)
|
||||
//
|
||||
// - Non-constants: everything else.
|
||||
//
|
||||
|
||||
enum constness {
|
||||
integral_const,
|
||||
general_const,
|
||||
non_const
|
||||
}
|
||||
|
||||
fn join(a: constness, b: constness) -> constness {
|
||||
alt (a,b) {
|
||||
(integral_const, integral_const) { integral_const }
|
||||
(integral_const, general_const)
|
||||
| (general_const, integral_const)
|
||||
| (general_const, general_const) { general_const }
|
||||
_ { non_const }
|
||||
}
|
||||
}
|
||||
|
||||
fn join_all(cs: &[constness]) -> constness {
|
||||
vec::foldl(integral_const, cs, join)
|
||||
}
|
||||
|
||||
fn classify(e: @expr,
|
||||
def_map: resolve3::DefMap,
|
||||
tcx: ty::ctxt) -> constness {
|
||||
let did = ast_util::local_def(e.id);
|
||||
alt tcx.ccache.find(did) {
|
||||
some(x) { x }
|
||||
none {
|
||||
let cn =
|
||||
alt e.node {
|
||||
ast::expr_lit(lit) {
|
||||
alt lit.node {
|
||||
ast::lit_str(*) |
|
||||
ast::lit_float(*) { general_const }
|
||||
_ { integral_const }
|
||||
}
|
||||
}
|
||||
|
||||
ast::expr_copy(inner) |
|
||||
ast::expr_unary(_, inner) {
|
||||
classify(inner, def_map, tcx)
|
||||
}
|
||||
|
||||
ast::expr_binary(_, a, b) {
|
||||
join(classify(a, def_map, tcx),
|
||||
classify(b, def_map, tcx))
|
||||
}
|
||||
|
||||
ast::expr_tup(es) |
|
||||
ast::expr_vec(es, ast::m_imm) {
|
||||
join_all(vec::map(es, |e| classify(e, def_map, tcx)))
|
||||
}
|
||||
|
||||
ast::expr_vstore(e, vstore) {
|
||||
alt vstore {
|
||||
ast::vstore_fixed(_) |
|
||||
ast::vstore_slice(_) { classify(e, def_map, tcx) }
|
||||
ast::vstore_uniq |
|
||||
ast::vstore_box { non_const }
|
||||
}
|
||||
}
|
||||
|
||||
ast::expr_rec(fs, none) {
|
||||
let cs = do vec::map(fs) |f| {
|
||||
if f.node.mutbl == ast::m_imm {
|
||||
classify(f.node.expr, def_map, tcx)
|
||||
} else {
|
||||
non_const
|
||||
}
|
||||
};
|
||||
join_all(cs)
|
||||
}
|
||||
|
||||
ast::expr_cast(base, _) {
|
||||
let ty = ty::expr_ty(tcx, e);
|
||||
let base = classify(base, def_map, tcx);
|
||||
if ty::type_is_integral(ty) {
|
||||
join(integral_const, base)
|
||||
} else if ty::type_is_fp(ty) {
|
||||
join(general_const, base)
|
||||
} else {
|
||||
non_const
|
||||
}
|
||||
}
|
||||
|
||||
ast::expr_field(base, _, _) {
|
||||
classify(base, def_map, tcx)
|
||||
}
|
||||
|
||||
ast::expr_index(base, idx) {
|
||||
join(classify(base, def_map, tcx),
|
||||
classify(idx, def_map, tcx))
|
||||
}
|
||||
|
||||
ast::expr_addr_of(ast::m_imm, base) {
|
||||
classify(base, def_map, tcx)
|
||||
}
|
||||
|
||||
// FIXME: #1272, we can probably do something CCI-ish
|
||||
// surrounding nonlocal constants. But we don't yet.
|
||||
ast::expr_path(_) {
|
||||
alt def_map.find(e.id) {
|
||||
some(ast::def_const(def_id)) {
|
||||
if ast_util::is_local(def_id) {
|
||||
let ty = ty::expr_ty(tcx, e);
|
||||
if ty::type_is_integral(ty) {
|
||||
integral_const
|
||||
} else {
|
||||
general_const
|
||||
}
|
||||
} else {
|
||||
non_const
|
||||
}
|
||||
}
|
||||
some(_) {
|
||||
non_const
|
||||
}
|
||||
none {
|
||||
tcx.sess.span_bug(e.span,
|
||||
~"unknown path when \
|
||||
classifying constants");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ { non_const }
|
||||
};
|
||||
tcx.ccache.insert(did, cn);
|
||||
cn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_crate(crate: @ast::crate,
|
||||
def_map: resolve3::DefMap,
|
||||
tcx: ty::ctxt) {
|
||||
let v = visit::mk_simple_visitor(@{
|
||||
visit_expr_post: |e| { classify(e, def_map, tcx); }
|
||||
with *visit::default_simple_visitor()
|
||||
});
|
||||
visit::visit_crate(*crate, (), v);
|
||||
tcx.sess.abort_if_errors();
|
||||
}
|
||||
|
||||
|
||||
// FIXME (#33): this doesn't handle big integer/float literals correctly
|
||||
// (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 {
|
||||
fn lit_eq(a: @lit, b: @lit) -> bool {
|
||||
compare_const_vals(lit_to_const(a), lit_to_const(b)) == 0
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
||||
|
@ -249,6 +249,7 @@ enum ast_ty_to_ty_cache_entry {
|
||||
freevars: freevars::freevar_map,
|
||||
tcache: type_cache,
|
||||
rcache: creader_cache,
|
||||
ccache: constness_cache,
|
||||
short_names_cache: hashmap<t, @~str>,
|
||||
needs_drop_cache: hashmap<t, bool>,
|
||||
needs_unwind_cleanup_cache: hashmap<t, bool>,
|
||||
@ -534,6 +535,8 @@ fn param_bounds_to_kind(bounds: param_bounds) -> kind {
|
||||
|
||||
type type_cache = hashmap<ast::def_id, ty_param_bounds_and_ty>;
|
||||
|
||||
type constness_cache = hashmap<ast::def_id, const_eval::constness>;
|
||||
|
||||
type node_type_table = @smallintmap::smallintmap<t>;
|
||||
|
||||
fn mk_rcache() -> creader_cache {
|
||||
@ -581,6 +584,7 @@ fn mk_ctxt(s: session::session,
|
||||
freevars: freevars,
|
||||
tcache: ast_util::new_def_hash(),
|
||||
rcache: mk_rcache(),
|
||||
ccache: ast_util::new_def_hash(),
|
||||
short_names_cache: new_ty_hash(),
|
||||
needs_drop_cache: new_ty_hash(),
|
||||
needs_unwind_cleanup_cache: new_ty_hash(),
|
||||
|
Loading…
Reference in New Issue
Block a user