@@ -58,7 +58,14 @@ impl<'a,'tcx> Builder<'a,'tcx> {
5858 } ) ;
5959
6060 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+ } ;
6269
6370 let join_block = this. cfg . start_new_block ( ) ;
6471 this. cfg . terminate ( then_block, Terminator :: Goto { target : join_block } ) ;
@@ -157,11 +164,18 @@ impl<'a,'tcx> Builder<'a,'tcx> {
157164 }
158165
159166 // 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) ) ;
162178 this. cfg . terminate ( body_block_end, Terminator :: Goto { target : loop_block } ) ;
163-
164- // final point is exit_block
165179 exit_block. unit ( )
166180 } )
167181 }
@@ -206,7 +220,13 @@ impl<'a,'tcx> Builder<'a,'tcx> {
206220 this. break_or_continue ( expr_span, label, block, |loop_scope| loop_scope. break_block )
207221 }
208222 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+ } ;
210230 let extent = this. extent_of_outermost_scope ( ) ;
211231 this. exit_scope ( expr_span, extent, block, END_BLOCK ) ;
212232 this. cfg . start_new_block ( ) . unit ( )
0 commit comments