(index<- )        ./librustc/middle/trans/controlflow.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  use lib::llvm::*;
  12  use driver::session::FullDebugInfo;
  13  use middle::lang_items::{FailFnLangItem, FailBoundsCheckFnLangItem};
  14  use middle::trans::base::*;
  15  use middle::trans::build::*;
  16  use middle::trans::callee;
  17  use middle::trans::common::*;
  18  use middle::trans::debuginfo;
  19  use middle::trans::cleanup;
  20  use middle::trans::cleanup::CleanupMethods;
  21  use middle::trans::expr;
  22  use middle::ty;
  23  use util::ppaux::Repr;
  24  
  25  use middle::trans::type_::Type;
  26  
  27  use syntax::ast;
  28  use syntax::ast::Ident;
  29  use syntax::ast_util;
  30  use syntax::codemap::Span;
  31  use syntax::parse::token::InternedString;
  32  use syntax::parse::token;
  33  use syntax::visit::Visitor;
  34  
  35  pub fn trans_stmt<'a>(cx: &'a Block<'a>,
  36                        s: &ast::Stmt)
  37                        -> &'a Block<'a> {
  38      let _icx = push_ctxt("trans_stmt");
  39      let fcx = cx.fcx;
  40      debug!("trans_stmt({})", s.repr(cx.tcx()));
  41  
  42      if cx.sess().asm_comments() {
  43          add_span_comment(cx, s.span, s.repr(cx.tcx()));
  44      }
  45  
  46      let mut bcx = cx;
  47  
  48      let id = ast_util::stmt_id(s);
  49      fcx.push_ast_cleanup_scope(id);
  50  
  51      match s.node {
  52          ast::StmtExpr(e, _) | ast::StmtSemi(e, _) => {
  53              bcx = trans_stmt_semi(bcx, e);
  54          }
  55          ast::StmtDecl(d, _) => {
  56              match d.node {
  57                  ast::DeclLocal(ref local) => {
  58                      bcx = init_local(bcx, *local);
  59                      if cx.sess().opts.debuginfo == FullDebugInfo {
  60                          debuginfo::create_local_var_metadata(bcx, *local);
  61                      }
  62                  }
  63                  ast::DeclItem(i) => trans_item(cx.fcx.ccx, i)
  64              }
  65          }
  66          ast::StmtMac(..) => cx.tcx().sess.bug("unexpanded macro")
  67      }
  68  
  69      bcx = fcx.pop_and_trans_ast_cleanup_scope(
  70          bcx, ast_util::stmt_id(s));
  71  
  72      return bcx;
  73  }
  74  
  75  pub fn trans_stmt_semi<'a>(cx: &'a Block<'a>, e: &ast::Expr) -> &'a Block<'a> {
  76      let _icx = push_ctxt("trans_stmt_semi");
  77      let ty = expr_ty(cx, e);
  78      if ty::type_needs_drop(cx.tcx(), ty) {
  79          expr::trans_to_lvalue(cx, e, "stmt").bcx
  80      } else {
  81          expr::trans_into(cx, e, expr::Ignore)
  82      }
  83  }
  84  
  85  pub fn trans_block<'a>(bcx: &'a Block<'a>,
  86                         b: &ast::Block,
  87                         mut destexpr::Dest)
  88                         -> &'a Block<'a> {
  89      let _icx = push_ctxt("trans_block");
  90      let fcx = bcx.fcx;
  91      let mut bcx = bcx;
  92  
  93      fcx.push_ast_cleanup_scope(b.id);
  94  
  95      for s in b.stmts.iter() {
  96          bcx = trans_stmt(bcx, *s);
  97      }
  98  
  99      if dest != expr::Ignore {
 100          let block_ty = node_id_type(bcx, b.id);
 101          if b.expr.is_none() || type_is_zero_size(bcx.ccx(), block_ty) {
 102              dest = expr::Ignore;
 103          }
 104      }
 105  
 106      match b.expr {
 107          Some(e) => {
 108              bcx = expr::trans_into(bcx, e, dest);
 109          }
 110          None => {
 111              assert!(dest == expr::Ignore || bcx.unreachable.get());
 112          }
 113      }
 114  
 115      bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, b.id);
 116  
 117      return bcx;
 118  }
 119  
 120  pub fn trans_if<'a>(bcx: &'a Block<'a>,
 121                      if_idast::NodeId,
 122                      cond: &ast::Expr,
 123                      thnast::P<ast::Block>,
 124                      elsOption<@ast::Expr>,
 125                      destexpr::Dest)
 126                      -> &'a Block<'a> {
 127      debug!("trans_if(bcx={}, if_id={}, cond={}, thn={:?}, dest={})",
 128             bcx.to_str(), if_id, bcx.expr_to_str(cond), thn.id,
 129             dest.to_str(bcx.ccx()));
 130      let _icx = push_ctxt("trans_if");
 131      let mut bcx = bcx;
 132  
 133      let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool());
 134  
 135      // Drop branches that are known to be impossible
 136      if is_const(cond_val) && !is_undef(cond_val) {
 137          if const_to_uint(cond_val) == 1 {
 138              match els {
 139                  Some(elexpr) => {
 140                      let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx };
 141                      trans.visit_expr(elexpr, ());
 142                  }
 143                  None => {}
 144              }
 145              // if true { .. } [else { .. }]
 146              bcx = trans_block(bcx, thn, dest);
 147              debuginfo::clear_source_location(bcx.fcx);
 148          } else {
 149              let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx } ;
 150              trans.visit_block(thn, ());
 151  
 152              match els {
 153                  // if false { .. } else { .. }
 154                  Some(elexpr) => {
 155                      bcx = expr::trans_into(bcx, elexpr, dest);
 156                      debuginfo::clear_source_location(bcx.fcx);
 157                  }
 158  
 159                  // if false { .. }
 160                  None => { }
 161              }
 162          }
 163  
 164          return bcx;
 165      }
 166  
 167      let name = format!("then-block-{}-", thn.id);
 168      let then_bcx_in = bcx.fcx.new_id_block(name, thn.id);
 169      let then_bcx_out = trans_block(then_bcx_in, thn, dest);
 170      debuginfo::clear_source_location(bcx.fcx);
 171  
 172      let next_bcx;
 173      match els {
 174          Some(elexpr) => {
 175              let else_bcx_in = bcx.fcx.new_id_block("else-block", elexpr.id);
 176              let else_bcx_out = expr::trans_into(else_bcx_in, elexpr, dest);
 177              next_bcx = bcx.fcx.join_blocks(if_id,
 178                                             [then_bcx_out, else_bcx_out]);
 179              CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb);
 180          }
 181  
 182          None => {
 183              next_bcx = bcx.fcx.new_id_block("next-block", if_id);
 184              Br(then_bcx_out, next_bcx.llbb);
 185              CondBr(bcx, cond_val, then_bcx_in.llbb, next_bcx.llbb);
 186          }
 187      }
 188  
 189      // Clear the source location because it is still set to whatever has been translated
 190      // right before.
 191      debuginfo::clear_source_location(next_bcx.fcx);
 192  
 193      next_bcx
 194  }
 195  
 196  pub fn trans_while<'a>(bcx: &'a Block<'a>,
 197                         loop_idast::NodeId,
 198                         cond: &ast::Expr,
 199                         body: &ast::Block)
 200                         -> &'a Block<'a> {
 201      let _icx = push_ctxt("trans_while");
 202      let fcx = bcx.fcx;
 203  
 204      //            bcx
 205      //             |
 206      //         cond_bcx_in  <--------+
 207      //             |                 |
 208      //         cond_bcx_out          |
 209      //           |      |            |
 210      //           |    body_bcx_in    |
 211      // cleanup_blk      |            |
 212      //    |           body_bcx_out --+
 213      // next_bcx_in
 214  
 215      let next_bcx_in = fcx.new_id_block("while_exit", loop_id);
 216      let cond_bcx_in = fcx.new_id_block("while_cond", cond.id);
 217      let body_bcx_in = fcx.new_id_block("while_body", body.id);
 218  
 219      fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in, cond_bcx_in]);
 220  
 221      Br(bcx, cond_bcx_in.llbb);
 222  
 223      // compile the block where we will handle loop cleanups
 224      let cleanup_llbb = fcx.normal_exit_block(loop_id, cleanup::EXIT_BREAK);
 225  
 226      // compile the condition
 227      let Result {bcx: cond_bcx_out, val: cond_val} =
 228          expr::trans(cond_bcx_in, cond).to_llbool();
 229      CondBr(cond_bcx_out, cond_val, body_bcx_in.llbb, cleanup_llbb);
 230  
 231      // loop body:
 232      let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
 233      Br(body_bcx_out, cond_bcx_in.llbb);
 234  
 235      fcx.pop_loop_cleanup_scope(loop_id);
 236      return next_bcx_in;
 237  }
 238  
 239  pub fn trans_loop<'a>(bcx:&'a Block<'a>,
 240                        loop_idast::NodeId,
 241                        body: &ast::Block)
 242                        -> &'a Block<'a> {
 243      let _icx = push_ctxt("trans_loop");
 244      let fcx = bcx.fcx;
 245  
 246      //            bcx
 247      //             |
 248      //         body_bcx_in
 249      //             |
 250      //         body_bcx_out
 251      //
 252      // next_bcx
 253      //
 254      // Links between body_bcx_in and next_bcx are created by
 255      // break statements.
 256  
 257      let next_bcx_in = bcx.fcx.new_id_block("loop_exit", loop_id);
 258      let body_bcx_in = bcx.fcx.new_id_block("loop_body", body.id);
 259  
 260      fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in, body_bcx_in]);
 261  
 262      Br(bcx, body_bcx_in.llbb);
 263      let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
 264      Br(body_bcx_out, body_bcx_in.llbb);
 265  
 266      fcx.pop_loop_cleanup_scope(loop_id);
 267  
 268      return next_bcx_in;
 269  }
 270  
 271  pub fn trans_break_cont<'a>(bcx: &'a Block<'a>,
 272                              expr_idast::NodeId,
 273                              opt_labelOption<Ident>,
 274                              exit: uint)
 275                              -> &'a Block<'a> {
 276      let _icx = push_ctxt("trans_break_cont");
 277      let fcx = bcx.fcx;
 278  
 279      if bcx.unreachable.get() {
 280          return bcx;
 281      }
 282  
 283      // Locate loop that we will break to
 284      let loop_id = match opt_label {
 285          None => fcx.top_loop_scope(),
 286          Some(_) => {
 287              match bcx.tcx().def_map.borrow().find(&expr_id) {
 288                  Some(&ast::DefLabel(loop_id)) => loop_id,
 289                  ref r => {
 290                      bcx.tcx().sess.bug(format!("{:?} in def-map for label", r))
 291                  }
 292              }
 293          }
 294      };
 295  
 296      // Generate appropriate cleanup code and branch
 297      let cleanup_llbb = fcx.normal_exit_block(loop_id, exit);
 298      Br(bcx, cleanup_llbb);
 299      Unreachable(bcx); // anything afterwards should be ignored
 300      return bcx;
 301  }
 302  
 303  pub fn trans_break<'a>(bcx: &'a Block<'a>,
 304                         expr_idast::NodeId,
 305                         label_optOption<Ident>)
 306                         -> &'a Block<'a> {
 307      return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_BREAK);
 308  }
 309  
 310  pub fn trans_cont<'a>(bcx: &'a Block<'a>,
 311                        expr_idast::NodeId,
 312                        label_optOption<Ident>)
 313                        -> &'a Block<'a> {
 314      return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_LOOP);
 315  }
 316  
 317  pub fn trans_ret<'a>(bcx: &'a Block<'a>,
 318                       eOption<@ast::Expr>)
 319                       -> &'a Block<'a> {
 320      let _icx = push_ctxt("trans_ret");
 321      let fcx = bcx.fcx;
 322      let mut bcx = bcx;
 323      let dest = match bcx.fcx.llretptr.get() {
 324          None => expr::Ignore,
 325          Some(retptr) => expr::SaveIn(retptr),
 326      };
 327      match e {
 328          Some(x) => {
 329              bcx = expr::trans_into(bcx, x, dest);
 330          }
 331          _ => {}
 332      }
 333      let cleanup_llbb = fcx.return_exit_block();
 334      Br(bcx, cleanup_llbb);
 335      Unreachable(bcx);
 336      return bcx;
 337  }
 338  
 339  pub fn trans_fail<'a>(
 340                    bcx: &'a Block<'a>,
 341                    spSpan,
 342                    fail_strInternedString)
 343                    -> &'a Block<'a> {
 344      let ccx = bcx.ccx();
 345      let v_fail_str = C_cstr(ccx, fail_str, true);
 346      let _icx = push_ctxt("trans_fail_value");
 347      let loc = bcx.sess().codemap().lookup_char_pos(sp.lo);
 348      let v_filename = C_cstr(ccx,
 349                              token::intern_and_get_ident(loc.file
 350                                                             .name
 351                                                             .as_slice()),
 352                              true);
 353      let v_line = loc.line as int;
 354      let v_str = PointerCast(bcx, v_fail_str, Type::i8p(ccx));
 355      let v_filename = PointerCast(bcx, v_filename, Type::i8p(ccx));
 356      let args = vec!(v_str, v_filename, C_int(ccx, v_line));
 357      let did = langcall(bcx, Some(sp), "", FailFnLangItem);
 358      let bcx = callee::trans_lang_call(bcx,
 359                                        did,
 360                                        args.as_slice(),
 361                                        Some(expr::Ignore)).bcx;
 362      Unreachable(bcx);
 363      return bcx;
 364  }
 365  
 366  pub fn trans_fail_bounds_check<'a>(
 367                                 bcx: &'a Block<'a>,
 368                                 spSpan,
 369                                 indexValueRef,
 370                                 lenValueRef)
 371                                 -> &'a Block<'a> {
 372      let _icx = push_ctxt("trans_fail_bounds_check");
 373      let (filename, line) = filename_and_line_num_from_span(bcx, sp);
 374      let args = vec!(filename, line, index, len);
 375      let did = langcall(bcx, Some(sp), "", FailBoundsCheckFnLangItem);
 376      let bcx = callee::trans_lang_call(bcx,
 377                                        did,
 378                                        args.as_slice(),
 379                                        Some(expr::Ignore)).bcx;
 380      Unreachable(bcx);
 381      return bcx;
 382  }


