@@ -10,9 +10,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1010 /// Returns an operand suitable for use until the end of the current
1111 /// scope expression.
1212 ///
13- /// The operand returned from this function will *not be valid* after
14- /// an ExprKind::Scope is passed, so please do *not* return it from
15- /// functions to avoid bad miscompiles.
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.
1617 crate fn as_local_operand < M > ( & mut self , block : BasicBlock , expr : M ) -> BlockAnd < Operand < ' tcx > >
1718 where
1819 M : Mirror < ' tcx , Output = Expr < ' tcx > > ,
@@ -21,6 +22,66 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2122 self . as_operand ( block, local_scope, expr)
2223 }
2324
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.
27+ ///
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).
33+ ///
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
37+ /// miscompiles.
38+ ///
39+ /// # Parameters of unsized types
40+ ///
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:
43+ ///
44+ /// ```rust
45+ /// fn foo(p: dyn Debug) { ... }
46+ ///
47+ /// fn bar(box_p: Box<dyn Debug>) { foo(*p); }
48+ /// ```
49+ ///
50+ /// Ordinarily, for sized types, we would compile the call `foo(*p)` like so:
51+ ///
52+ /// ```rust
53+ /// let tmp0 = *box_p; // tmp0 would be the operand returned by this function call
54+ /// foo(tmp0)
55+ /// ```
56+ ///
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
60+ /// `*tmp0`:
61+ ///
62+ /// ```rust
63+ /// let tmp0 = box_p; call foo(*tmp0)
64+ /// ```
65+ ///
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.
71+ ///
72+ /// See #68034 for more details.
73+ crate fn as_local_call_operand < M > (
74+ & mut self ,
75+ block : BasicBlock ,
76+ expr : M ,
77+ ) -> BlockAnd < Operand < ' tcx > >
78+ where
79+ M : Mirror < ' tcx , Output = Expr < ' tcx > > ,
80+ {
81+ let local_scope = self . local_scope ( ) ;
82+ self . as_call_operand ( block, local_scope, expr)
83+ }
84+
2485 /// Compile `expr` into a value that can be used as an operand.
2586 /// If `expr` is a place like `x`, this will introduce a
2687 /// temporary `tmp = x`, so that we capture the value of `x` at
@@ -40,6 +101,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
40101 self . expr_as_operand ( block, scope, expr)
41102 }
42103
104+ /// Like `as_local_call_operand`, except that the argument will
105+ /// not be valid once `scope` ends.
106+ fn as_call_operand < M > (
107+ & mut self ,
108+ block : BasicBlock ,
109+ scope : Option < region:: Scope > ,
110+ expr : M ,
111+ ) -> BlockAnd < Operand < ' tcx > >
112+ where
113+ M : Mirror < ' tcx , Output = Expr < ' tcx > > ,
114+ {
115+ let expr = self . hir . mirror ( expr) ;
116+ self . expr_as_call_operand ( block, scope, expr)
117+ }
118+
43119 fn expr_as_operand (
44120 & mut self ,
45121 mut block : BasicBlock ,
@@ -69,4 +145,54 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
69145 }
70146 }
71147 }
148+
149+ fn expr_as_call_operand (
150+ & mut self ,
151+ mut block : BasicBlock ,
152+ scope : Option < region:: Scope > ,
153+ expr : Expr < ' tcx > ,
154+ ) -> BlockAnd < Operand < ' tcx > > {
155+ debug ! ( "expr_as_call_operand(block={:?}, expr={:?})" , block, expr) ;
156+ let this = self ;
157+
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)
163+ } ) ;
164+ }
165+
166+ let tcx = this. hir . tcx ( ) ;
167+
168+ if tcx. features ( ) . unsized_locals {
169+ let ty = expr. ty ;
170+ let span = expr. span ;
171+ let param_env = this. hir . param_env ;
172+
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, param_env, span) ) ;
176+
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 ( ) ) ;
181+
182+ // Generate let tmp0 = arg0
183+ let operand = unpack ! ( block = this. as_temp( block, scope, arg, Mutability :: Mut ) ) ;
184+
185+ // Return the operand *tmp0 to be used as the call argument
186+ let place = Place {
187+ local : operand,
188+ projection : tcx. intern_place_elems ( & [ PlaceElem :: Deref ] ) ,
189+ } ;
190+
191+ return block. and ( Operand :: Move ( place) ) ;
192+ }
193+ }
194+ }
195+
196+ this. expr_as_operand ( block, scope, expr)
197+ }
72198}
0 commit comments