diff options
| author | Graydon Hoare <graydon@mozilla.com> | 2012-07-30 19:05:56 -0700 |
|---|---|---|
| committer | Graydon Hoare <graydon@mozilla.com> | 2012-07-30 19:06:06 -0700 |
| commit | 290f079474670a14168104af5e3a32ff49abfae9 (patch) | |
| tree | 3d9794c4141163461c0ec470820ff47f35f257e8 | |
| parent | bf8c7739369da57555e65b2c187759e59edd96ae (diff) | |
| download | rust-290f079474670a14168104af5e3a32ff49abfae9.tar.gz rust-290f079474670a14168104af5e3a32ff49abfae9.zip | |
Frontend bits for #2317, general const-expr classification.
| -rw-r--r-- | src/libsyntax/ast_util.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 10 | ||||
| -rw-r--r-- | src/rustc/driver/driver.rs | 3 | ||||
| -rw-r--r-- | src/rustc/middle/const_eval.rs | 189 | ||||
| -rw-r--r-- | src/rustc/middle/ty.rs | 4 |
5 files changed, 208 insertions, 1 deletions
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 98b42ce79ae..265cb7d3749 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -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) { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index e279bf3a7f8..a542ca574ac 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -55,6 +55,7 @@ type visitor<E> = 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 @@ type simple_visitor = 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 mk_simple_visitor(v: simple_visitor) -> 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 mk_simple_visitor(v: simple_visitor) -> vt<()> { 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), diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 7be6103e34f..bd634a2b46e 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -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, diff --git a/src/rustc/middle/const_eval.rs b/src/rustc/middle/const_eval.rs index cdb1a3b10d0..50ec4e62175 100644 --- a/src/rustc/middle/const_eval.rs +++ b/src/rustc/middle/const_eval.rs @@ -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: diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index cb055055091..bae5b34f5a1 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -249,6 +249,7 @@ type ctxt = 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 @@ type ty_param_bounds_and_ty = {bounds: @~[param_bounds], 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(), |