librustc/middle/trans/controlflow.rs:74:1-74:1 -fn- definition:
pub fn trans_stmt_semi<'a>(cx: &'a Block<'a>, e: &ast::Expr) -> &'a Block<'a> {
    let _icx = push_ctxt("trans_stmt_semi");
    let ty = expr_ty(cx, e);
references:- 2
librustc/middle/trans/base.rs:
976:             Some(init) => {
977:                 return controlflow::trans_stmt_semi(bcx, init)
978:             }
librustc/middle/trans/controlflow.rs:
52:         ast::StmtExpr(e, _) | ast::StmtSemi(e, _) => {
53:             bcx = trans_stmt_semi(bcx, e);
54:         }


librustc/middle/trans/controlflow.rs:270:1-270:1 -fn- definition:
pub fn trans_break_cont<'a>(bcx: &'a Block<'a>,
                            expr_id: ast::NodeId,
                            opt_label: Option<Ident>,
references:- 2
306:                        -> &'a Block<'a> {
307:     return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_BREAK);
308: }
--
313:                       -> &'a Block<'a> {
314:     return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_LOOP);
315: }


librustc/middle/trans/controlflow.rs:338:1-338:1 -fn- definition:
pub fn trans_fail<'a>(
                  bcx: &'a Block<'a>,
                  sp: Span,
