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 rustc_data_structures
::fnv
::FnvHashMap
;
15 use build
::{BlockAnd, BlockAndExtension, Builder}
;
16 use build
::expr
::category
::{Category, RvalueFunc}
;
18 use rustc
::mir
::repr
::*;
20 impl<'a
,'tcx
> Builder
<'a
,'tcx
> {
21 /// Compile `expr`, yielding an rvalue.
22 pub fn as_rvalue
<M
>(&mut self, block
: BasicBlock
, expr
: M
) -> BlockAnd
<Rvalue
<'tcx
>>
23 where M
: Mirror
<'tcx
, Output
= Expr
<'tcx
>>
25 let expr
= self.hir
.mirror(expr
);
26 self.expr_as_rvalue(block
, expr
)
29 fn expr_as_rvalue(&mut self,
30 mut block
: BasicBlock
,
32 -> BlockAnd
<Rvalue
<'tcx
>> {
33 debug
!("expr_as_rvalue(block={:?}, expr={:?})", block
, expr
);
36 let scope_id
= this
.innermost_scope_id();
37 let expr_span
= expr
.span
;
40 ExprKind
::Scope { extent, value }
=> {
41 this
.in_scope(extent
, block
, |this
, _
| this
.as_rvalue(block
, value
))
43 ExprKind
::InlineAsm { asm, outputs, inputs }
=> {
44 let outputs
= outputs
.into_iter().map(|output
| {
45 unpack
!(block
= this
.as_lvalue(block
, output
))
48 let inputs
= inputs
.into_iter().map(|input
| {
49 unpack
!(block
= this
.as_operand(block
, input
))
52 block
.and(Rvalue
::InlineAsm
{
58 ExprKind
::Repeat { value, count }
=> {
59 let value_operand
= unpack
!(block
= this
.as_operand(block
, value
));
60 block
.and(Rvalue
::Repeat(value_operand
, count
))
62 ExprKind
::Borrow { region, borrow_kind, arg }
=> {
63 let arg_lvalue
= unpack
!(block
= this
.as_lvalue(block
, arg
));
64 block
.and(Rvalue
::Ref(region
, borrow_kind
, arg_lvalue
))
66 ExprKind
::Binary { op, lhs, rhs }
=> {
67 let lhs
= unpack
!(block
= this
.as_operand(block
, lhs
));
68 let rhs
= unpack
!(block
= this
.as_operand(block
, rhs
));
69 block
.and(Rvalue
::BinaryOp(op
, lhs
, rhs
))
71 ExprKind
::Unary { op, arg }
=> {
72 let arg
= unpack
!(block
= this
.as_operand(block
, arg
));
73 block
.and(Rvalue
::UnaryOp(op
, arg
))
75 ExprKind
::Box { value, value_extents }
=> {
76 let value
= this
.hir
.mirror(value
);
77 let result
= this
.temp(expr
.ty
);
78 // to start, malloc some memory of suitable type (thus far, uninitialized):
79 this
.cfg
.push_assign(block
, scope_id
, expr_span
, &result
, Rvalue
::Box(value
.ty
));
80 this
.in_scope(value_extents
, block
, |this
, _
| {
81 // schedule a shallow free of that memory, lest we unwind:
82 this
.schedule_box_free(expr_span
, value_extents
, &result
, value
.ty
);
83 // initialize the box contents:
84 unpack
!(block
= this
.into(&result
.clone().deref(), block
, value
));
85 block
.and(Rvalue
::Use(Operand
::Consume(result
)))
88 ExprKind
::Cast { source }
=> {
89 let source
= this
.hir
.mirror(source
);
90 if source
.ty
== expr
.ty
{
91 this
.expr_as_rvalue(block
, source
)
93 let source
= unpack
!(block
= this
.as_operand(block
, source
));
94 block
.and(Rvalue
::Cast(CastKind
::Misc
, source
, expr
.ty
))
97 ExprKind
::ReifyFnPointer { source }
=> {
98 let source
= unpack
!(block
= this
.as_operand(block
, source
));
99 block
.and(Rvalue
::Cast(CastKind
::ReifyFnPointer
, source
, expr
.ty
))
101 ExprKind
::UnsafeFnPointer { source }
=> {
102 let source
= unpack
!(block
= this
.as_operand(block
, source
));
103 block
.and(Rvalue
::Cast(CastKind
::UnsafeFnPointer
, source
, expr
.ty
))
105 ExprKind
::Unsize { source }
=> {
106 let source
= unpack
!(block
= this
.as_operand(block
, source
));
107 block
.and(Rvalue
::Cast(CastKind
::Unsize
, source
, expr
.ty
))
109 ExprKind
::Vec { fields }
=> {
110 // (*) We would (maybe) be closer to trans if we
111 // handled this and other aggregate cases via
112 // `into()`, not `as_rvalue` -- in that case, instead
117 // dest = Rvalue::Aggregate(Foo, [tmp1, tmp2])
119 // we could just generate
124 // The problem is that then we would need to:
126 // (a) have a more complex mechanism for handling
128 // (b) distinguish the case where the type `Foo` has a
129 // destructor, in which case creating an instance
130 // as a whole "arms" the destructor, and you can't
131 // write individual fields; and,
132 // (c) handle the case where the type Foo has no
133 // fields. We don't want `let x: ();` to compile
134 // to the same MIR as `let x = ();`.
136 // first process the set of fields
139 .map(|f
| unpack
!(block
= this
.as_operand(block
, f
)))
142 block
.and(Rvalue
::Aggregate(AggregateKind
::Vec
, fields
))
144 ExprKind
::Tuple { fields }
=> { // see (*) above
145 // first process the set of fields
148 .map(|f
| unpack
!(block
= this
.as_operand(block
, f
)))
151 block
.and(Rvalue
::Aggregate(AggregateKind
::Tuple
, fields
))
153 ExprKind
::Closure { closure_id, substs, upvars }
=> { // see (*) above
156 .map(|upvar
| unpack
!(block
= this
.as_operand(block
, upvar
)))
158 block
.and(Rvalue
::Aggregate(AggregateKind
::Closure(closure_id
, substs
), upvars
))
161 adt_def
, variant_index
, substs
, fields
, base
162 } => { // see (*) above
163 // first process the set of fields that were provided
164 // (evaluating them in order given by user)
165 let fields_map
: FnvHashMap
<_
, _
> =
167 .map(|f
| (f
.name
, unpack
!(block
= this
.as_operand(block
, f
.expr
))))
170 let field_names
= this
.hir
.all_fields(adt_def
, variant_index
);
172 let fields
= if let Some(FruInfo { base, field_types }
) = base
{
173 let base
= unpack
!(block
= this
.as_lvalue(block
, base
));
175 // MIR does not natively support FRU, so for each
176 // base-supplied field, generate an operand that
177 // reads it from the base.
178 field_names
.into_iter()
179 .zip(field_types
.into_iter())
180 .map(|(n
, ty
)| match fields_map
.get(&n
) {
181 Some(v
) => v
.clone(),
182 None
=> Operand
::Consume(base
.clone().field(n
, ty
))
186 field_names
.iter().map(|n
| fields_map
[n
].clone()).collect()
189 block
.and(Rvalue
::Aggregate(AggregateKind
::Adt(adt_def
, variant_index
, substs
),
192 ExprKind
::Literal { .. }
|
193 ExprKind
::Block { .. }
|
194 ExprKind
::Match { .. }
|
195 ExprKind
::If { .. }
|
196 ExprKind
::Loop { .. }
|
197 ExprKind
::LogicalOp { .. }
|
198 ExprKind
::Call { .. }
|
199 ExprKind
::Field { .. }
|
200 ExprKind
::Deref { .. }
|
201 ExprKind
::Index { .. }
|
202 ExprKind
::VarRef { .. }
|
204 ExprKind
::Assign { .. }
|
205 ExprKind
::AssignOp { .. }
|
206 ExprKind
::Break { .. }
|
207 ExprKind
::Continue { .. }
|
208 ExprKind
::Return { .. }
|
209 ExprKind
::StaticRef { .. }
=> {
210 // these do not have corresponding `Rvalue` variants,
211 // so make an operand and then return that
212 debug_assert
!(match Category
::of(&expr
.kind
) {
213 Some(Category
::Rvalue(RvalueFunc
::AsRvalue
)) => false,
216 let operand
= unpack
!(block
= this
.as_operand(block
, expr
));
217 block
.and(Rvalue
::Use(operand
))