]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir_build/src/build/expr/as_operand.rs
Update upstream source from tag 'upstream/1.70.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();
353b0b11 23 self.as_operand(block, Some(local_scope), expr, LocalInfo::Boring, 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
9c376795 30 /// passed, so please do *not* return it from functions to avoid bad miscompiles. Returns an
ba9703b0
XL
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 ///
9c376795 75 /// See #68304 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>,
353b0b11 105 local_info: 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));
353b0b11
FG
127 // Overwrite temp local info if we have something more interesting to record.
128 if !matches!(local_info, LocalInfo::Boring) {
129 let decl_info = this.local_decls[operand].local_info.as_mut().assert_crate_local();
130 if let LocalInfo::Boring | LocalInfo::BlockTailTemp(_) = **decl_info {
131 **decl_info = local_info;
132 }
c295e0f8 133 }
dc9dc135 134 block.and(Operand::Move(Place::from(operand)))
e9174d1e
SL
135 }
136 }
137 }
ba9703b0 138
923072b8 139 pub(crate) fn as_call_operand(
ba9703b0
XL
140 &mut self,
141 mut block: BasicBlock,
142 scope: Option<region::Scope>,
17df50a5 143 expr: &Expr<'tcx>,
ba9703b0 144 ) -> BlockAnd<Operand<'tcx>> {
6a06907d 145 debug!("as_call_operand(block={:?}, expr={:?})", block, expr);
ba9703b0
XL
146 let this = self;
147
148 if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
149 let source_info = this.source_info(expr.span);
150 let region_scope = (region_scope, source_info);
151 return this.in_scope(region_scope, lint_level, |this| {
17df50a5 152 this.as_call_operand(block, scope, &this.thir[value])
ba9703b0
XL
153 });
154 }
155
6a06907d 156 let tcx = this.tcx;
ba9703b0 157
29967ef6 158 if tcx.features().unsized_fn_params {
ba9703b0 159 let ty = expr.ty;
6a06907d 160 let param_env = this.param_env;
ba9703b0 161
2b03887a 162 if !ty.is_sized(tcx, param_env) {
ba9703b0 163 // !sized means !copy, so this is an unsized move
2b03887a 164 assert!(!ty.is_copy_modulo_regions(tcx, param_env));
ba9703b0
XL
165
166 // As described above, detect the case where we are passing a value of unsized
167 // type, and that value is coming from the deref of a box.
6a06907d 168 if let ExprKind::Deref { arg } = expr.kind {
ba9703b0 169 // Generate let tmp0 = arg0
17df50a5
XL
170 let operand = unpack!(
171 block = this.as_temp(block, scope, &this.thir[arg], Mutability::Mut)
172 );
ba9703b0
XL
173
174 // Return the operand *tmp0 to be used as the call argument
175 let place = Place {
176 local: operand,
9ffffee4 177 projection: tcx.mk_place_elems(&[PlaceElem::Deref]),
ba9703b0
XL
178 };
179
180 return block.and(Operand::Move(place));
181 }
182 }
183 }
184
353b0b11 185 this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::Maybe)
ba9703b0 186 }
e9174d1e 187}