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