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.
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.
12 use driver::config::FullDebugInfo;
14 use middle::lang_items::{FailFnLangItem, FailBoundsCheckFnLangItem};
15 use middle::trans::base::*;
16 use middle::trans::build::*;
17 use middle::trans::callee;
18 use middle::trans::cleanup::CleanupMethods;
19 use middle::trans::cleanup;
20 use middle::trans::common::*;
21 use middle::trans::debuginfo;
22 use middle::trans::expr;
24 use util::ppaux::Repr;
27 use syntax::ast::Ident;
29 use syntax::codemap::Span;
30 use syntax::parse::token::InternedString;
31 use syntax::parse::token;
32 use syntax::visit::Visitor;
36 pub fn trans_stmt<'a>(cx: &'a Block<'a>,
39 let _icx = push_ctxt("trans_stmt");
41 debug!("trans_stmt({})", s.repr(cx.tcx()));
43 if cx.sess().asm_comments() {
44 add_span_comment(cx, s.span, s.repr(cx.tcx()).as_slice());
49 let id = ast_util::stmt_id(s);
50 fcx.push_ast_cleanup_scope(id);
53 ast::StmtExpr(ref e, _) | ast::StmtSemi(ref e, _) => {
54 bcx = trans_stmt_semi(bcx, &**e);
56 ast::StmtDecl(d, _) => {
58 ast::DeclLocal(ref local) => {
59 bcx = init_local(bcx, &**local);
60 if cx.sess().opts.debuginfo == FullDebugInfo {
61 debuginfo::create_local_var_metadata(bcx, &**local);
64 ast::DeclItem(ref i) => trans_item(cx.fcx.ccx, &**i)
67 ast::StmtMac(..) => cx.tcx().sess.bug("unexpanded macro")
70 bcx = fcx.pop_and_trans_ast_cleanup_scope(
71 bcx, ast_util::stmt_id(s));
76 pub fn trans_stmt_semi<'a>(cx: &'a Block<'a>, e: &ast::Expr) -> &'a Block<'a> {
77 let _icx = push_ctxt("trans_stmt_semi");
78 let ty = expr_ty(cx, e);
79 if ty::type_needs_drop(cx.tcx(), ty) {
80 expr::trans_to_lvalue(cx, e, "stmt").bcx
82 expr::trans_into(cx, e, expr::Ignore)
86 pub fn trans_block<'a>(bcx: &'a Block<'a>,
90 let _icx = push_ctxt("trans_block");
94 fcx.push_ast_cleanup_scope(b.id);
96 for s in b.stmts.iter() {
97 bcx = trans_stmt(bcx, &**s);
100 if dest != expr::Ignore {
101 let block_ty = node_id_type(bcx, b.id);
102 if b.expr.is_none() || type_is_zero_size(bcx.ccx(), block_ty) {
109 bcx = expr::trans_into(bcx, &**e, dest);
112 assert!(dest == expr::Ignore || bcx.unreachable.get());
116 bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, b.id);
121 pub fn trans_if<'a>(bcx: &'a Block<'a>,
124 thn: ast::P<ast::Block>,
125 els: Option<Gc<ast::Expr>>,
128 debug!("trans_if(bcx={}, if_id={}, cond={}, thn={:?}, dest={})",
129 bcx.to_str(), if_id, bcx.expr_to_str(cond), thn.id,
130 dest.to_str(bcx.ccx()));
131 let _icx = push_ctxt("trans_if");
134 let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool());
136 // Drop branches that are known to be impossible
137 if is_const(cond_val) && !is_undef(cond_val) {
138 if const_to_uint(cond_val) == 1 {
141 let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx };
142 trans.visit_expr(&*elexpr, ());
146 // if true { .. } [else { .. }]
147 bcx = trans_block(bcx, &*thn, dest);
148 debuginfo::clear_source_location(bcx.fcx);
150 let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx } ;
151 trans.visit_block(&*thn, ());
154 // if false { .. } else { .. }
156 bcx = expr::trans_into(bcx, &*elexpr, dest);
157 debuginfo::clear_source_location(bcx.fcx);
168 let name = format!("then-block-{}-", thn.id);
169 let then_bcx_in = bcx.fcx.new_id_block(name.as_slice(), thn.id);
170 let then_bcx_out = trans_block(then_bcx_in, &*thn, dest);
171 debuginfo::clear_source_location(bcx.fcx);
176 let else_bcx_in = bcx.fcx.new_id_block("else-block", elexpr.id);
177 let else_bcx_out = expr::trans_into(else_bcx_in, &*elexpr, dest);
178 next_bcx = bcx.fcx.join_blocks(if_id,
179 [then_bcx_out, else_bcx_out]);
180 CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb);
184 next_bcx = bcx.fcx.new_id_block("next-block", if_id);
185 Br(then_bcx_out, next_bcx.llbb);
186 CondBr(bcx, cond_val, then_bcx_in.llbb, next_bcx.llbb);
190 // Clear the source location because it is still set to whatever has been translated
192 debuginfo::clear_source_location(next_bcx.fcx);
197 pub fn trans_while<'a>(bcx: &'a Block<'a>,
198 loop_id: ast::NodeId,
202 let _icx = push_ctxt("trans_while");
207 // cond_bcx_in <--------+
213 // | body_bcx_out --+
216 let next_bcx_in = fcx.new_id_block("while_exit", loop_id);
217 let cond_bcx_in = fcx.new_id_block("while_cond", cond.id);
218 let body_bcx_in = fcx.new_id_block("while_body", body.id);
220 fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in, cond_bcx_in]);
222 Br(bcx, cond_bcx_in.llbb);
224 // compile the block where we will handle loop cleanups
225 let cleanup_llbb = fcx.normal_exit_block(loop_id, cleanup::EXIT_BREAK);
227 // compile the condition
228 let Result {bcx: cond_bcx_out, val: cond_val} =
229 expr::trans(cond_bcx_in, cond).to_llbool();
230 CondBr(cond_bcx_out, cond_val, body_bcx_in.llbb, cleanup_llbb);
233 let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
234 Br(body_bcx_out, cond_bcx_in.llbb);
236 fcx.pop_loop_cleanup_scope(loop_id);
240 pub fn trans_loop<'a>(bcx:&'a Block<'a>,
241 loop_id: ast::NodeId,
244 let _icx = push_ctxt("trans_loop");
255 // Links between body_bcx_in and next_bcx are created by
258 let next_bcx_in = bcx.fcx.new_id_block("loop_exit", loop_id);
259 let body_bcx_in = bcx.fcx.new_id_block("loop_body", body.id);
261 fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in, body_bcx_in]);
263 Br(bcx, body_bcx_in.llbb);
264 let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
265 Br(body_bcx_out, body_bcx_in.llbb);
267 fcx.pop_loop_cleanup_scope(loop_id);
269 if ty::type_is_bot(node_id_type(bcx, loop_id)) {
270 Unreachable(next_bcx_in);
276 pub fn trans_break_cont<'a>(bcx: &'a Block<'a>,
277 expr_id: ast::NodeId,
278 opt_label: Option<Ident>,
281 let _icx = push_ctxt("trans_break_cont");
284 if bcx.unreachable.get() {
288 // Locate loop that we will break to
289 let loop_id = match opt_label {
290 None => fcx.top_loop_scope(),
292 match bcx.tcx().def_map.borrow().find(&expr_id) {
293 Some(&def::DefLabel(loop_id)) => loop_id,
295 bcx.tcx().sess.bug(format!("{:?} in def-map for label",
302 // Generate appropriate cleanup code and branch
303 let cleanup_llbb = fcx.normal_exit_block(loop_id, exit);
304 Br(bcx, cleanup_llbb);
305 Unreachable(bcx); // anything afterwards should be ignored
309 pub fn trans_break<'a>(bcx: &'a Block<'a>,
310 expr_id: ast::NodeId,
311 label_opt: Option<Ident>)
313 return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_BREAK);
316 pub fn trans_cont<'a>(bcx: &'a Block<'a>,
317 expr_id: ast::NodeId,
318 label_opt: Option<Ident>)
320 return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_LOOP);
323 pub fn trans_ret<'a>(bcx: &'a Block<'a>,
324 e: Option<Gc<ast::Expr>>)
326 let _icx = push_ctxt("trans_ret");
329 let dest = match bcx.fcx.llretptr.get() {
330 None => expr::Ignore,
331 Some(retptr) => expr::SaveIn(retptr),
335 bcx = expr::trans_into(bcx, &*x, dest);
339 let cleanup_llbb = fcx.return_exit_block();
340 Br(bcx, cleanup_llbb);
345 fn str_slice_arg<'a>(bcx: &'a Block<'a>, s: InternedString) -> ValueRef {
347 let s = C_str_slice(ccx, s);
348 let slot = alloca(bcx, val_ty(s), "__temp");
353 pub fn trans_fail<'a>(
356 fail_str: InternedString)
359 let _icx = push_ctxt("trans_fail_value");
361 let v_str = str_slice_arg(bcx, fail_str);
362 let loc = bcx.sess().codemap().lookup_char_pos(sp.lo);
363 let filename = token::intern_and_get_ident(loc.file.name.as_slice());
364 let v_filename = str_slice_arg(bcx, filename);
365 let v_line = loc.line as int;
366 let args = vec!(v_str, v_filename, C_int(ccx, v_line));
367 let did = langcall(bcx, Some(sp), "", FailFnLangItem);
368 let bcx = callee::trans_lang_call(bcx,
371 Some(expr::Ignore)).bcx;
376 pub fn trans_fail_bounds_check<'a>(
382 let _icx = push_ctxt("trans_fail_bounds_check");
384 // Extract the file/line from the span
385 let loc = bcx.sess().codemap().lookup_char_pos(sp.lo);
386 let filename = token::intern_and_get_ident(loc.file.name.as_slice());
388 // Invoke the lang item
389 let filename = str_slice_arg(bcx, filename);
390 let line = C_int(bcx.ccx(), loc.line as int);
391 let args = vec!(filename, line, index, len);
392 let did = langcall(bcx, Some(sp), "", FailBoundsCheckFnLangItem);
393 let bcx = callee::trans_lang_call(bcx,
396 Some(expr::Ignore)).bcx;