@@ -10,9 +10,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10
10
/// Returns an operand suitable for use until the end of the current
11
11
/// scope expression.
12
12
///
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.
16
17
crate fn as_local_operand < M > ( & mut self , block : BasicBlock , expr : M ) -> BlockAnd < Operand < ' tcx > >
17
18
where
18
19
M : Mirror < ' tcx , Output = Expr < ' tcx > > ,
@@ -21,6 +22,66 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
21
22
self . as_operand ( block, local_scope, expr)
22
23
}
23
24
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
+
24
85
/// Compile `expr` into a value that can be used as an operand.
25
86
/// If `expr` is a place like `x`, this will introduce a
26
87
/// temporary `tmp = x`, so that we capture the value of `x` at
@@ -40,6 +101,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
40
101
self . expr_as_operand ( block, scope, expr)
41
102
}
42
103
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
+
43
119
fn expr_as_operand (
44
120
& mut self ,
45
121
mut block : BasicBlock ,
@@ -69,4 +145,54 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
69
145
}
70
146
}
71
147
}
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
+ }
72
198
}
0 commit comments