diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index a2f7d2c9d725f..1c0129bcc0ad9 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -35,13 +35,11 @@ impl<'a,'tcx> Builder<'a,'tcx> { let expr_ty = expr.ty.clone(); let temp = this.temp(expr_ty.clone()); - let temp_lifetime = match expr.temp_lifetime { - Some(t) => t, - None => { - span_bug!(expr.span, "no temp_lifetime for expr"); - } - }; - this.schedule_drop(expr.span, temp_lifetime, &temp, expr_ty); + if let Some(temp_lifetime) = expr.temp_lifetime { + this.schedule_drop(expr.span, temp_lifetime, &temp, expr_ty); + } + // if expression is inside a constant then + // there's no temp_lifetime and no need to drop // Careful here not to cause an infinite cycle. If we always // called `into`, then for lvalues like `x.f`, it would diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 5284a2ef39535..e6a6c617ef7e3 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -264,6 +264,77 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>, ) } + +/////////////////////////////////////////////////////////////////////////// +/// the main entry point for building MIR for an arbitrary expression + +pub fn construct_expr<'a,'tcx>(hir: Cx<'a,'tcx>, + id: ast::NodeId, + span: Span, + expr: &'tcx hir::Expr) + -> (Mir<'tcx>, ScopeAuxiliaryVec) { + let tcx = hir.tcx(); + let cfg = CFG { basic_blocks: vec![] }; + let ty = tcx.node_id_to_type(id); + + let mut builder = Builder { + hir: hir, + cfg: cfg, + fn_span: span, + scopes: vec![], + scope_datas: vec![], + scope_auxiliary: ScopeAuxiliaryVec { vec: vec![] }, + loop_scopes: vec![], + temp_decls: vec![], + var_decls: vec![], + var_indices: FnvHashMap(), + unit_temp: None, + cached_resume_block: None, + }; + + assert_eq!(builder.cfg.start_new_block(), START_BLOCK); + assert_eq!(builder.cfg.start_new_block(), END_BLOCK); + + let call_site_extent = tcx.region_maps.item_extent(id); + let _ = builder.in_scope(call_site_extent, START_BLOCK, |builder, call_site_scope_id| { + let mut block = START_BLOCK; + let expr = builder.hir.mirror(expr); + unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr)); + builder.cfg.terminate(block, call_site_scope_id, span, + TerminatorKind::Goto { target: END_BLOCK }); + builder.cfg.terminate(END_BLOCK, call_site_scope_id, span, + TerminatorKind::Return); + + END_BLOCK.unit() + }); + + assert!( + builder.cfg.basic_blocks + .iter() + .enumerate() + .all(|(index, block)| { + if block.terminator.is_none() { + bug!("no terminator on block {:?} in fn {:?}", + index, id) + } + true + })); + + ( + Mir { + basic_blocks: builder.cfg.basic_blocks, + scopes: builder.scope_datas, + var_decls: builder.var_decls, + arg_decls: Vec::new(), + temp_decls: builder.temp_decls, + upvar_decls: Vec::new(), + return_ty: FnOutput::FnConverging(ty), + span: span + }, + builder.scope_auxiliary, + ) +} + impl<'a,'tcx> Builder<'a,'tcx> { fn args_and_body(&mut self, mut block: BasicBlock, diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 40334f652eed3..b96346e7eb09e 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -60,19 +60,13 @@ struct OuterDump<'a, 'tcx: 'a> { } impl<'a, 'tcx> OuterDump<'a, 'tcx> { - fn visit_mir(&mut self, attributes: &'a [ast::Attribute], mut walk_op: OP) + fn visit_mir(&mut self, mut walk_op: OP) where OP: for<'m> FnMut(&mut InnerDump<'a, 'm, 'tcx>) { let mut closure_dump = InnerDump { tcx: self.tcx, - attr: None, map: &mut *self.map, }; - for attr in attributes { - if attr.check_name("rustc_mir") { - closure_dump.attr = Some(attr); - } - } walk_op(&mut closure_dump); } } @@ -80,14 +74,14 @@ impl<'a, 'tcx> OuterDump<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for OuterDump<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { - self.visit_mir(&item.attrs, |c| intravisit::walk_item(c, item)); + self.visit_mir(|c| c.visit_item(item)); intravisit::walk_item(self, item); } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { match trait_item.node { hir::MethodTraitItem(_, Some(_)) => { - self.visit_mir(&trait_item.attrs, |c| intravisit::walk_trait_item(c, trait_item)); + self.visit_mir(|c| intravisit::walk_trait_item(c, trait_item)); } hir::MethodTraitItem(_, None) | hir::ConstTraitItem(..) | @@ -99,7 +93,7 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterDump<'a, 'tcx> { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { match impl_item.node { hir::ImplItemKind::Method(..) => { - self.visit_mir(&impl_item.attrs, |c| intravisit::walk_impl_item(c, impl_item)); + self.visit_mir(|c| intravisit::walk_impl_item(c, impl_item)); } hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(..) => {} } @@ -113,7 +107,6 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterDump<'a, 'tcx> { struct InnerDump<'a, 'm, 'tcx: 'a + 'm> { tcx: &'a TyCtxt<'tcx>, map: &'m mut MirMap<'tcx>, - attr: Option<&'a ast::Attribute>, } impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> { @@ -150,6 +143,32 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> { intravisit::walk_fn(self, fk, decl, body, span); } + + fn visit_item(&mut self, i: &'tcx hir::Item) { + match i.node { + hir::ItemConst(_, ref expr) | + hir::ItemStatic(_, _, ref expr) => { + let param_env = ty::ParameterEnvironment::for_item(self.tcx, i.id); + let infcx = infer::new_infer_ctxt(self.tcx, + &self.tcx.tables, + Some(param_env), + ProjectionMode::AnyFinal); + let (mir, scope_auxiliary) = build::construct_expr(Cx::new(&infcx), + i.id, + i.span, + expr); + pretty::dump_mir(self.tcx, + "mir_map", + &0, + i.id, + &mir, + Some(&scope_auxiliary)); + assert!(self.map.map.insert(i.id, mir).is_none()); + }, + _ => {}, + } + intravisit::walk_item(self, i); + } } fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>, diff --git a/src/test/run-pass/mir_constant.rs b/src/test/run-pass/mir_constant.rs new file mode 100644 index 0000000000000..a5edcfcdbdcdd --- /dev/null +++ b/src/test/run-pass/mir_constant.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test does nothing useful yet, it just generates MIR for constants + +#![feature(rustc_attrs)] + +#[rustc_mir] +const C: i32 = 5 + 6; + +#[rustc_mir] +const D: i32 = C - 3; + +fn main() { + assert_eq!(D, 8); + assert_eq!(C, 11); +}