|
12 | 12 | #![allow(unsigned_negation)] |
13 | 13 |
|
14 | 14 | pub use self::const_val::*; |
15 | | -pub use self::constness::*; |
16 | 15 |
|
17 | 16 | use metadata::csearch; |
18 | 17 | use middle::{astencode, def}; |
19 | 18 | use middle::pat_util::def_to_path; |
20 | 19 | use middle::ty::{self}; |
21 | 20 | use middle::astconv_util::{ast_ty_to_prim_ty}; |
22 | | -use util::nodemap::DefIdMap; |
23 | 21 |
|
24 | 22 | use syntax::ast::{self, Expr}; |
25 | 23 | use syntax::codemap::Span; |
26 | 24 | use syntax::parse::token::InternedString; |
27 | 25 | use syntax::ptr::P; |
28 | | -use syntax::visit::{self, Visitor}; |
29 | 26 | use syntax::{ast_map, ast_util, codemap}; |
30 | 27 |
|
31 | 28 | use std::collections::hash_map::Entry::Vacant; |
32 | 29 | use std::rc::Rc; |
33 | 30 |
|
34 | | -// |
35 | | -// This pass classifies expressions by their constant-ness. |
36 | | -// |
37 | | -// Constant-ness comes in 3 flavours: |
38 | | -// |
39 | | -// - Integer-constants: can be evaluated by the frontend all the way down |
40 | | -// to their actual value. They are used in a few places (enum |
41 | | -// discriminants, switch arms) and are a subset of |
42 | | -// general-constants. They cover all the integer and integer-ish |
43 | | -// literals (nil, bool, int, uint, char, iNN, uNN) and all integer |
44 | | -// operators and copies applied to them. |
45 | | -// |
46 | | -// - General-constants: can be evaluated by LLVM but not necessarily by |
47 | | -// the frontend; usually due to reliance on target-specific stuff such |
48 | | -// as "where in memory the value goes" or "what floating point mode the |
49 | | -// target uses". This _includes_ integer-constants, plus the following |
50 | | -// constructors: |
51 | | -// |
52 | | -// fixed-size vectors and strings: [] and ""/_ |
53 | | -// vector and string slices: &[] and &"" |
54 | | -// tuples: (,) |
55 | | -// enums: foo(...) |
56 | | -// floating point literals and operators |
57 | | -// & and * pointers |
58 | | -// copies of general constants |
59 | | -// |
60 | | -// (in theory, probably not at first: if/match on integer-const |
61 | | -// conditions / discriminants) |
62 | | -// |
63 | | -// - Non-constants: everything else. |
64 | | -// |
65 | | - |
66 | | -#[derive(Copy)] |
67 | | -pub enum constness { |
68 | | - integral_const, |
69 | | - general_const, |
70 | | - non_const |
71 | | -} |
72 | | - |
73 | | -type constness_cache = DefIdMap<constness>; |
74 | | - |
75 | | -pub fn join(a: constness, b: constness) -> constness { |
76 | | - match (a, b) { |
77 | | - (integral_const, integral_const) => integral_const, |
78 | | - (integral_const, general_const) |
79 | | - | (general_const, integral_const) |
80 | | - | (general_const, general_const) => general_const, |
81 | | - _ => non_const |
82 | | - } |
83 | | -} |
84 | | - |
85 | | -pub fn join_all<It: Iterator<Item=constness>>(cs: It) -> constness { |
86 | | - cs.fold(integral_const, |a, b| join(a, b)) |
87 | | -} |
88 | | - |
89 | 31 | fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> { |
90 | 32 | let opt_def = tcx.def_map.borrow().get(&e.id).cloned(); |
91 | 33 | match opt_def { |
@@ -186,113 +128,6 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId) |
186 | 128 | } |
187 | 129 | } |
188 | 130 |
|
189 | | -struct ConstEvalVisitor<'a, 'tcx: 'a> { |
190 | | - tcx: &'a ty::ctxt<'tcx>, |
191 | | - ccache: constness_cache, |
192 | | -} |
193 | | - |
194 | | -impl<'a, 'tcx> ConstEvalVisitor<'a, 'tcx> { |
195 | | - fn classify(&mut self, e: &Expr) -> constness { |
196 | | - let did = ast_util::local_def(e.id); |
197 | | - match self.ccache.get(&did) { |
198 | | - Some(&x) => return x, |
199 | | - None => {} |
200 | | - } |
201 | | - let cn = match e.node { |
202 | | - ast::ExprLit(ref lit) => { |
203 | | - match lit.node { |
204 | | - ast::LitStr(..) | ast::LitFloat(..) => general_const, |
205 | | - _ => integral_const |
206 | | - } |
207 | | - } |
208 | | - |
209 | | - ast::ExprUnary(_, ref inner) | ast::ExprParen(ref inner) => |
210 | | - self.classify(&**inner), |
211 | | - |
212 | | - ast::ExprBinary(_, ref a, ref b) => |
213 | | - join(self.classify(&**a), self.classify(&**b)), |
214 | | - |
215 | | - ast::ExprTup(ref es) | |
216 | | - ast::ExprVec(ref es) => |
217 | | - join_all(es.iter().map(|e| self.classify(&**e))), |
218 | | - |
219 | | - ast::ExprStruct(_, ref fs, None) => { |
220 | | - let cs = fs.iter().map(|f| self.classify(&*f.expr)); |
221 | | - join_all(cs) |
222 | | - } |
223 | | - |
224 | | - ast::ExprCast(ref base, _) => { |
225 | | - let ty = ty::expr_ty(self.tcx, e); |
226 | | - let base = self.classify(&**base); |
227 | | - if ty::type_is_integral(ty) { |
228 | | - join(integral_const, base) |
229 | | - } else if ty::type_is_fp(ty) { |
230 | | - join(general_const, base) |
231 | | - } else { |
232 | | - non_const |
233 | | - } |
234 | | - } |
235 | | - |
236 | | - ast::ExprField(ref base, _) => self.classify(&**base), |
237 | | - |
238 | | - ast::ExprTupField(ref base, _) => self.classify(&**base), |
239 | | - |
240 | | - ast::ExprIndex(ref base, ref idx) => |
241 | | - join(self.classify(&**base), self.classify(&**idx)), |
242 | | - |
243 | | - ast::ExprAddrOf(ast::MutImmutable, ref base) => |
244 | | - self.classify(&**base), |
245 | | - |
246 | | - // FIXME: (#3728) we can probably do something CCI-ish |
247 | | - // surrounding nonlocal constants. But we don't yet. |
248 | | - ast::ExprPath(_) | ast::ExprQPath(_) => self.lookup_constness(e), |
249 | | - |
250 | | - ast::ExprRepeat(..) => general_const, |
251 | | - |
252 | | - ast::ExprBlock(ref block) => { |
253 | | - match block.expr { |
254 | | - Some(ref e) => self.classify(&**e), |
255 | | - None => integral_const |
256 | | - } |
257 | | - } |
258 | | - |
259 | | - _ => non_const |
260 | | - }; |
261 | | - self.ccache.insert(did, cn); |
262 | | - cn |
263 | | - } |
264 | | - |
265 | | - fn lookup_constness(&self, e: &Expr) -> constness { |
266 | | - match lookup_const(self.tcx, e) { |
267 | | - Some(rhs) => { |
268 | | - let ty = ty::expr_ty(self.tcx, &*rhs); |
269 | | - if ty::type_is_integral(ty) { |
270 | | - integral_const |
271 | | - } else { |
272 | | - general_const |
273 | | - } |
274 | | - } |
275 | | - None => non_const |
276 | | - } |
277 | | - } |
278 | | - |
279 | | -} |
280 | | - |
281 | | -impl<'a, 'tcx, 'v> Visitor<'v> for ConstEvalVisitor<'a, 'tcx> { |
282 | | - fn visit_expr_post(&mut self, e: &Expr) { |
283 | | - self.classify(e); |
284 | | - } |
285 | | -} |
286 | | - |
287 | | -pub fn process_crate(tcx: &ty::ctxt) { |
288 | | - visit::walk_crate(&mut ConstEvalVisitor { |
289 | | - tcx: tcx, |
290 | | - ccache: DefIdMap(), |
291 | | - }, tcx.map.krate()); |
292 | | - tcx.sess.abort_if_errors(); |
293 | | -} |
294 | | - |
295 | | - |
296 | 131 | // FIXME (#33): this doesn't handle big integer/float literals correctly |
297 | 132 | // (nor does the rest of our literal handling). |
298 | 133 | #[derive(Clone, PartialEq)] |
|
0 commit comments