1 //! See docs in build/expr/mod.rs
3 use crate::build
::expr
::category
::Category
;
4 use crate::build
::{BlockAnd, BlockAndExtension, Builder}
;
6 use rustc_middle
::middle
::region
;
7 use rustc_middle
::mir
::*;
9 impl<'a
, 'tcx
> Builder
<'a
, 'tcx
> {
10 /// Returns an operand suitable for use until the end of the current
13 /// The operand returned from this function will *not be valid*
14 /// after the current enclosing `ExprKind::Scope` has ended, so
15 /// please do *not* return it from functions to avoid bad
17 crate fn as_local_operand
<M
>(&mut self, block
: BasicBlock
, expr
: M
) -> BlockAnd
<Operand
<'tcx
>>
19 M
: Mirror
<'tcx
, Output
= Expr
<'tcx
>>,
21 let local_scope
= self.local_scope();
22 self.as_operand(block
, local_scope
, expr
)
25 /// Returns an operand suitable for use until the end of the current scope expression and
26 /// suitable also to be passed as function arguments.
28 /// The operand returned from this function will *not be valid* after an ExprKind::Scope is
29 /// passed, so please do *not* return it from functions to avoid bad miscompiles. Returns an
30 /// operand suitable for use as a call argument. This is almost always equivalent to
31 /// `as_operand`, except for the particular case of passing values of (potentially) unsized
32 /// types "by value" (see details below).
34 /// The operand returned from this function will *not be valid*
35 /// after the current enclosing `ExprKind::Scope` has ended, so
36 /// please do *not* return it from functions to avoid bad
39 /// # Parameters of unsized types
41 /// We tweak the handling of parameters of unsized type slightly to avoid the need to create a
42 /// local variable of unsized type. For example, consider this program:
45 /// fn foo(p: dyn Debug) { ... }
47 /// fn bar(box_p: Box<dyn Debug>) { foo(*p); }
50 /// Ordinarily, for sized types, we would compile the call `foo(*p)` like so:
53 /// let tmp0 = *box_p; // tmp0 would be the operand returned by this function call
57 /// But because the parameter to `foo` is of the unsized type `dyn Debug`, and because it is
58 /// being moved the deref of a box, we compile it slightly differently. The temporary `tmp0`
59 /// that we create *stores the entire box*, and the parameter to the call itself will be
63 /// let tmp0 = box_p; call foo(*tmp0)
66 /// This way, the temporary `tmp0` that we create has type `Box<dyn Debug>`, which is sized.
67 /// The value passed to the call (`*tmp0`) still has the `dyn Debug` type -- but the way that
68 /// calls are compiled means that this parameter will be passed "by reference", meaning that we
69 /// will actually provide a pointer to the interior of the box, and not move the `dyn Debug`
70 /// value to the stack.
72 /// See #68034 for more details.
73 crate fn as_local_call_operand
<M
>(
77 ) -> BlockAnd
<Operand
<'tcx
>>
79 M
: Mirror
<'tcx
, Output
= Expr
<'tcx
>>,
81 let local_scope
= self.local_scope();
82 self.as_call_operand(block
, local_scope
, expr
)
85 /// Compile `expr` into a value that can be used as an operand.
86 /// If `expr` is a place like `x`, this will introduce a
87 /// temporary `tmp = x`, so that we capture the value of `x` at
90 /// The operand is known to be live until the end of `scope`.
91 crate fn as_operand
<M
>(
94 scope
: Option
<region
::Scope
>,
96 ) -> BlockAnd
<Operand
<'tcx
>>
98 M
: Mirror
<'tcx
, Output
= Expr
<'tcx
>>,
100 let expr
= self.hir
.mirror(expr
);
101 self.expr_as_operand(block
, scope
, expr
)
104 /// Like `as_local_call_operand`, except that the argument will
105 /// not be valid once `scope` ends.
106 fn as_call_operand
<M
>(
109 scope
: Option
<region
::Scope
>,
111 ) -> BlockAnd
<Operand
<'tcx
>>
113 M
: Mirror
<'tcx
, Output
= Expr
<'tcx
>>,
115 let expr
= self.hir
.mirror(expr
);
116 self.expr_as_call_operand(block
, scope
, expr
)
121 mut block
: BasicBlock
,
122 scope
: Option
<region
::Scope
>,
124 ) -> BlockAnd
<Operand
<'tcx
>> {
125 debug
!("expr_as_operand(block={:?}, expr={:?})", block
, expr
);
128 if let ExprKind
::Scope { region_scope, lint_level, value }
= expr
.kind
{
129 let source_info
= this
.source_info(expr
.span
);
130 let region_scope
= (region_scope
, source_info
);
132 .in_scope(region_scope
, lint_level
, |this
| this
.as_operand(block
, scope
, value
));
135 let category
= Category
::of(&expr
.kind
).unwrap();
136 debug
!("expr_as_operand: category={:?} for={:?}", category
, expr
.kind
);
138 Category
::Constant
=> {
139 let constant
= this
.as_constant(expr
);
140 block
.and(Operand
::Constant(box constant
))
142 Category
::Place
| Category
::Rvalue(..) => {
143 let operand
= unpack
!(block
= this
.as_temp(block
, scope
, expr
, Mutability
::Mut
));
144 block
.and(Operand
::Move(Place
::from(operand
)))
149 fn expr_as_call_operand(
151 mut block
: BasicBlock
,
152 scope
: Option
<region
::Scope
>,
154 ) -> BlockAnd
<Operand
<'tcx
>> {
155 debug
!("expr_as_call_operand(block={:?}, expr={:?})", block
, expr
);
158 if let ExprKind
::Scope { region_scope, lint_level, value }
= expr
.kind
{
159 let source_info
= this
.source_info(expr
.span
);
160 let region_scope
= (region_scope
, source_info
);
161 return this
.in_scope(region_scope
, lint_level
, |this
| {
162 this
.as_call_operand(block
, scope
, value
)
166 let tcx
= this
.hir
.tcx();
168 if tcx
.features().unsized_locals
{
170 let span
= expr
.span
;
171 let param_env
= this
.hir
.param_env
;
173 if !ty
.is_sized(tcx
.at(span
), param_env
) {
174 // !sized means !copy, so this is an unsized move
175 assert
!(!ty
.is_copy_modulo_regions(tcx
.at(span
), param_env
));
177 // As described above, detect the case where we are passing a value of unsized
178 // type, and that value is coming from the deref of a box.
179 if let ExprKind
::Deref { ref arg }
= expr
.kind
{
180 let arg
= this
.hir
.mirror(arg
.clone());
182 // Generate let tmp0 = arg0
183 let operand
= unpack
!(block
= this
.as_temp(block
, scope
, arg
, Mutability
::Mut
));
185 // Return the operand *tmp0 to be used as the call argument
188 projection
: tcx
.intern_place_elems(&[PlaceElem
::Deref
]),
191 return block
.and(Operand
::Move(place
));
196 this
.expr_as_operand(block
, scope
, expr
)