@@ -512,21 +512,28 @@ struct GetReturnObjectManager {
512
512
}();
513
513
}
514
514
515
+ bool shouldEmitAlloca () {
516
+ if (DirectEmit)
517
+ return false ;
518
+
519
+ if (!isa_and_nonnull<DeclStmt>(S.getResultDecl ())) {
520
+ // If get_return_object returns void, no need to do an alloca.
521
+ return false ;
522
+ }
523
+
524
+ return true ;
525
+ }
526
+
515
527
// The gro variable has to outlive coroutine frame and coroutine promise, but,
516
528
// it can only be initialized after coroutine promise was created, thus, we
517
529
// split its emission in two parts. EmitGroAlloca emits an alloca and sets up
518
530
// cleanups. Later when coroutine promise is available we initialize the gro
519
531
// and sets the flag that the cleanup is now active.
520
532
void EmitGroAlloca () {
521
- if (DirectEmit)
522
- return ;
523
-
524
- auto *GroDeclStmt = dyn_cast_or_null<DeclStmt>(S.getResultDecl ());
525
- if (!GroDeclStmt) {
526
- // If get_return_object returns void, no need to do an alloca.
533
+ if (!shouldEmitAlloca ())
527
534
return ;
528
- }
529
535
536
+ auto *GroDeclStmt = cast<DeclStmt>(S.getResultDecl ());
530
537
auto *GroVarDecl = cast<VarDecl>(GroDeclStmt->getSingleDecl ());
531
538
532
539
// Set GRO flag that it is not initialized yet
@@ -658,6 +665,25 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
658
665
659
666
GetReturnObjectManager GroManager (*this , S);
660
667
CurCoro.Data ->CleanupJD = getJumpDestInCurrentScope (RetBB);
668
+ bool shouldGROEmitAlloca = GroManager.shouldEmitAlloca ();
669
+ auto emitRetBlock = [&]() {
670
+ EmitBlock (RetBB);
671
+ // Emit coro.end before getReturnStmt (and parameter destructors), since
672
+ // resume and destroy parts of the coroutine should not include them.
673
+ llvm::Function *CoroEnd = CGM.getIntrinsic (llvm::Intrinsic::coro_end);
674
+ Builder.CreateCall (CoroEnd,
675
+ {NullPtr, Builder.getFalse (),
676
+ llvm::ConstantTokenNone::get (CoroEnd->getContext ())});
677
+
678
+ if (Stmt *Ret = S.getReturnStmt ()) {
679
+ // Since we already emitted the return value above, so we shouldn't
680
+ // emit it again here.
681
+ if (GroManager.DirectEmit )
682
+ cast<ReturnStmt>(Ret)->setRetValue (nullptr );
683
+ EmitStmt (Ret);
684
+ }
685
+ };
686
+
661
687
{
662
688
CGDebugInfo *DI = getDebugInfo ();
663
689
ParamReferenceReplacerRAII ParamReplacer (LocalDeclMap);
@@ -757,23 +783,16 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
757
783
EmitBlock (FinalBB, /* IsFinished=*/ true );
758
784
}
759
785
760
- EmitBlock (RetBB);
761
- // Emit coro.end before getReturnStmt (and parameter destructors), since
762
- // resume and destroy parts of the coroutine should not include them.
763
- llvm::Function *CoroEnd = CGM.getIntrinsic (llvm::Intrinsic::coro_end);
764
- Builder.CreateCall (CoroEnd,
765
- {NullPtr, Builder.getFalse (),
766
- llvm::ConstantTokenNone::get (CoroEnd->getContext ())});
767
-
768
- if (Stmt *Ret = S.getReturnStmt ()) {
769
- // Since we already emitted the return value above, so we shouldn't
770
- // emit it again here.
771
- if (GroManager.DirectEmit )
772
- cast<ReturnStmt>(Ret)->setRetValue (nullptr );
773
- EmitStmt (Ret);
774
- }
786
+ // If an alloca is emitted for GRO handling, make sure the ret block
787
+ // is taken into account within the appropriate cleanup.
788
+ if (shouldGROEmitAlloca)
789
+ emitRetBlock ();
775
790
}
776
791
792
+ // No GRO alloca's, no need for to account for extra cleanups.
793
+ if (!shouldGROEmitAlloca)
794
+ emitRetBlock ();
795
+
777
796
// LLVM require the frontend to mark the coroutine.
778
797
CurFn->setPresplitCoroutine ();
779
798
}
0 commit comments