@@ -9,7 +9,7 @@ use rustc::hir::def_id::DefId;
99use rustc:: mir:: {
1010 AggregateKind , Constant , Location , Place , PlaceBase , Body , Operand , Rvalue , Local , UnOp ,
1111 StatementKind , Statement , LocalKind , TerminatorKind , Terminator , ClearCrossCrate , SourceInfo ,
12- BinOp , SourceScope , SourceScopeLocalData , LocalDecl , BasicBlock ,
12+ BinOp , SourceScope , SourceScopeLocalData , LocalDecl , BasicBlock , RETURN_PLACE ,
1313} ;
1414use rustc:: mir:: visit:: {
1515 Visitor , PlaceContext , MutatingUseContext , MutVisitor , NonMutatingUseContext ,
@@ -25,6 +25,7 @@ use rustc::ty::layout::{
2525 LayoutOf , TyLayout , LayoutError , HasTyCtxt , TargetDataLayout , HasDataLayout ,
2626} ;
2727
28+ use crate :: rustc:: ty:: subst:: Subst ;
2829use crate :: interpret:: {
2930 self , InterpCx , ScalarMaybeUndef , Immediate , OpTy ,
3031 StackPopCleanup , LocalValue , LocalState , AllocId , Frame ,
@@ -269,6 +270,7 @@ struct ConstPropagator<'mir, 'tcx> {
269270 param_env : ParamEnv < ' tcx > ,
270271 source_scope_local_data : ClearCrossCrate < IndexVec < SourceScope , SourceScopeLocalData > > ,
271272 local_decls : IndexVec < Local , LocalDecl < ' tcx > > ,
273+ ret : Option < OpTy < ' tcx , ( ) > > ,
272274}
273275
274276impl < ' mir , ' tcx > LayoutOf for ConstPropagator < ' mir , ' tcx > {
@@ -308,11 +310,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
308310 let mut ecx = InterpCx :: new ( tcx. at ( span) , param_env, ConstPropMachine , ( ) ) ;
309311 let can_const_prop = CanConstProp :: check ( body) ;
310312
313+ let substs = & InternalSubsts :: identity_for_item ( tcx, def_id) ;
314+
315+ let ret =
316+ ecx
317+ . layout_of ( body. return_ty ( ) . subst ( tcx, substs) )
318+ . ok ( )
319+ // Don't bother allocating memory for ZST types which have no values.
320+ . filter ( |ret_layout| !ret_layout. is_zst ( ) )
321+ . map ( |ret_layout| ecx. allocate ( ret_layout, MemoryKind :: Stack ) ) ;
322+
311323 ecx. push_stack_frame (
312- Instance :: new ( def_id, & InternalSubsts :: identity_for_item ( tcx , def_id ) ) ,
324+ Instance :: new ( def_id, substs ) ,
313325 span,
314326 dummy_body,
315- None ,
327+ ret . map ( Into :: into ) ,
316328 StackPopCleanup :: None {
317329 cleanup : false ,
318330 } ,
@@ -327,6 +339,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
327339 source_scope_local_data,
328340 //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
329341 local_decls : body. local_decls . clone ( ) ,
342+ ret : ret. map ( Into :: into) ,
330343 }
331344 }
332345
@@ -335,6 +348,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
335348 }
336349
337350 fn get_const ( & self , local : Local ) -> Option < Const < ' tcx > > {
351+ if local == RETURN_PLACE {
352+ // Try to read the return place as an immediate so that if it is representable as a
353+ // scalar, we can handle it as such, but otherwise, just return the value as is.
354+ return match self . ret . map ( |ret| self . ecx . try_read_immediate ( ret) ) {
355+ Some ( Ok ( Ok ( imm) ) ) => Some ( imm. into ( ) ) ,
356+ _ => self . ret ,
357+ } ;
358+ }
359+
338360 self . ecx . access_local ( self . ecx . frame ( ) , local, None ) . ok ( )
339361 }
340362
@@ -643,7 +665,8 @@ impl CanConstProp {
643665 // lint for x != y
644666 // FIXME(oli-obk): lint variables until they are used in a condition
645667 // FIXME(oli-obk): lint if return value is constant
646- * val = body. local_kind ( local) == LocalKind :: Temp ;
668+ let local_kind = body. local_kind ( local) ;
669+ * val = local_kind == LocalKind :: Temp || local_kind == LocalKind :: ReturnPointer ;
647670
648671 if !* val {
649672 trace ! ( "local {:?} can't be propagated because it's not a temporary" , local) ;
@@ -731,7 +754,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
731754 }
732755 } else {
733756 trace ! ( "can't propagate into {:?}" , local) ;
734- self . remove_const ( local) ;
757+ if local != RETURN_PLACE {
758+ self . remove_const ( local) ;
759+ }
735760 }
736761 }
737762 }
0 commit comments