1 // Copyright 2015 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.
11 //! See docs in build/expr/mod.rs
13 use build::{BlockAnd, BlockAndExtension, Builder};
14 use build::expr::category::Category;
16 use rustc::middle::region::CodeExtent;
19 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
20 /// Compile `expr` into a fresh temporary. This is used when building
21 /// up rvalues so as to freeze the value that will be consumed.
22 pub fn as_temp<M>(&mut self,
24 temp_lifetime: Option<CodeExtent>,
26 -> BlockAnd<Lvalue<'tcx>>
27 where M: Mirror<'tcx, Output = Expr<'tcx>>
29 let expr = self.hir.mirror(expr);
30 self.expr_as_temp(block, temp_lifetime, expr)
33 fn expr_as_temp(&mut self,
34 mut block: BasicBlock,
35 temp_lifetime: Option<CodeExtent>,
37 -> BlockAnd<Lvalue<'tcx>> {
38 debug!("expr_as_temp(block={:?}, expr={:?})", block, expr);
41 if let ExprKind::Scope { extent, value } = expr.kind {
42 return this.in_scope(extent, block, |this| {
43 this.as_temp(block, temp_lifetime, value)
47 let expr_ty = expr.ty.clone();
48 let expr_span = expr.span;
49 let temp = this.temp(expr_ty.clone(), expr_span);
50 let source_info = this.source_info(expr_span);
52 if expr.temp_lifetime_was_shrunk && this.hir.needs_drop(expr_ty) {
53 this.hir.tcx().sess.span_warn(
55 "this temporary used to live longer - see issue #39283 \
56 (https://github.com/rust-lang/rust/issues/39283)");
59 if !expr_ty.is_never() && temp_lifetime.is_some() {
60 this.cfg.push(block, Statement {
61 source_info: source_info,
62 kind: StatementKind::StorageLive(temp.clone())
66 // Careful here not to cause an infinite cycle. If we always
67 // called `into`, then for lvalues like `x.f`, it would
68 // eventually fallback to us, and we'd loop. There's a reason
69 // for this: `as_temp` is the point where we bridge the "by
70 // reference" semantics of `as_lvalue` with the "by value"
71 // semantics of `into`, `as_operand`, `as_rvalue`, and (of
73 match Category::of(&expr.kind).unwrap() {
75 let lvalue = unpack!(block = this.as_lvalue(block, expr));
76 let rvalue = Rvalue::Use(Operand::Consume(lvalue));
77 this.cfg.push_assign(block, source_info, &temp, rvalue);
80 unpack!(block = this.into(&temp, block, expr));
84 // In constants, temp_lifetime is None. We should not need to drop
85 // anything because no values with a destructor can be created in
86 // a constant at this time, even if the type may need dropping.
87 if let Some(temp_lifetime) = temp_lifetime {
88 this.schedule_drop(expr_span, temp_lifetime, &temp, expr_ty);