@@ -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,12 +164,18 @@ impl<'a,'tcx> Builder<'a,'tcx> {
157164 }
158165
159166 // execute the body, branching back to the test
160- // FIXME(#30636): this should not create or request any sort of destination at
161- // all.
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.
162177 let body_block_end = unpack ! ( this. into( destination, body_block, body) ) ;
163178 this. cfg . terminate ( body_block_end, Terminator :: Goto { target : loop_block } ) ;
164-
165- // final point is exit_block
166179 exit_block. unit ( )
167180 } )
168181 }
@@ -207,7 +220,13 @@ impl<'a,'tcx> Builder<'a,'tcx> {
207220 this. break_or_continue ( expr_span, label, block, |loop_scope| loop_scope. break_block )
208221 }
209222 ExprKind :: Return { value } => {
210- 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+ } ;
211230 let extent = this. extent_of_outermost_scope ( ) ;
212231 this. exit_scope ( expr_span, extent, block, END_BLOCK ) ;
213232 this. cfg . start_new_block ( ) . unit ( )
0 commit comments