]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir_build/src/build/expr/as_operand.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / compiler / rustc_mir_build / src / build / expr / as_operand.rs
CommitLineData
e9174d1e
SL
1//! See docs in build/expr/mod.rs
2
9fa01778
XL
3use crate::build::expr::category::Category;
4use crate::build::{BlockAnd, BlockAndExtension, Builder};
ba9703b0
XL
5use rustc_middle::middle::region;
6use rustc_middle::mir::*;
17df50a5 7use rustc_middle::thir::*;
e9174d1e 8
dc9dc135 9impl<'a, 'tcx> Builder<'a, 'tcx> {
8bb4bdeb
XL
10 /// Returns an operand suitable for use until the end of the current
11 /// scope expression.
12 ///
ba9703b0
XL
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
16 /// miscompiles.
6a06907d
XL
17 crate fn as_local_operand(
18 &mut self,
19 block: BasicBlock,
17df50a5 20 expr: &Expr<'tcx>,
6a06907d 21 ) -> BlockAnd<Operand<'tcx>> {
7cac9316 22 let local_scope = self.local_scope();
c295e0f8 23 self.as_operand(block, Some(local_scope), expr, None)
8bb4bdeb
XL
24 }
25
ba9703b0
XL
26 /// Returns an operand suitable for use until the end of the current scope expression and
27 /// suitable also to be passed as function arguments.
28 ///
29 /// The operand returned from this function will *not be valid* after an ExprKind::Scope is
30 /// passed, so please do *not* return it from functions to avoid bad miscompiles. Returns an
31 /// operand suitable for use as a call argument. This is almost always equivalent to
32 /// `as_operand`, except for the particular case of passing values of (potentially) unsized
33 /// types "by value" (see details below).
34 ///
35 /// The operand returned from this function will *not be valid*
36 /// after the current enclosing `ExprKind::Scope` has ended, so
37 /// please do *not* return it from functions to avoid bad
38 /// miscompiles.
39 ///
40 /// # Parameters of unsized types
41 ///
42 /// We tweak the handling of parameters of unsized type slightly to avoid the need to create a
43 /// local variable of unsized type. For example, consider this program:
44 ///
45 /// ```rust
46 /// fn foo(p: dyn Debug) { ... }
47 ///
48 /// fn bar(box_p: Box<dyn Debug>) { foo(*p); }
49 /// ```
50 ///
51 /// Ordinarily, for sized types, we would compile the call `foo(*p)` like so:
52 ///
53 /// ```rust
54 /// let tmp0 = *box_p; // tmp0 would be the operand returned by this function call
55 /// foo(tmp0)
56 /// ```
57 ///
58 /// But because the parameter to `foo` is of the unsized type `dyn Debug`, and because it is
59 /// being moved the deref of a box, we compile it slightly differently. The temporary `tmp0`
60 /// that we create *stores the entire box*, and the parameter to the call itself will be
61 /// `*tmp0`:
62 ///
63 /// ```rust
64 /// let tmp0 = box_p; call foo(*tmp0)
65 /// ```
66 ///
67 /// This way, the temporary `tmp0` that we create has type `Box<dyn Debug>`, which is sized.
68 /// The value passed to the call (`*tmp0`) still has the `dyn Debug` type -- but the way that
69 /// calls are compiled means that this parameter will be passed "by reference", meaning that we
70 /// will actually provide a pointer to the interior of the box, and not move the `dyn Debug`
71 /// value to the stack.
72 ///
73 /// See #68034 for more details.
6a06907d 74 crate fn as_local_call_operand(
ba9703b0
XL
75 &mut self,
76 block: BasicBlock,
17df50a5 77 expr: &Expr<'tcx>,
6a06907d 78 ) -> BlockAnd<Operand<'tcx>> {
ba9703b0 79 let local_scope = self.local_scope();
fc512014 80 self.as_call_operand(block, Some(local_scope), expr)
ba9703b0
XL
81 }
82
e9174d1e 83 /// Compile `expr` into a value that can be used as an operand.
ff7c6d11 84 /// If `expr` is a place like `x`, this will introduce a
e9174d1e
SL
85 /// temporary `tmp = x`, so that we capture the value of `x` at
86 /// this time.
8bb4bdeb 87 ///
c295e0f8
XL
88 /// If we end up needing to create a temporary, then we will use
89 /// `local_info` as its `LocalInfo`, unless `as_temporary`
90 /// has already assigned it a non-`None` `LocalInfo`.
91 /// Normally, you should use `None` for `local_info`
92 ///
8bb4bdeb 93 /// The operand is known to be live until the end of `scope`.
6a06907d 94 ///
ba9703b0
XL
95 /// Like `as_local_call_operand`, except that the argument will
96 /// not be valid once `scope` ends.
6a06907d 97 crate fn as_operand(
b7449926
XL
98 &mut self,
99 mut block: BasicBlock,
100 scope: Option<region::Scope>,
17df50a5 101 expr: &Expr<'tcx>,
c295e0f8 102 local_info: Option<Box<LocalInfo<'tcx>>>,
b7449926 103 ) -> BlockAnd<Operand<'tcx>> {
c295e0f8 104 debug!("as_operand(block={:?}, expr={:?} local_info={:?})", block, expr, local_info);
e9174d1e
SL
105 let this = self;
106
dfeec247 107 if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
041b39d2 108 let source_info = this.source_info(expr.span);
ea8adc8c 109 let region_scope = (region_scope, source_info);
17df50a5 110 return this.in_scope(region_scope, lint_level, |this| {
c295e0f8 111 this.as_operand(block, scope, &this.thir[value], local_info)
17df50a5 112 });
e9174d1e
SL
113 }
114
115 let category = Category::of(&expr.kind).unwrap();
6a06907d 116 debug!("as_operand: category={:?} for={:?}", category, expr.kind);
e9174d1e
SL
117 match category {
118 Category::Constant => {
119 let constant = this.as_constant(expr);
94222f64 120 block.and(Operand::Constant(Box::new(constant)))
e9174d1e 121 }
b7449926
XL
122 Category::Place | Category::Rvalue(..) => {
123 let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
c295e0f8
XL
124 if this.local_decls[operand].local_info.is_none() {
125 this.local_decls[operand].local_info = local_info;
126 }
dc9dc135 127 block.and(Operand::Move(Place::from(operand)))
e9174d1e
SL
128 }
129 }
130 }
ba9703b0 131
6a06907d 132 crate fn as_call_operand(
ba9703b0
XL
133 &mut self,
134 mut block: BasicBlock,
135 scope: Option<region::Scope>,
17df50a5 136 expr: &Expr<'tcx>,
ba9703b0 137 ) -> BlockAnd<Operand<'tcx>> {
6a06907d 138 debug!("as_call_operand(block={:?}, expr={:?})", block, expr);
ba9703b0
XL
139 let this = self;
140
141 if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
142 let source_info = this.source_info(expr.span);
143 let region_scope = (region_scope, source_info);
144 return this.in_scope(region_scope, lint_level, |this| {
17df50a5 145 this.as_call_operand(block, scope, &this.thir[value])
ba9703b0
XL
146 });
147 }
148
6a06907d 149 let tcx = this.tcx;
ba9703b0 150
29967ef6 151 if tcx.features().unsized_fn_params {
ba9703b0
XL
152 let ty = expr.ty;
153 let span = expr.span;
6a06907d 154 let param_env = this.param_env;
ba9703b0
XL
155
156 if !ty.is_sized(tcx.at(span), param_env) {
157 // !sized means !copy, so this is an unsized move
f035d41b 158 assert!(!ty.is_copy_modulo_regions(tcx.at(span), param_env));
ba9703b0
XL
159
160 // As described above, detect the case where we are passing a value of unsized
161 // type, and that value is coming from the deref of a box.
6a06907d 162 if let ExprKind::Deref { arg } = expr.kind {
ba9703b0 163 // Generate let tmp0 = arg0
17df50a5
XL
164 let operand = unpack!(
165 block = this.as_temp(block, scope, &this.thir[arg], Mutability::Mut)
166 );
ba9703b0
XL
167
168 // Return the operand *tmp0 to be used as the call argument
169 let place = Place {
170 local: operand,
171 projection: tcx.intern_place_elems(&[PlaceElem::Deref]),
172 };
173
174 return block.and(Operand::Move(place));
175 }
176 }
177 }
178
c295e0f8 179 this.as_operand(block, scope, expr, None)
ba9703b0 180 }
e9174d1e 181}