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
15 use rustc_const_math
::{ConstMathErr, Op}
;
16 use rustc_data_structures
::fnv
::FnvHashMap
;
17 use rustc_data_structures
::indexed_vec
::Idx
;
19 use build
::{BlockAnd, BlockAndExtension, Builder}
;
20 use build
::expr
::category
::{Category, RvalueFunc}
;
22 use rustc_const_math
::{ConstInt, ConstIsize}
;
23 use rustc
::middle
::const_val
::ConstVal
;
25 use rustc
::mir
::repr
::*;
29 impl<'a
, 'gcx
, 'tcx
> Builder
<'a
, 'gcx
, 'tcx
> {
30 /// Compile `expr`, yielding an rvalue.
31 pub fn as_rvalue
<M
>(&mut self, block
: BasicBlock
, expr
: M
) -> BlockAnd
<Rvalue
<'tcx
>>
32 where M
: Mirror
<'tcx
, Output
= Expr
<'tcx
>>
34 let expr
= self.hir
.mirror(expr
);
35 self.expr_as_rvalue(block
, expr
)
38 fn expr_as_rvalue(&mut self,
39 mut block
: BasicBlock
,
41 -> BlockAnd
<Rvalue
<'tcx
>> {
42 debug
!("expr_as_rvalue(block={:?}, expr={:?})", block
, expr
);
45 let expr_span
= expr
.span
;
46 let source_info
= this
.source_info(expr_span
);
49 ExprKind
::Scope { extent, value }
=> {
50 this
.in_scope(extent
, block
, |this
| this
.as_rvalue(block
, value
))
52 ExprKind
::InlineAsm { asm, outputs, inputs }
=> {
53 let outputs
= outputs
.into_iter().map(|output
| {
54 unpack
!(block
= this
.as_lvalue(block
, output
))
57 let inputs
= inputs
.into_iter().map(|input
| {
58 unpack
!(block
= this
.as_operand(block
, input
))
61 block
.and(Rvalue
::InlineAsm
{
67 ExprKind
::Repeat { value, count }
=> {
68 let value_operand
= unpack
!(block
= this
.as_operand(block
, value
));
69 block
.and(Rvalue
::Repeat(value_operand
, count
))
71 ExprKind
::Borrow { region, borrow_kind, arg }
=> {
72 let arg_lvalue
= unpack
!(block
= this
.as_lvalue(block
, arg
));
73 block
.and(Rvalue
::Ref(region
, borrow_kind
, arg_lvalue
))
75 ExprKind
::Binary { op, lhs, rhs }
=> {
76 let lhs
= unpack
!(block
= this
.as_operand(block
, lhs
));
77 let rhs
= unpack
!(block
= this
.as_operand(block
, rhs
));
78 this
.build_binary_op(block
, op
, expr_span
, expr
.ty
,
81 ExprKind
::Unary { op, arg }
=> {
82 let arg
= unpack
!(block
= this
.as_operand(block
, arg
));
83 // Check for -MIN on signed integers
84 if this
.hir
.check_overflow() && op
== UnOp
::Neg
&& expr
.ty
.is_signed() {
85 let bool_ty
= this
.hir
.bool_ty();
87 let minval
= this
.minval_literal(expr_span
, expr
.ty
);
88 let is_min
= this
.temp(bool_ty
);
90 this
.cfg
.push_assign(block
, source_info
, &is_min
,
91 Rvalue
::BinaryOp(BinOp
::Eq
, arg
.clone(), minval
));
93 let err
= ConstMathErr
::Overflow(Op
::Neg
);
94 block
= this
.assert(block
, Operand
::Consume(is_min
), false,
95 AssertMessage
::Math(err
), expr_span
);
97 block
.and(Rvalue
::UnaryOp(op
, arg
))
99 ExprKind
::Box { value, value_extents }
=> {
100 let value
= this
.hir
.mirror(value
);
101 let result
= this
.temp(expr
.ty
);
102 // to start, malloc some memory of suitable type (thus far, uninitialized):
103 this
.cfg
.push_assign(block
, source_info
, &result
, Rvalue
::Box(value
.ty
));
104 this
.in_scope(value_extents
, block
, |this
| {
105 // schedule a shallow free of that memory, lest we unwind:
106 this
.schedule_box_free(expr_span
, value_extents
, &result
, value
.ty
);
107 // initialize the box contents:
108 unpack
!(block
= this
.into(&result
.clone().deref(), block
, value
));
109 block
.and(Rvalue
::Use(Operand
::Consume(result
)))
112 ExprKind
::Cast { source }
=> {
113 let source
= this
.hir
.mirror(source
);
115 let source
= unpack
!(block
= this
.as_operand(block
, source
));
116 block
.and(Rvalue
::Cast(CastKind
::Misc
, source
, expr
.ty
))
118 ExprKind
::ReifyFnPointer { source }
=> {
119 let source
= unpack
!(block
= this
.as_operand(block
, source
));
120 block
.and(Rvalue
::Cast(CastKind
::ReifyFnPointer
, source
, expr
.ty
))
122 ExprKind
::UnsafeFnPointer { source }
=> {
123 let source
= unpack
!(block
= this
.as_operand(block
, source
));
124 block
.and(Rvalue
::Cast(CastKind
::UnsafeFnPointer
, source
, expr
.ty
))
126 ExprKind
::Unsize { source }
=> {
127 let source
= unpack
!(block
= this
.as_operand(block
, source
));
128 block
.and(Rvalue
::Cast(CastKind
::Unsize
, source
, expr
.ty
))
130 ExprKind
::Vec { fields }
=> {
131 // (*) We would (maybe) be closer to trans if we
132 // handled this and other aggregate cases via
133 // `into()`, not `as_rvalue` -- in that case, instead
138 // dest = Rvalue::Aggregate(Foo, [tmp1, tmp2])
140 // we could just generate
145 // The problem is that then we would need to:
147 // (a) have a more complex mechanism for handling
149 // (b) distinguish the case where the type `Foo` has a
150 // destructor, in which case creating an instance
151 // as a whole "arms" the destructor, and you can't
152 // write individual fields; and,
153 // (c) handle the case where the type Foo has no
154 // fields. We don't want `let x: ();` to compile
155 // to the same MIR as `let x = ();`.
157 // first process the set of fields
160 .map(|f
| unpack
!(block
= this
.as_operand(block
, f
)))
163 block
.and(Rvalue
::Aggregate(AggregateKind
::Vec
, fields
))
165 ExprKind
::Tuple { fields }
=> { // see (*) above
166 // first process the set of fields
169 .map(|f
| unpack
!(block
= this
.as_operand(block
, f
)))
172 block
.and(Rvalue
::Aggregate(AggregateKind
::Tuple
, fields
))
174 ExprKind
::Closure { closure_id, substs, upvars }
=> { // see (*) above
177 .map(|upvar
| unpack
!(block
= this
.as_operand(block
, upvar
)))
179 block
.and(Rvalue
::Aggregate(AggregateKind
::Closure(closure_id
, substs
), upvars
))
182 adt_def
, variant_index
, substs
, fields
, base
183 } => { // see (*) above
184 // first process the set of fields that were provided
185 // (evaluating them in order given by user)
186 let fields_map
: FnvHashMap
<_
, _
> =
188 .map(|f
| (f
.name
, unpack
!(block
= this
.as_operand(block
, f
.expr
))))
191 let field_names
= this
.hir
.all_fields(adt_def
, variant_index
);
193 let fields
= if let Some(FruInfo { base, field_types }
) = base
{
194 let base
= unpack
!(block
= this
.as_lvalue(block
, base
));
196 // MIR does not natively support FRU, so for each
197 // base-supplied field, generate an operand that
198 // reads it from the base.
199 field_names
.into_iter()
200 .zip(field_types
.into_iter())
201 .map(|(n
, ty
)| match fields_map
.get(&n
) {
202 Some(v
) => v
.clone(),
203 None
=> Operand
::Consume(base
.clone().field(n
, ty
))
207 field_names
.iter().map(|n
| fields_map
[n
].clone()).collect()
210 block
.and(Rvalue
::Aggregate(AggregateKind
::Adt(adt_def
, variant_index
, substs
),
213 ExprKind
::Assign { .. }
|
214 ExprKind
::AssignOp { .. }
=> {
215 block
= unpack
!(this
.stmt_expr(block
, expr
));
216 block
.and(this
.unit_rvalue())
218 ExprKind
::Literal { .. }
|
219 ExprKind
::Block { .. }
|
220 ExprKind
::Match { .. }
|
221 ExprKind
::If { .. }
|
222 ExprKind
::Loop { .. }
|
223 ExprKind
::LogicalOp { .. }
|
224 ExprKind
::Call { .. }
|
225 ExprKind
::Field { .. }
|
226 ExprKind
::Deref { .. }
|
227 ExprKind
::Index { .. }
|
228 ExprKind
::VarRef { .. }
|
230 ExprKind
::Break { .. }
|
231 ExprKind
::Continue { .. }
|
232 ExprKind
::Return { .. }
|
233 ExprKind
::StaticRef { .. }
=> {
234 // these do not have corresponding `Rvalue` variants,
235 // so make an operand and then return that
236 debug_assert
!(match Category
::of(&expr
.kind
) {
237 Some(Category
::Rvalue(RvalueFunc
::AsRvalue
)) => false,
240 let operand
= unpack
!(block
= this
.as_operand(block
, expr
));
241 block
.and(Rvalue
::Use(operand
))
246 pub fn build_binary_op(&mut self, mut block
: BasicBlock
,
247 op
: BinOp
, span
: Span
, ty
: ty
::Ty
<'tcx
>,
248 lhs
: Operand
<'tcx
>, rhs
: Operand
<'tcx
>) -> BlockAnd
<Rvalue
<'tcx
>> {
249 let source_info
= self.source_info(span
);
250 let bool_ty
= self.hir
.bool_ty();
251 if self.hir
.check_overflow() && op
.is_checkable() && ty
.is_integral() {
252 let result_tup
= self.hir
.tcx().mk_tup(vec
![ty
, bool_ty
]);
253 let result_value
= self.temp(result_tup
);
255 self.cfg
.push_assign(block
, source_info
,
256 &result_value
, Rvalue
::CheckedBinaryOp(op
,
259 let val_fld
= Field
::new(0);
260 let of_fld
= Field
::new(1);
262 let val
= result_value
.clone().field(val_fld
, ty
);
263 let of
= result_value
.field(of_fld
, bool_ty
);
265 let err
= ConstMathErr
::Overflow(match op
{
266 BinOp
::Add
=> Op
::Add
,
267 BinOp
::Sub
=> Op
::Sub
,
268 BinOp
::Mul
=> Op
::Mul
,
269 BinOp
::Shl
=> Op
::Shl
,
270 BinOp
::Shr
=> Op
::Shr
,
272 bug
!("MIR build_binary_op: {:?} is not checkable", op
)
276 block
= self.assert(block
, Operand
::Consume(of
), false,
277 AssertMessage
::Math(err
), span
);
279 block
.and(Rvalue
::Use(Operand
::Consume(val
)))
281 if ty
.is_integral() && (op
== BinOp
::Div
|| op
== BinOp
::Rem
) {
282 // Checking division and remainder is more complex, since we 1. always check
283 // and 2. there are two possible failure cases, divide-by-zero and overflow.
285 let (zero_err
, overflow_err
) = if op
== BinOp
::Div
{
286 (ConstMathErr
::DivisionByZero
,
287 ConstMathErr
::Overflow(Op
::Div
))
289 (ConstMathErr
::RemainderByZero
,
290 ConstMathErr
::Overflow(Op
::Rem
))
294 let is_zero
= self.temp(bool_ty
);
295 let zero
= self.zero_literal(span
, ty
);
296 self.cfg
.push_assign(block
, source_info
, &is_zero
,
297 Rvalue
::BinaryOp(BinOp
::Eq
, rhs
.clone(), zero
));
299 block
= self.assert(block
, Operand
::Consume(is_zero
), false,
300 AssertMessage
::Math(zero_err
), span
);
302 // We only need to check for the overflow in one case:
303 // MIN / -1, and only for signed values.
305 let neg_1
= self.neg_1_literal(span
, ty
);
306 let min
= self.minval_literal(span
, ty
);
308 let is_neg_1
= self.temp(bool_ty
);
309 let is_min
= self.temp(bool_ty
);
310 let of
= self.temp(bool_ty
);
312 // this does (rhs == -1) & (lhs == MIN). It could short-circuit instead
314 self.cfg
.push_assign(block
, source_info
, &is_neg_1
,
315 Rvalue
::BinaryOp(BinOp
::Eq
, rhs
.clone(), neg_1
));
316 self.cfg
.push_assign(block
, source_info
, &is_min
,
317 Rvalue
::BinaryOp(BinOp
::Eq
, lhs
.clone(), min
));
319 let is_neg_1
= Operand
::Consume(is_neg_1
);
320 let is_min
= Operand
::Consume(is_min
);
321 self.cfg
.push_assign(block
, source_info
, &of
,
322 Rvalue
::BinaryOp(BinOp
::BitAnd
, is_neg_1
, is_min
));
324 block
= self.assert(block
, Operand
::Consume(of
), false,
325 AssertMessage
::Math(overflow_err
), span
);
329 block
.and(Rvalue
::BinaryOp(op
, lhs
, rhs
))
333 // Helper to get a `-1` value of the appropriate type
334 fn neg_1_literal(&mut self, span
: Span
, ty
: ty
::Ty
<'tcx
>) -> Operand
<'tcx
> {
335 let literal
= match ty
.sty
{
337 let val
= match ity
{
338 ast
::IntTy
::I8
=> ConstInt
::I8(-1),
339 ast
::IntTy
::I16
=> ConstInt
::I16(-1),
340 ast
::IntTy
::I32
=> ConstInt
::I32(-1),
341 ast
::IntTy
::I64
=> ConstInt
::I64(-1),
343 let int_ty
= self.hir
.tcx().sess
.target
.int_type
;
344 let val
= ConstIsize
::new(-1, int_ty
).unwrap();
349 Literal
::Value { value: ConstVal::Integral(val) }
352 span_bug
!(span
, "Invalid type for neg_1_literal: `{:?}`", ty
)
356 self.literal_operand(span
, ty
, literal
)
359 // Helper to get the minimum value of the appropriate type
360 fn minval_literal(&mut self, span
: Span
, ty
: ty
::Ty
<'tcx
>) -> Operand
<'tcx
> {
361 let literal
= match ty
.sty
{
363 let val
= match ity
{
364 ast
::IntTy
::I8
=> ConstInt
::I8(std
::i8::MIN
),
365 ast
::IntTy
::I16
=> ConstInt
::I16(std
::i16::MIN
),
366 ast
::IntTy
::I32
=> ConstInt
::I32(std
::i32::MIN
),
367 ast
::IntTy
::I64
=> ConstInt
::I64(std
::i64::MIN
),
369 let int_ty
= self.hir
.tcx().sess
.target
.int_type
;
370 let min
= match int_ty
{
371 ast
::IntTy
::I16
=> std
::i16::MIN
as i64,
372 ast
::IntTy
::I32
=> std
::i32::MIN
as i64,
373 ast
::IntTy
::I64
=> std
::i64::MIN
,
376 let val
= ConstIsize
::new(min
, int_ty
).unwrap();
381 Literal
::Value { value: ConstVal::Integral(val) }
384 span_bug
!(span
, "Invalid type for minval_literal: `{:?}`", ty
)
388 self.literal_operand(span
, ty
, literal
)