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::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 util::ppaux::Repr;
24 use middle::trans::type_::Type;
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;
34 pub fn trans_stmt<'a>(cx: &'a Block<'a>,
37 let _icx = push_ctxt("trans_stmt");
39 debug!("trans_stmt({})", s.repr(cx.tcx()));
41 if cx.sess().asm_comments() {
42 add_span_comment(cx, s.span, s.repr(cx.tcx()));
47 let id = ast_util::stmt_id(s);
48 fcx.push_ast_cleanup_scope(id);
51 ast::StmtExpr(e, _) | ast::StmtSemi(e, _) => {
52 bcx = expr::trans_into(cx, e, expr::Ignore);
54 ast::StmtDecl(d, _) => {
56 ast::DeclLocal(ref local) => {
57 bcx = init_local(bcx, *local);
58 if cx.sess().opts.debuginfo == FullDebugInfo {
59 debuginfo::create_local_var_metadata(bcx, *local);
62 ast::DeclItem(i) => trans_item(cx.fcx.ccx, i)
65 ast::StmtMac(..) => cx.tcx().sess.bug("unexpanded macro")
68 bcx = fcx.pop_and_trans_ast_cleanup_scope(
69 bcx, ast_util::stmt_id(s));
74 pub fn trans_block<'a>(bcx: &'a Block<'a>,
78 let _icx = push_ctxt("trans_block");
82 fcx.push_ast_cleanup_scope(b.id);
84 for s in b.stmts.iter() {
85 bcx = trans_stmt(bcx, *s);
88 if dest != expr::Ignore {
89 let block_ty = node_id_type(bcx, b.id);
90 if b.expr.is_none() || type_is_zero_size(bcx.ccx(), block_ty) {
97 bcx = expr::trans_into(bcx, e, dest);
100 assert!(dest == expr::Ignore || bcx.unreachable.get());
104 bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, b.id);
109 pub fn trans_if<'a>(bcx: &'a Block<'a>,
112 thn: ast::P<ast::Block>,
113 els: Option<@ast::Expr>,
116 debug!("trans_if(bcx={}, if_id={}, cond={}, thn={:?}, dest={})",
117 bcx.to_str(), if_id, bcx.expr_to_str(cond), thn.id,
118 dest.to_str(bcx.ccx()));
119 let _icx = push_ctxt("trans_if");
122 let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool());
124 // Drop branches that are known to be impossible
125 if is_const(cond_val) && !is_undef(cond_val) {
126 if const_to_uint(cond_val) == 1 {
129 let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx };
130 trans.visit_expr(elexpr, ());
134 // if true { .. } [else { .. }]
135 bcx = trans_block(bcx, thn, dest);
136 debuginfo::clear_source_location(bcx.fcx);
138 let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx } ;
139 trans.visit_block(thn, ());
142 // if false { .. } else { .. }
144 bcx = expr::trans_into(bcx, elexpr, dest);
145 debuginfo::clear_source_location(bcx.fcx);
156 let name = format!("then-block-{}-", thn.id);
157 let then_bcx_in = bcx.fcx.new_id_block(name, thn.id);
158 let then_bcx_out = trans_block(then_bcx_in, thn, dest);
159 debuginfo::clear_source_location(bcx.fcx);
164 let else_bcx_in = bcx.fcx.new_id_block("else-block", elexpr.id);
165 let else_bcx_out = expr::trans_into(else_bcx_in, elexpr, dest);
166 next_bcx = bcx.fcx.join_blocks(if_id,
167 [then_bcx_out, else_bcx_out]);
168 CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb);
172 next_bcx = bcx.fcx.new_id_block("next-block", if_id);
173 Br(then_bcx_out, next_bcx.llbb);
174 CondBr(bcx, cond_val, then_bcx_in.llbb, next_bcx.llbb);
178 // Clear the source location because it is still set to whatever has been translated
180 debuginfo::clear_source_location(next_bcx.fcx);
185 pub fn trans_while<'a>(bcx: &'a Block<'a>,
186 loop_id: ast::NodeId,
190 let _icx = push_ctxt("trans_while");
195 // cond_bcx_in <--------+
201 // | body_bcx_out --+
204 let next_bcx_in = fcx.new_id_block("while_exit", loop_id);
205 let cond_bcx_in = fcx.new_id_block("while_cond", cond.id);
206 let body_bcx_in = fcx.new_id_block("while_body", body.id);
208 fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in, cond_bcx_in]);
210 Br(bcx, cond_bcx_in.llbb);
212 // compile the block where we will handle loop cleanups
213 let cleanup_llbb = fcx.normal_exit_block(loop_id, cleanup::EXIT_BREAK);
215 // compile the condition
216 let Result {bcx: cond_bcx_out, val: cond_val} =
217 expr::trans(cond_bcx_in, cond).to_llbool();
218 CondBr(cond_bcx_out, cond_val, body_bcx_in.llbb, cleanup_llbb);
221 let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
222 Br(body_bcx_out, cond_bcx_in.llbb);
224 fcx.pop_loop_cleanup_scope(loop_id);
228 pub fn trans_loop<'a>(bcx:&'a Block<'a>,
229 loop_id: ast::NodeId,
232 let _icx = push_ctxt("trans_loop");
243 // Links between body_bcx_in and next_bcx are created by
246 let next_bcx_in = bcx.fcx.new_id_block("loop_exit", loop_id);
247 let body_bcx_in = bcx.fcx.new_id_block("loop_body", body.id);
249 fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in, body_bcx_in]);
251 Br(bcx, body_bcx_in.llbb);
252 let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
253 Br(body_bcx_out, body_bcx_in.llbb);
255 fcx.pop_loop_cleanup_scope(loop_id);
260 pub fn trans_break_cont<'a>(bcx: &'a Block<'a>,
261 expr_id: ast::NodeId,
262 opt_label: Option<Ident>,
265 let _icx = push_ctxt("trans_break_cont");
268 if bcx.unreachable.get() {
272 // Locate loop that we will break to
273 let loop_id = match opt_label {
274 None => fcx.top_loop_scope(),
276 let def_map = bcx.tcx().def_map.borrow();
277 match def_map.get().find(&expr_id) {
278 Some(&ast::DefLabel(loop_id)) => loop_id,
280 bcx.tcx().sess.bug(format!("{:?} in def-map for label", r))
286 // Generate appropriate cleanup code and branch
287 let cleanup_llbb = fcx.normal_exit_block(loop_id, exit);
288 Br(bcx, cleanup_llbb);
289 Unreachable(bcx); // anything afterwards should be ignored
293 pub fn trans_break<'a>(bcx: &'a Block<'a>,
294 expr_id: ast::NodeId,
295 label_opt: Option<Ident>)
297 return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_BREAK);
300 pub fn trans_cont<'a>(bcx: &'a Block<'a>,
301 expr_id: ast::NodeId,
302 label_opt: Option<Ident>)
304 return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_LOOP);
307 pub fn trans_ret<'a>(bcx: &'a Block<'a>,
308 e: Option<@ast::Expr>)
310 let _icx = push_ctxt("trans_ret");
313 let dest = match bcx.fcx.llretptr.get() {
314 None => expr::Ignore,
315 Some(retptr) => expr::SaveIn(retptr),
319 bcx = expr::trans_into(bcx, x, dest);
323 let cleanup_llbb = fcx.return_exit_block();
324 Br(bcx, cleanup_llbb);
329 pub fn trans_fail<'a>(
332 fail_str: InternedString)
334 let v_fail_str = C_cstr(bcx.ccx(), fail_str);
335 let _icx = push_ctxt("trans_fail_value");
337 let sess = bcx.sess();
338 let loc = sess.parse_sess.cm.lookup_char_pos(sp.lo);
339 let v_filename = C_cstr(bcx.ccx(),
340 token::intern_and_get_ident(loc.file.name));
341 let v_line = loc.line as int;
342 let v_str = PointerCast(bcx, v_fail_str, Type::i8p());
343 let v_filename = PointerCast(bcx, v_filename, Type::i8p());
344 let args = ~[v_str, v_filename, C_int(ccx, v_line)];
345 let did = langcall(bcx, Some(sp), "", FailFnLangItem);
346 let bcx = callee::trans_lang_call(bcx, did, args, Some(expr::Ignore)).bcx;
351 pub fn trans_fail_bounds_check<'a>(
357 let _icx = push_ctxt("trans_fail_bounds_check");
358 let (filename, line) = filename_and_line_num_from_span(bcx, sp);
359 let args = ~[filename, line, index, len];
360 let did = langcall(bcx, Some(sp), "", FailBoundsCheckFnLangItem);
361 let bcx = callee::trans_lang_call(bcx, did, args, Some(expr::Ignore)).bcx;