diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index e275ac7bc7dc6..acda0fe2f0e35 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -38,6 +38,7 @@ use std::borrow::{Cow, IntoCow}; use std::num::wrapping::OverflowingOps; use std::cmp::Ordering; use std::collections::hash_map::Entry::Vacant; +use std::mem::transmute; use std::{i8, i16, i32, i64, u8, u16, u32, u64}; use std::rc::Rc; @@ -242,7 +243,7 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) } } -#[derive(Clone, PartialEq)] +#[derive(Clone, Debug)] pub enum ConstVal { Float(f64), Int(i64), @@ -254,6 +255,27 @@ pub enum ConstVal { Tuple(ast::NodeId), } +/// Note that equality for `ConstVal` means that the it is the same +/// constant, not that the rust values are equal. In particular, `NaN +/// == NaN` (at least if it's the same NaN; distinct encodings for NaN +/// are considering unequal). +impl PartialEq for ConstVal { + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &ConstVal) -> bool { + match (self, other) { + (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}, + (&Int(a), &Int(b)) => a == b, + (&Uint(a), &Uint(b)) => a == b, + (&Str(ref a), &Str(ref b)) => a == b, + (&ByteStr(ref a), &ByteStr(ref b)) => a == b, + (&Bool(a), &Bool(b)) => a == b, + (&Struct(a), &Struct(b)) => a == b, + (&Tuple(a), &Tuple(b)) => a == b, + _ => false, + } + } +} + impl ConstVal { pub fn description(&self) -> &'static str { match *self { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 97fb6c3d26fc9..64d09a2365869 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -718,9 +718,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, // passes are timed inside typeck typeck::check_crate(tcx, trait_map); - time(time_passes, "MIR dump", || - mir::dump::dump_crate(tcx)); - time(time_passes, "const checking", || middle::check_const::check_crate(tcx)); @@ -741,6 +738,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, time(time_passes, "match checking", || middle::check_match::check_crate(tcx)); + time(time_passes, "MIR dump", || + mir::dump::dump_crate(tcx)); + time(time_passes, "liveness checking", || middle::liveness::check_crate(tcx)); diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index 5d20fe4bab4fd..6cc99a56933d6 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -10,8 +10,6 @@ //! See docs in build/expr/mod.rs -use rustc_data_structures::fnv::FnvHashMap; - use build::{Builder}; use hair::*; use repr::*; @@ -28,93 +26,16 @@ impl Builder { fn expr_as_constant(&mut self, expr: Expr) -> Constant { let this = self; - let Expr { ty: _, temp_lifetime: _, span, kind } = expr; - let kind = match kind { - ExprKind::Scope { extent: _, value } => { - return this.as_constant(value); - } - ExprKind::Literal { literal } => { - ConstantKind::Literal(literal) - } - ExprKind::Vec { fields } => { - let fields = this.as_constants(fields); - ConstantKind::Aggregate(AggregateKind::Vec, fields) - } - ExprKind::Tuple { fields } => { - let fields = this.as_constants(fields); - ConstantKind::Aggregate(AggregateKind::Tuple, fields) - } - ExprKind::Adt { adt_def, variant_index, substs, fields, base: None } => { - let field_names = this.hir.fields(adt_def, variant_index); - let fields = this.named_field_constants(field_names, fields); - ConstantKind::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs), fields) - } - ExprKind::Repeat { value, count } => { - let value = Box::new(this.as_constant(value)); - let count = Box::new(this.as_constant(count)); - ConstantKind::Repeat(value, count) - } - ExprKind::Binary { op, lhs, rhs } => { - let lhs = Box::new(this.as_constant(lhs)); - let rhs = Box::new(this.as_constant(rhs)); - ConstantKind::BinaryOp(op, lhs, rhs) - } - ExprKind::Unary { op, arg } => { - let arg = Box::new(this.as_constant(arg)); - ConstantKind::UnaryOp(op, arg) - } - ExprKind::Field { lhs, name } => { - let lhs = this.as_constant(lhs); - ConstantKind::Projection( - Box::new(ConstantProjection { - base: lhs, - elem: ProjectionElem::Field(name), - })) - } - ExprKind::Deref { arg } => { - let arg = this.as_constant(arg); - ConstantKind::Projection( - Box::new(ConstantProjection { - base: arg, - elem: ProjectionElem::Deref, - })) - } - ExprKind::Call { fun, args } => { - let fun = this.as_constant(fun); - let args = this.as_constants(args); - ConstantKind::Call(Box::new(fun), args) - } - _ => { + let Expr { ty, temp_lifetime: _, span, kind } = expr; + match kind { + ExprKind::Scope { extent: _, value } => + this.as_constant(value), + ExprKind::Literal { literal } => + Constant { span: span, ty: ty, literal: literal }, + _ => this.hir.span_bug( span, - &format!("expression is not a valid constant {:?}", kind)); - } - }; - Constant { span: span, kind: kind } - } - - fn as_constants(&mut self, - exprs: Vec>) - -> Vec> - { - exprs.into_iter().map(|expr| self.as_constant(expr)).collect() - } - - fn named_field_constants(&mut self, - field_names: Vec>, - field_exprs: Vec>) - -> Vec> - { - let fields_map: FnvHashMap<_, _> = - field_exprs.into_iter() - .map(|f| (f.name, self.as_constant(f.expr))) - .collect(); - - let fields: Vec<_> = - field_names.into_iter() - .map(|n| fields_map[&n].clone()) - .collect(); - - fields + &format!("expression is not a valid constant {:?}", kind)), + } } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 72e505f2b6edd..61eeac30c0f1d 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -99,14 +99,16 @@ impl Builder { true_block, expr_span, destination, Constant { span: expr_span, - kind: ConstantKind::Literal(Literal::Bool { value: true }), + ty: this.hir.bool_ty(), + literal: this.hir.true_literal(), }); this.cfg.push_assign_constant( false_block, expr_span, destination, Constant { span: expr_span, - kind: ConstantKind::Literal(Literal::Bool { value: false }), + ty: this.hir.bool_ty(), + literal: this.hir.false_literal(), }); this.cfg.terminate(true_block, Terminator::Goto { target: join_block }); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 2ff57a187123d..4d0acd5fac924 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -34,10 +34,20 @@ impl Builder { let discriminant_lvalue = unpack!(block = self.as_lvalue(block, discriminant)); - let arm_blocks: Vec = - arms.iter() - .map(|_| self.cfg.start_new_block()) - .collect(); + // Before we do anything, create uninitialized variables with + // suitable extent for all of the bindings in this match. It's + // easiest to do this up front because some of these arms may + // be unreachable or reachable multiple times. + let var_extent = self.extent_of_innermost_scope().unwrap(); + for arm in &arms { + self.declare_bindings(var_extent, arm.patterns[0].clone()); + } + + let mut arm_blocks = ArmBlocks { + blocks: arms.iter() + .map(|_| self.cfg.start_new_block()) + .collect(), + }; let arm_bodies: Vec> = arms.iter() @@ -51,35 +61,33 @@ impl Builder { // reverse of the order in which candidates are written in the // source. let candidates: Vec> = - arms.into_iter() - .zip(arm_blocks.iter()) + arms.iter() + .enumerate() .rev() // highest priority comes last - .flat_map(|(arm, &arm_block)| { - let guard = arm.guard; - arm.patterns.into_iter() + .flat_map(|(arm_index, arm)| { + arm.patterns.iter() .rev() - .map(move |pat| (arm_block, pat, guard.clone())) + .map(move |pat| (arm_index, pat.clone(), arm.guard.clone())) }) - .map(|(arm_block, pattern, guard)| { + .map(|(arm_index, pattern, guard)| { Candidate { match_pairs: vec![self.match_pair(discriminant_lvalue.clone(), pattern)], bindings: vec![], guard: guard, - arm_block: arm_block, + arm_index: arm_index, } }) .collect(); // this will generate code to test discriminant_lvalue and // branch to the appropriate arm block - let var_extent = self.extent_of_innermost_scope().unwrap(); - self.match_candidates(span, var_extent, candidates, block); + self.match_candidates(span, &mut arm_blocks, candidates, block); // all the arm blocks will rejoin here let end_block = self.cfg.start_new_block(); - for (arm_body, &arm_block) in arm_bodies.into_iter().zip(arm_blocks.iter()) { - let mut arm_block = arm_block; + for (arm_index, arm_body) in arm_bodies.into_iter().enumerate() { + let mut arm_block = arm_blocks.blocks[arm_index]; unpack!(arm_block = self.into(destination, arm_block, arm_body)); self.cfg.terminate(arm_block, Terminator::Goto { target: end_block }); } @@ -122,12 +130,15 @@ impl Builder { initializer: &Lvalue) -> BlockAnd<()> { + // first, creating the bindings + self.declare_bindings(var_extent, irrefutable_pat.clone()); + // create a dummy candidate let mut candidate = Candidate:: { - match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat)], + match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat.clone())], bindings: vec![], guard: None, - arm_block: block + arm_index: 0, // since we don't call `match_candidates`, this field is unused }; // Simplify the candidate. Since the pattern is irrefutable, this should @@ -142,44 +153,50 @@ impl Builder { } // now apply the bindings, which will also declare the variables - self.bind_matched_candidate(block, var_extent, candidate.bindings); + self.bind_matched_candidate(block, candidate.bindings); block.unit() } - pub fn declare_uninitialized_variables(&mut self, - var_extent: H::CodeExtent, - pattern: PatternRef) + pub fn declare_bindings(&mut self, + var_extent: H::CodeExtent, + pattern: PatternRef) { let pattern = self.hir.mirror(pattern); match pattern.kind { PatternKind::Binding { mutability, name, mode: _, var, ty, subpattern } => { self.declare_binding(var_extent, mutability, name, var, ty, pattern.span); if let Some(subpattern) = subpattern { - self.declare_uninitialized_variables(var_extent, subpattern); + self.declare_bindings(var_extent, subpattern); } } PatternKind::Array { prefix, slice, suffix } | PatternKind::Slice { prefix, slice, suffix } => { for subpattern in prefix.into_iter().chain(slice).chain(suffix) { - self.declare_uninitialized_variables(var_extent, subpattern); + self.declare_bindings(var_extent, subpattern); } } PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => { } PatternKind::Deref { subpattern } => { - self.declare_uninitialized_variables(var_extent, subpattern); + self.declare_bindings(var_extent, subpattern); } PatternKind::Leaf { subpatterns } | PatternKind::Variant { subpatterns, .. } => { for subpattern in subpatterns { - self.declare_uninitialized_variables(var_extent, subpattern.pattern); + self.declare_bindings(var_extent, subpattern.pattern); } } } } } +/// List of blocks for each arm (and potentially other metadata in the +/// future). +struct ArmBlocks { + blocks: Vec, +} + #[derive(Clone, Debug)] struct Candidate { // all of these must be satisfied... @@ -191,8 +208,8 @@ struct Candidate { // ...and the guard must be evaluated... guard: Option>, - // ...and then we branch here. - arm_block: BasicBlock, + // ...and then we branch to arm with this index. + arm_index: usize, } #[derive(Clone, Debug)] @@ -221,10 +238,10 @@ enum TestKind { Switch { adt_def: H::AdtDef }, // test for equality - Eq { value: Constant, ty: H::Ty }, + Eq { value: Literal, ty: H::Ty }, // test whether the value falls within an inclusive range - Range { lo: Constant, hi: Constant, ty: H::Ty }, + Range { lo: Literal, hi: Literal, ty: H::Ty }, // test length of the slice is equal to len Len { len: usize, op: BinOp }, @@ -242,12 +259,12 @@ struct Test { impl Builder { fn match_candidates(&mut self, span: H::Span, - var_extent: H::CodeExtent, + arm_blocks: &mut ArmBlocks, mut candidates: Vec>, mut block: BasicBlock) { - debug!("matched_candidate(span={:?}, var_extent={:?}, block={:?}, candidates={:?})", - span, var_extent, block, candidates); + debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})", + span, block, candidates); // Start by simplifying candidates. Once this process is // complete, all the match pairs which remain require some @@ -267,9 +284,12 @@ impl Builder { // If so, apply any bindings, test the guard (if any), and // branch to the arm. let candidate = candidates.pop().unwrap(); - match self.bind_and_guard_matched_candidate(block, var_extent, candidate) { - None => { return; } - Some(b) => { block = b; } + if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) { + block = b; + } else { + // if None is returned, then any remaining candidates + // are unreachable (at least not through this path). + return; } } @@ -297,7 +317,7 @@ impl Builder { candidate)) }) .collect(); - self.match_candidates(span, var_extent, applicable_candidates, target_block); + self.match_candidates(span, arm_blocks, applicable_candidates, target_block); } } @@ -315,15 +335,17 @@ impl Builder { /// MIR). fn bind_and_guard_matched_candidate(&mut self, mut block: BasicBlock, - var_extent: H::CodeExtent, + arm_blocks: &mut ArmBlocks, candidate: Candidate) -> Option { - debug!("bind_and_guard_matched_candidate(block={:?}, var_extent={:?}, candidate={:?})", - block, var_extent, candidate); + debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})", + block, candidate); debug_assert!(candidate.match_pairs.is_empty()); - self.bind_matched_candidate(block, var_extent, candidate.bindings); + self.bind_matched_candidate(block, candidate.bindings); + + let arm_block = arm_blocks.blocks[candidate.arm_index]; if let Some(guard) = candidate.guard { // the block to branch to if the guard fails; if there is no @@ -331,36 +353,26 @@ impl Builder { let cond = unpack!(block = self.as_operand(block, guard)); let otherwise = self.cfg.start_new_block(); self.cfg.terminate(block, Terminator::If { cond: cond, - targets: [candidate.arm_block, otherwise]}); + targets: [arm_block, otherwise]}); Some(otherwise) } else { - self.cfg.terminate(block, Terminator::Goto { target: candidate.arm_block }); + self.cfg.terminate(block, Terminator::Goto { target: arm_block }); None } } fn bind_matched_candidate(&mut self, block: BasicBlock, - var_extent: H::CodeExtent, bindings: Vec>) { - debug!("bind_matched_candidate(block={:?}, var_extent={:?}, bindings={:?})", - block, var_extent, bindings); + debug!("bind_matched_candidate(block={:?}, bindings={:?})", + block, bindings); // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { - // Create a variable for the `var_id` being bound. In the - // case where there are multiple patterns for a single - // arm, it may already exist. - let var_index = if !self.var_indices.contains_key(&binding.var_id) { - self.declare_binding(var_extent, - binding.mutability, - binding.name, - binding.var_id, - binding.var_ty, - binding.span) - } else { - self.var_indices[&binding.var_id] - }; + // Find the variable for the `var_id` being bound. It + // should have been created by a previous call to + // `declare_bindings`. + let var_index = self.var_indices[&binding.var_id]; let rvalue = match binding.binding_mode { BindingMode::ByValue => diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 2d0a6e61beb28..2d034baef167d 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -33,20 +33,20 @@ impl Builder { } } - PatternKind::Constant { ref expr } => { - let expr = self.as_constant(expr.clone()); + PatternKind::Constant { ref value } => { Test { span: match_pair.pattern.span, - kind: TestKind::Eq { value: expr, ty: match_pair.pattern.ty.clone() }, + kind: TestKind::Eq { value: value.clone(), + ty: match_pair.pattern.ty.clone() }, } } PatternKind::Range { ref lo, ref hi } => { - let lo = self.as_constant(lo.clone()); - let hi = self.as_constant(hi.clone()); Test { span: match_pair.pattern.span, - kind: TestKind::Range { lo: lo, hi: hi, ty: match_pair.pattern.ty.clone() }, + kind: TestKind::Range { lo: lo.clone(), + hi: hi.clone(), + ty: match_pair.pattern.ty.clone() }, } } @@ -90,15 +90,15 @@ impl Builder { TestKind::Eq { value, ty } => { // call PartialEq::eq(discrim, constant) - let constant = self.push_constant(block, test.span, ty.clone(), value); + let constant = self.push_literal(block, test.span, ty.clone(), value); let item_ref = self.hir.partial_eq(ty); self.call_comparison_fn(block, test.span, item_ref, lvalue.clone(), constant) } TestKind::Range { lo, hi, ty } => { // Test `v` by computing `PartialOrd::le(lo, v) && PartialOrd::le(v, hi)`. - let lo = self.push_constant(block, test.span, ty.clone(), lo); - let hi = self.push_constant(block, test.span, ty.clone(), hi); + let lo = self.push_literal(block, test.span, ty.clone(), lo); + let hi = self.push_literal(block, test.span, ty.clone(), hi); let item_ref = self.hir.partial_le(ty); let lo_blocks = diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 1c44988e4b407..9fa1d55e82f9c 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -33,13 +33,14 @@ impl Builder { lvalue } - pub fn push_constant(&mut self, - block: BasicBlock, - span: H::Span, - ty: H::Ty, - constant: Constant) - -> Lvalue { - let temp = self.temp(ty); + pub fn push_literal(&mut self, + block: BasicBlock, + span: H::Span, + ty: H::Ty, + literal: Literal) + -> Lvalue { + let temp = self.temp(ty.clone()); + let constant = Constant { span: span, ty: ty, literal: literal }; self.cfg.push_assign_constant(block, span, &temp, constant); temp } @@ -55,8 +56,8 @@ impl Builder { block, span, &temp, Constant { span: span, - kind: ConstantKind::Literal(Literal::Uint { bits: IntegralBits::BSize, - value: value as u64 }), + ty: self.hir.usize_ty(), + literal: self.hir.usize_literal(value), }); temp } @@ -66,13 +67,7 @@ impl Builder { span: H::Span, item_ref: ItemRef) -> Lvalue { - let constant = Constant { - span: span, - kind: ConstantKind::Literal(Literal::Item { - def_id: item_ref.def_id, - substs: item_ref.substs - }) - }; - self.push_constant(block, span, item_ref.ty, constant) + let literal = Literal::Item { def_id: item_ref.def_id, substs: item_ref.substs }; + self.push_literal(block, span, item_ref.ty, literal) } } diff --git a/src/librustc_mir/build/stmt.rs b/src/librustc_mir/build/stmt.rs index 9d5a83154d402..3dd4f5f253c0a 100644 --- a/src/librustc_mir/build/stmt.rs +++ b/src/librustc_mir/build/stmt.rs @@ -40,7 +40,7 @@ impl Builder { StmtKind::Let { remainder_scope, init_scope, pattern, initializer: None, stmts } => { this.in_scope(remainder_scope, block, |this| { unpack!(block = this.in_scope(init_scope, block, |this| { - this.declare_uninitialized_variables(remainder_scope, pattern); + this.declare_bindings(remainder_scope, pattern); block.unit() })); this.stmts(block, stmts) diff --git a/src/librustc_mir/dump.rs b/src/librustc_mir/dump.rs index ebde7e1d097b3..4251b550cfc4d 100644 --- a/src/librustc_mir/dump.rs +++ b/src/librustc_mir/dump.rs @@ -62,7 +62,7 @@ impl<'a, 'tcx> OuterDump<'a, 'tcx> { } } - let always_build_mir = self.tcx.sess.opts.always_build_mir; + let always_build_mir = true; if !built_mir && always_build_mir { let mut closure_dump = InnerDump { tcx: self.tcx, attr: None }; walk_op(&mut closure_dump); diff --git a/src/librustc_mir/hair.rs b/src/librustc_mir/hair.rs index cb094ad49055f..f4eb03c5d07c2 100644 --- a/src/librustc_mir/hair.rs +++ b/src/librustc_mir/hair.rs @@ -38,6 +38,7 @@ pub trait Hair: Sized+Debug+Clone+Eq+Hash { // (*) type Ty: Clone+Debug+Eq; // e.g., ty::Ty<'tcx> type Region: Copy+Debug; // e.g., ty::Region type CodeExtent: Copy+Debug+Hash+Eq; // e.g., region::CodeExtent + type ConstVal: Clone+Debug+PartialEq; // e.g., ConstVal type Pattern: Clone+Debug+Mirror>; // e.g., &P type Expr: Clone+Debug+Mirror>; // e.g., &P type Stmt: Clone+Debug+Mirror>; // e.g., &P @@ -55,9 +56,18 @@ pub trait Hair: Sized+Debug+Clone+Eq+Hash { // (*) /// Returns the type `usize`. fn usize_ty(&mut self) -> Self::Ty; + /// Returns the literal for `true` + fn usize_literal(&mut self, value: usize) -> Literal; + /// Returns the type `bool`. fn bool_ty(&mut self) -> Self::Ty; + /// Returns the literal for `true` + fn true_literal(&mut self) -> Literal; + + /// Returns the literal for `true` + fn false_literal(&mut self) -> Literal; + /// Returns a reference to `PartialEq::::eq` fn partial_eq(&mut self, ty: Self::Ty) -> ItemRef; @@ -261,9 +271,9 @@ pub enum PatternKind { Deref { subpattern: PatternRef }, // box P, &P, &mut P, etc - Constant { expr: ExprRef }, + Constant { value: Literal }, - Range { lo: ExprRef, hi: ExprRef }, + Range { lo: Literal, hi: Literal }, // matches against a slice, checking the length and extracting elements Slice { prefix: Vec>, diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs index a1b891ab09086..d522518a3d4af 100644 --- a/src/librustc_mir/repr.rs +++ b/src/librustc_mir/repr.rs @@ -642,48 +642,21 @@ impl Debug for Rvalue { /////////////////////////////////////////////////////////////////////////// // Constants +// +// Two constants are equal if they are the same constant. Note that +// this does not necessarily mean that they are "==" in Rust -- in +// particular one must be wary of `NaN`! #[derive(Clone, Debug, PartialEq)] pub struct Constant { pub span: H::Span, - pub kind: ConstantKind + pub ty: H::Ty, + pub literal: Literal } -#[derive(Clone, Debug, PartialEq)] -pub enum ConstantKind { - Literal(Literal), - Aggregate(AggregateKind, Vec>), - Call(Box>, Vec>), - Cast(Box>, H::Ty), - Repeat(Box>, Box>), - Ref(BorrowKind, Box>), - BinaryOp(BinOp, Box>, Box>), - UnaryOp(UnOp, Box>), - Projection(Box>) -} - -pub type ConstantProjection = - Projection,Constant>; - #[derive(Clone, Debug, PartialEq)] pub enum Literal { Item { def_id: H::DefId, substs: H::Substs }, - Projection { projection: H::Projection }, - Int { bits: IntegralBits, value: i64 }, - Uint { bits: IntegralBits, value: u64 }, - Float { bits: FloatBits, value: f64 }, - Char { c: char }, - Bool { value: bool }, - Bytes { value: H::Bytes }, - String { value: H::InternedString }, -} - -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub enum IntegralBits { - B8, B16, B32, B64, BSize + Value { value: H::ConstVal }, } -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub enum FloatBits { - F32, F64 -} diff --git a/src/librustc_mir/tcx/expr.rs b/src/librustc_mir/tcx/expr.rs index 97becd474b1fe..098a85514eb2a 100644 --- a/src/librustc_mir/tcx/expr.rs +++ b/src/librustc_mir/tcx/expr.rs @@ -16,14 +16,13 @@ use tcx::Cx; use tcx::block; use tcx::pattern::PatNode; use tcx::rustc::front::map; +use tcx::rustc::middle::const_eval; use tcx::rustc::middle::def; use tcx::rustc::middle::region::CodeExtent; use tcx::rustc::middle::pat_util; use tcx::rustc::middle::ty::{self, Ty}; use tcx::rustc_front::hir; use tcx::rustc_front::util as hir_util; -use tcx::syntax::ast; -use tcx::syntax::codemap::Span; use tcx::syntax::parse::token; use tcx::syntax::ptr::P; use tcx::to_ref::ToRef; @@ -83,9 +82,9 @@ impl<'a,'tcx:'a> Mirror> for &'tcx hir::Expr { } } - hir::ExprLit(ref lit) => { - let literal = convert_literal(cx, self.span, expr_ty, lit); - ExprKind::Literal { literal: literal } + hir::ExprLit(..) => { + let value = const_eval::eval_const_expr(cx.tcx, self); + ExprKind::Literal { literal: Literal::Value { value: value } } } hir::ExprBinary(op, ref lhs, ref rhs) => { @@ -452,67 +451,6 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind { } } -fn convert_literal<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>, - expr_span: Span, - expr_ty: Ty<'tcx>, - literal: &ast::Lit) - -> Literal> -{ - use repr::IntegralBits::*; - match (&literal.node, &expr_ty.sty) { - (&ast::LitStr(ref text, _), _) => - Literal::String { value: text.clone() }, - (&ast::LitByteStr(ref bytes), _) => - Literal::Bytes { value: bytes.clone() }, - (&ast::LitByte(c), _) => - Literal::Uint { bits: B8, value: c as u64 }, - (&ast::LitChar(c), _) => - Literal::Char { c: c }, - (&ast::LitInt(v, _), &ty::TyUint(ast::TyU8)) => - Literal::Uint { bits: B8, value: v }, - (&ast::LitInt(v, _), &ty::TyUint(ast::TyU16)) => - Literal::Uint { bits: B16, value: v }, - (&ast::LitInt(v, _), &ty::TyUint(ast::TyU32)) => - Literal::Uint { bits: B32, value: v }, - (&ast::LitInt(v, _), &ty::TyUint(ast::TyU64)) => - Literal::Uint { bits: B64, value: v }, - (&ast::LitInt(v, _), &ty::TyUint(ast::TyUs)) => - Literal::Uint { bits: BSize, value: v }, - (&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI8)) => - Literal::Int { bits: B8, value: -(v as i64) }, - (&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI16)) => - Literal::Int { bits: B16, value: -(v as i64) }, - (&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI32)) => - Literal::Int { bits: B32, value: -(v as i64) }, - (&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI64)) => - Literal::Int { bits: B64, value: -(v as i64) }, - (&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyIs)) => - Literal::Int { bits: BSize, value: -(v as i64) }, - (&ast::LitInt(v, _), &ty::TyInt(ast::TyI8)) => - Literal::Int { bits: B8, value: v as i64 }, - (&ast::LitInt(v, _), &ty::TyInt(ast::TyI16)) => - Literal::Int { bits: B16, value: v as i64 }, - (&ast::LitInt(v, _), &ty::TyInt(ast::TyI32)) => - Literal::Int { bits: B32, value: v as i64 }, - (&ast::LitInt(v, _), &ty::TyInt(ast::TyI64)) => - Literal::Int { bits: B64, value: v as i64 }, - (&ast::LitInt(v, _), &ty::TyInt(ast::TyIs)) => - Literal::Int { bits: BSize, value: v as i64 }, - (&ast::LitFloat(ref v, _), &ty::TyFloat(ast::TyF32)) | - (&ast::LitFloatUnsuffixed(ref v), &ty::TyFloat(ast::TyF32)) => - Literal::Float { bits: FloatBits::F32, value: v.parse::().unwrap() }, - (&ast::LitFloat(ref v, _), &ty::TyFloat(ast::TyF64)) | - (&ast::LitFloatUnsuffixed(ref v), &ty::TyFloat(ast::TyF64)) => - Literal::Float { bits: FloatBits::F64, value: v.parse::().unwrap() }, - (&ast::LitBool(v), _) => - Literal::Bool { value: v }, - (ref l, ref t) => - cx.tcx.sess.span_bug( - expr_span, - &format!("Invalid literal/type combination: {:?},{:?}", l, t)) - } -} - fn convert_arm<'a,'tcx:'a>(cx: &Cx<'a,'tcx>, arm: &'tcx hir::Arm) -> Arm> { let map = if arm.pats.len() == 1 { None diff --git a/src/librustc_mir/tcx/mod.rs b/src/librustc_mir/tcx/mod.rs index 9c0ef55b3d83a..04f52a52464b7 100644 --- a/src/librustc_mir/tcx/mod.rs +++ b/src/librustc_mir/tcx/mod.rs @@ -14,6 +14,7 @@ use std::fmt::{Debug, Formatter, Error}; use std::hash::{Hash, Hasher}; use std::rc::Rc; +use self::rustc::middle::const_eval::ConstVal; use self::rustc::middle::def_id::DefId; use self::rustc::middle::infer::InferCtxt; use self::rustc::middle::region::CodeExtent; @@ -56,6 +57,7 @@ impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> { type Ty = Ty<'tcx>; type Region = ty::Region; type CodeExtent = CodeExtent; + type ConstVal = ConstVal; type Pattern = PatNode<'tcx>; type Expr = &'tcx hir::Expr; type Stmt = &'tcx hir::Stmt; @@ -70,10 +72,22 @@ impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> { self.tcx.types.usize } + fn usize_literal(&mut self, value: usize) -> Literal { + Literal::Value { value: ConstVal::Uint(value as u64) } + } + fn bool_ty(&mut self) -> Ty<'tcx> { self.tcx.types.bool } + fn true_literal(&mut self) -> Literal { + Literal::Value { value: ConstVal::Bool(true) } + } + + fn false_literal(&mut self) -> Literal { + Literal::Value { value: ConstVal::Bool(false) } + } + fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef { let eq_def_id = self.tcx.lang_items.eq_trait().unwrap(); self.cmp_method_ref(eq_def_id, "eq", ty) diff --git a/src/librustc_mir/tcx/pattern.rs b/src/librustc_mir/tcx/pattern.rs index d80fbfa7fe897..fe0c2c6c76add 100644 --- a/src/librustc_mir/tcx/pattern.rs +++ b/src/librustc_mir/tcx/pattern.rs @@ -14,9 +14,10 @@ use repr::*; use rustc_data_structures::fnv::FnvHashMap; use std::rc::Rc; use tcx::Cx; -use tcx::rustc::middle::const_eval::lookup_const_by_id; +use tcx::rustc::middle::const_eval; use tcx::rustc::middle::def; use tcx::rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding}; +use tcx::rustc::middle::subst::Substs; use tcx::rustc::middle::ty::{self, Ty}; use tcx::rustc_front::hir; use tcx::syntax::ast; @@ -145,12 +146,19 @@ impl<'a,'tcx:'a> Mirror> for PatNode<'tcx> { hir::PatWild(..) => PatternKind::Wild, - hir::PatLit(ref lt) => - PatternKind::Constant { expr: lt.to_ref() }, + hir::PatLit(ref value) => { + let value = const_eval::eval_const_expr(cx.tcx, value); + let value = Literal::Value { value: value }; + PatternKind::Constant { value: value } + }, - hir::PatRange(ref begin, ref end) => - PatternKind::Range { lo: begin.to_ref(), - hi: end.to_ref() }, + hir::PatRange(ref lo, ref hi) => { + let lo = const_eval::eval_const_expr(cx.tcx, lo); + let lo = Literal::Value { value: lo }; + let hi = const_eval::eval_const_expr(cx.tcx, hi); + let hi = Literal::Value { value: hi }; + PatternKind::Range { lo: lo, hi: hi } + }, hir::PatEnum(..) | hir::PatIdent(..) | hir::PatQPath(..) if pat_is_resolved_const(&cx.tcx.def_map, self.pat) => @@ -158,13 +166,25 @@ impl<'a,'tcx:'a> Mirror> for PatNode<'tcx> { let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def(); match def { def::DefConst(def_id) | def::DefAssociatedConst(def_id) => - match lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) { - Some(const_expr) => - PatternKind::Constant { expr: const_expr.to_ref() }, - None => + match const_eval::lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) { + Some(const_expr) => { + let opt_value = + const_eval::eval_const_expr_partial( + cx.tcx, const_expr, + const_eval::EvalHint::ExprTypeChecked); + let literal = if let Ok(value) = opt_value { + Literal::Value { value: value } + } else { + let substs = cx.tcx.mk_substs(Substs::empty()); + Literal::Item { def_id: def_id, substs: substs } + }; + PatternKind::Constant { value: literal } + } + None => { cx.tcx.sess.span_bug( self.pat.span, - &format!("cannot eval constant: {:?}", def_id)), + &format!("cannot eval constant: {:?}", def_id)) + } }, _ => cx.tcx.sess.span_bug(