@@ -58,7 +58,14 @@ impl<'a,'tcx> Builder<'a,'tcx> {
58
58
} ) ;
59
59
60
60
unpack ! ( then_block = this. into( destination, then_block, then_expr) ) ;
61
- unpack ! ( else_block = this. into( destination, else_block, else_expr) ) ;
61
+ else_block = if let Some ( else_expr) = else_expr {
62
+ unpack ! ( this. into( destination, else_block, else_expr) )
63
+ } else {
64
+ // Body of the `if` expression without an `else` clause must return `()`, thus
65
+ // we implicitly generate a `else {}` if it is not specified.
66
+ this. cfg . push_assign_unit ( else_block, expr_span, & Lvalue :: ReturnPointer ) ;
67
+ else_block
68
+ } ;
62
69
63
70
let join_block = this. cfg . start_new_block ( ) ;
64
71
this. cfg . terminate ( then_block, Terminator :: Goto { target : join_block } ) ;
@@ -157,11 +164,18 @@ impl<'a,'tcx> Builder<'a,'tcx> {
157
164
}
158
165
159
166
// execute the body, branching back to the test
160
- let unit_temp = this. unit_temp . clone ( ) ;
161
- let body_block_end = unpack ! ( this. into( & unit_temp, body_block, body) ) ;
167
+ // We write body’s “return value” into the destination of loop. This is fine,
168
+ // because:
169
+ //
170
+ // * In Rust both loop expression and its body are required to have `()`
171
+ // as the “return value”;
172
+ // * The destination will be considered uninitialised (given it was
173
+ // uninitialised before the loop) during the first iteration, thus
174
+ // disallowing its use inside the body. Alternatively, if it was already
175
+ // initialised, the `destination` can only possibly have a value of `()`,
176
+ // therefore, “mutating” the destination during iteration is fine.
177
+ let body_block_end = unpack ! ( this. into( destination, body_block, body) ) ;
162
178
this. cfg . terminate ( body_block_end, Terminator :: Goto { target : loop_block } ) ;
163
-
164
- // final point is exit_block
165
179
exit_block. unit ( )
166
180
} )
167
181
}
@@ -206,7 +220,13 @@ impl<'a,'tcx> Builder<'a,'tcx> {
206
220
this. break_or_continue ( expr_span, label, block, |loop_scope| loop_scope. break_block )
207
221
}
208
222
ExprKind :: Return { value } => {
209
- unpack ! ( block = this. into( & Lvalue :: ReturnPointer , block, value) ) ;
223
+ block = match value {
224
+ Some ( value) => unpack ! ( this. into( & Lvalue :: ReturnPointer , block, value) ) ,
225
+ None => {
226
+ this. cfg . push_assign_unit ( block, expr_span, & Lvalue :: ReturnPointer ) ;
227
+ block
228
+ }
229
+ } ;
210
230
let extent = this. extent_of_outermost_scope ( ) ;
211
231
this. exit_scope ( expr_span, extent, block, END_BLOCK ) ;
212
232
this. cfg . start_new_block ( ) . unit ( )
0 commit comments