references:- 2
librustc/middle/trans/_match.rs:
1147:         let fail_cx = fcx.new_block(false, "case_fallthrough", None);
1148:         controlflow::trans_fail(fail_cx, self.sp, self.msg.clone());
1149:         self.finished.set(Some(fail_cx.llbb));
librustc/middle/trans/base.rs:
840:     with_cond(cx, is_zero, |bcx| {
841:         controlflow::trans_fail(bcx, span, InternedString::new(text))
842:     })


librustc/middle/trans/controlflow.rs:84:1-84:1 -fn- definition:
pub fn trans_block<'a>(bcx: &'a Block<'a>,
                       b: &ast::Block,
                       mut dest: expr::Dest)
references:- 6
168:     let then_bcx_in = bcx.fcx.new_id_block(name, thn.id);
169:     let then_bcx_out = trans_block(then_bcx_in, thn, dest);
170:     debuginfo::clear_source_location(bcx.fcx);
--
262:     Br(bcx, body_bcx_in.llbb);
263:     let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
264:     Br(body_bcx_out, body_bcx_in.llbb);
librustc/middle/trans/expr.rs:
666:         ast::ExprBlock(blk) => {
667:             controlflow::trans_block(bcx, blk, dest)
668:         }
librustc/middle/trans/base.rs:
1429:     // (trans_block, trans_expr, et cetera).
1430:     bcx = controlflow::trans_block(bcx, body, dest);