@@ -662,7 +662,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
662662
663663 // Used for dominance checking within a basic block.
664664 llvm::DenseMap<const SILInstruction *, unsigned > InstNumbers;
665-
665+
666666 DeadEndBlocks DEBlocks;
667667 LoadBorrowNeverInvalidatedAnalysis loadBorrowNeverInvalidatedAnalysis;
668668 bool SingleFunction = true ;
@@ -4748,6 +4748,72 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
47484748 " Type of witness instruction does not match actual type of "
47494749 " witnessed function" );
47504750 }
4751+
4752+ void checkGetAsyncContinuationInstBase (GetAsyncContinuationInstBase *GACI) {
4753+ auto resultTy = GACI->getType ();
4754+ auto &C = resultTy.getASTContext ();
4755+ auto resultBGT = resultTy.getAs <BoundGenericType>();
4756+ require (resultBGT, " Instruction type must be a continuation type" );
4757+ auto resultDecl = resultBGT->getDecl ();
4758+ require (resultDecl == C.getUnsafeContinuationDecl ()
4759+ || resultDecl == C.getUnsafeThrowingContinuationDecl (),
4760+ " Instruction type must be a continuation type" );
4761+ }
4762+
4763+ void checkGetAsyncContinuationInst (GetAsyncContinuationInst *GACI) {
4764+ checkGetAsyncContinuationInstBase (GACI);
4765+ }
4766+
4767+ void checkGetAsyncContinuationAddrInst (GetAsyncContinuationAddrInst *GACI) {
4768+ checkGetAsyncContinuationInstBase (GACI);
4769+
4770+ requireSameType (GACI->getOperand ()->getType (),
4771+ GACI->getLoweredResumeType ().getAddressType (),
4772+ " Operand type must match continuation resume type" );
4773+ }
4774+
4775+ void checkAwaitAsyncContinuationInst (AwaitAsyncContinuationInst *AACI) {
4776+ // The operand must be a GetAsyncContinuation* instruction.
4777+ auto cont = dyn_cast<GetAsyncContinuationInstBase>(AACI->getOperand ());
4778+ require (cont, " can only await the result of a get_async_continuation instruction" );
4779+ bool isAddressForm = isa<GetAsyncContinuationAddrInst>(cont);
4780+
4781+ auto &C = cont->getType ().getASTContext ();
4782+
4783+ // The shape of the successors depends on the continuation instruction being
4784+ // awaited.
4785+ require ((bool )AACI->getErrorBB () == cont->throws (),
4786+ " must have an error successor if and only if the continuation is throwing" );
4787+ if (cont->throws ()) {
4788+ require (AACI->getErrorBB ()->getNumArguments () == 1 ,
4789+ " error successor must take one argument" );
4790+ auto arg = AACI->getErrorBB ()->getArgument (0 );
4791+ auto errorType = C.getErrorDecl ()->getDeclaredType ()->getCanonicalType ();
4792+ requireSameType (arg->getType (),
4793+ SILType::getPrimitiveObjectType (errorType),
4794+ " error successor argument must have Error type" );
4795+
4796+ if (AACI->getFunction ()->hasOwnership ()) {
4797+ require (arg->getOwnershipKind () == ValueOwnershipKind::Owned,
4798+ " error successor argument must be owned" );
4799+ }
4800+ }
4801+ if (isAddressForm) {
4802+ require (AACI->getResumeBB ()->getNumArguments () == 0 ,
4803+ " resume successor must take no arguments for get_async_continuation_addr" );
4804+ } else {
4805+ require (AACI->getResumeBB ()->getNumArguments () == 1 ,
4806+ " resume successor must take one argument for get_async_continuation" );
4807+ auto arg = AACI->getResumeBB ()->getArgument (0 );
4808+
4809+ requireSameType (arg->getType (), cont->getLoweredResumeType (),
4810+ " resume successor must take an argument of the continuation resume type" );
4811+ if (AACI->getFunction ()->hasOwnership ()) {
4812+ require (arg->getOwnershipKind () == ValueOwnershipKind::Owned,
4813+ " resume successor argument must be owned" );
4814+ }
4815+ }
4816+ }
47514817
47524818 // This verifies that the entry block of a SIL function doesn't have
47534819 // any predecessors and also verifies the entry point arguments.
@@ -4902,13 +4968,17 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
49024968 std::set<SILInstruction*> ActiveOps;
49034969
49044970 CFGState CFG = Normal;
4971+
4972+ GetAsyncContinuationInstBase *GotAsyncContinuation = nullptr ;
49054973 };
49064974 };
49074975
49084976 // / Verify the various control-flow-sensitive rules of SIL:
49094977 // /
49104978 // / - stack allocations and deallocations must obey a stack discipline
49114979 // / - accesses must be uniquely ended
4980+ // / - async continuations must be awaited before getting the continuation again, suspending
4981+ // / the task, or exiting the function
49124982 // / - flow-sensitive states must be equivalent on all paths into a block
49134983 void verifyFlowSensitiveRules (SILFunction *F) {
49144984 // Do a traversal of the basic blocks.
@@ -4924,6 +4994,20 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
49244994 for (SILInstruction &i : *BB) {
49254995 CurInstruction = &i;
49264996
4997+ if (i.maySuspend ()) {
4998+ // Instructions that may suspend an async context must not happen
4999+ // while the continuation is being accessed, with the exception of
5000+ // the AwaitAsyncContinuationInst that completes suspending the task.
5001+ if (auto aaci = dyn_cast<AwaitAsyncContinuationInst>(&i)) {
5002+ require (state.GotAsyncContinuation == aaci->getOperand (),
5003+ " encountered await_async_continuation that doesn't match active gotten continuation" );
5004+ state.GotAsyncContinuation = nullptr ;
5005+ } else {
5006+ require (!state.GotAsyncContinuation ,
5007+ " cannot suspend async task while unawaited continuation is active" );
5008+ }
5009+ }
5010+
49275011 if (i.isAllocatingStack ()) {
49285012 state.Stack .push_back (cast<SingleValueInstruction>(&i));
49295013
@@ -4946,13 +5030,18 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
49465030 bool present = state.ActiveOps .erase (beginOp);
49475031 require (present, " operation has already been ended" );
49485032 }
4949-
5033+ } else if (auto gaci = dyn_cast<GetAsyncContinuationInstBase>(&i)) {
5034+ require (!state.GotAsyncContinuation ,
5035+ " get_async_continuation while unawaited continuation is already active" );
5036+ state.GotAsyncContinuation = gaci;
49505037 } else if (auto term = dyn_cast<TermInst>(&i)) {
49515038 if (term->isFunctionExiting ()) {
49525039 require (state.Stack .empty (),
49535040 " return with stack allocs that haven't been deallocated" );
49545041 require (state.ActiveOps .empty (),
49555042 " return with operations still active" );
5043+ require (!state.GotAsyncContinuation ,
5044+ " return with unawaited async continuation" );
49565045
49575046 if (isa<UnwindInst>(term)) {
49585047 require (state.CFG == VerifyFlowSensitiveRulesDetails::YieldUnwind,
@@ -4970,12 +5059,14 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
49705059 }
49715060 }
49725061 }
4973-
5062+
49745063 if (isa<YieldInst>(term)) {
49755064 require (state.CFG != VerifyFlowSensitiveRulesDetails::YieldOnceResume,
49765065 " encountered multiple 'yield's along single path" );
49775066 require (state.CFG == VerifyFlowSensitiveRulesDetails::Normal,
49785067 " encountered 'yield' on abnormal CFG path" );
5068+ require (!state.GotAsyncContinuation ,
5069+ " encountered 'yield' while an unawaited continuation is active" );
49795070 }
49805071
49815072 auto successors = term->getSuccessors ();
@@ -5037,6 +5128,8 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
50375128 " inconsistent active-operations sets entering basic block" );
50385129 require (state.CFG == foundState.CFG ,
50395130 " inconsistent coroutine states entering basic block" );
5131+ require (state.GotAsyncContinuation == foundState.GotAsyncContinuation ,
5132+ " inconsistent active async continuations entering basic block" );
50405133 }
50415134 }
50425135 }
0 commit comments