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 expr_span
= expr
.span
;
39 ExprKind
::Scope { extent, value }
=> {
40 this
.in_scope(extent
, block
, |this
| this
.as_rvalue(block
, value
))
42 ExprKind
::InlineAsm { asm }
=> {
43 block
.and(Rvalue
::InlineAsm(asm
.clone()))
45 ExprKind
::Repeat { value, count }
=> {
46 let value_operand
= unpack
!(block
= this
.as_operand(block
, value
));
47 block
.and(Rvalue
::Repeat(value_operand
, count
))
49 ExprKind
::Borrow { region, borrow_kind, arg }
=> {
50 let arg_lvalue
= unpack
!(block
= this
.as_lvalue(block
, arg
));
51 block
.and(Rvalue
::Ref(region
, borrow_kind
, arg_lvalue
))
53 ExprKind
::Binary { op, lhs, rhs }
=> {
54 let lhs
= unpack
!(block
= this
.as_operand(block
, lhs
));
55 let rhs
= unpack
!(block
= this
.as_operand(block
, rhs
));
56 block
.and(Rvalue
::BinaryOp(op
, lhs
, rhs
))
58 ExprKind
::Unary { op, arg }
=> {
59 let arg
= unpack
!(block
= this
.as_operand(block
, arg
));
60 block
.and(Rvalue
::UnaryOp(op
, arg
))
62 ExprKind
::Box { value, value_extents }
=> {
63 let value
= this
.hir
.mirror(value
);
64 let result
= this
.temp(expr
.ty
);
65 // to start, malloc some memory of suitable type (thus far, uninitialized):
66 this
.cfg
.push_assign(block
, expr_span
, &result
, Rvalue
::Box(value
.ty
));
67 this
.in_scope(value_extents
, block
, |this
| {
68 // schedule a shallow free of that memory, lest we unwind:
69 this
.schedule_box_free(expr_span
, value_extents
, &result
, value
.ty
);
70 // initialize the box contents:
71 unpack
!(block
= this
.into(&result
.clone().deref(), block
, value
));
72 block
.and(Rvalue
::Use(Operand
::Consume(result
)))
75 ExprKind
::Cast { source }
=> {
76 let source
= unpack
!(block
= this
.as_operand(block
, source
));
77 block
.and(Rvalue
::Cast(CastKind
::Misc
, source
, expr
.ty
))
79 ExprKind
::ReifyFnPointer { source }
=> {
80 let source
= unpack
!(block
= this
.as_operand(block
, source
));
81 block
.and(Rvalue
::Cast(CastKind
::ReifyFnPointer
, source
, expr
.ty
))
83 ExprKind
::UnsafeFnPointer { source }
=> {
84 let source
= unpack
!(block
= this
.as_operand(block
, source
));
85 block
.and(Rvalue
::Cast(CastKind
::UnsafeFnPointer
, source
, expr
.ty
))
87 ExprKind
::Unsize { source }
=> {
88 let source
= unpack
!(block
= this
.as_operand(block
, source
));
89 block
.and(Rvalue
::Cast(CastKind
::Unsize
, source
, expr
.ty
))
91 ExprKind
::Vec { fields }
=> {
92 // (*) We would (maybe) be closer to trans if we
93 // handled this and other aggregate cases via
94 // `into()`, not `as_rvalue` -- in that case, instead
99 // dest = Rvalue::Aggregate(Foo, [tmp1, tmp2])
101 // we could just generate
106 // The problem is that then we would need to:
108 // (a) have a more complex mechanism for handling
110 // (b) distinguish the case where the type `Foo` has a
111 // destructor, in which case creating an instance
112 // as a whole "arms" the destructor, and you can't
113 // write individual fields; and,
114 // (c) handle the case where the type Foo has no
115 // fields. We don't want `let x: ();` to compile
116 // to the same MIR as `let x = ();`.
118 // first process the set of fields
121 .map(|f
| unpack
!(block
= this
.as_operand(block
, f
)))
124 block
.and(Rvalue
::Aggregate(AggregateKind
::Vec
, fields
))
126 ExprKind
::Tuple { fields }
=> { // see (*) above
127 // first process the set of fields
130 .map(|f
| unpack
!(block
= this
.as_operand(block
, f
)))
133 block
.and(Rvalue
::Aggregate(AggregateKind
::Tuple
, fields
))
135 ExprKind
::Closure { closure_id, substs, upvars }
=> { // see (*) above
138 .map(|upvar
| unpack
!(block
= this
.as_operand(block
, upvar
)))
140 block
.and(Rvalue
::Aggregate(AggregateKind
::Closure(closure_id
, substs
), upvars
))
143 adt_def
, variant_index
, substs
, fields
, base
144 } => { // see (*) above
145 // first process the set of fields that were provided
146 // (evaluating them in order given by user)
147 let fields_map
: FnvHashMap
<_
, _
> =
149 .map(|f
| (f
.name
, unpack
!(block
= this
.as_operand(block
, f
.expr
))))
152 let field_names
= this
.hir
.all_fields(adt_def
, variant_index
);
154 let fields
= if let Some(FruInfo { base, field_types }
) = base
{
155 let base
= unpack
!(block
= this
.as_lvalue(block
, base
));
157 // MIR does not natively support FRU, so for each
158 // base-supplied field, generate an operand that
159 // reads it from the base.
160 field_names
.into_iter()
161 .zip(field_types
.into_iter())
162 .map(|(n
, ty
)| match fields_map
.get(&n
) {
163 Some(v
) => v
.clone(),
164 None
=> Operand
::Consume(base
.clone().field(n
, ty
))
168 field_names
.iter().map(|n
| fields_map
[n
].clone()).collect()
171 block
.and(Rvalue
::Aggregate(AggregateKind
::Adt(adt_def
, variant_index
, substs
),
174 ExprKind
::Literal { .. }
|
175 ExprKind
::Block { .. }
|
176 ExprKind
::Match { .. }
|
177 ExprKind
::If { .. }
|
178 ExprKind
::Loop { .. }
|
179 ExprKind
::LogicalOp { .. }
|
180 ExprKind
::Call { .. }
|
181 ExprKind
::Field { .. }
|
182 ExprKind
::Deref { .. }
|
183 ExprKind
::Index { .. }
|
184 ExprKind
::VarRef { .. }
|
186 ExprKind
::Assign { .. }
|
187 ExprKind
::AssignOp { .. }
|
188 ExprKind
::Break { .. }
|
189 ExprKind
::Continue { .. }
|
190 ExprKind
::Return { .. }
|
191 ExprKind
::StaticRef { .. }
=> {
192 // these do not have corresponding `Rvalue` variants,
193 // so make an operand and then return that
194 debug_assert
!(match Category
::of(&expr
.kind
) {
195 Some(Category
::Rvalue(RvalueFunc
::AsRvalue
)) => false,
198 let operand
= unpack
!(block
= this
.as_operand(block
, expr
));
199 block
.and(Rvalue
::Use(operand
))