@@ -4517,6 +4517,7 @@ struct CallbackClassifier {
45174517 // / names from `Body`. Errors are added through `DiagEngine`, possibly
45184518 // / resulting in partially filled out blocks.
45194519 static void classifyInto (ClassifiedBlocks &Blocks,
4520+ llvm::DenseSet<SwitchStmt *> &HandledSwitches,
45204521 DiagnosticEngine &DiagEngine,
45214522 ArrayRef<const ParamDecl *> SuccessParams,
45224523 const ParamDecl *ErrParam, HandlerType ResultType,
@@ -4528,25 +4529,30 @@ struct CallbackClassifier {
45284529 if (ErrParam)
45294530 ParamsSet.insert (ErrParam);
45304531
4531- CallbackClassifier Classifier (Blocks, DiagEngine, ParamsSet, ErrParam,
4532+ CallbackClassifier Classifier (Blocks, HandledSwitches, DiagEngine,
4533+ ParamsSet, ErrParam,
45324534 ResultType == HandlerType::RESULT);
45334535 Classifier.classifyNodes (Body);
45344536 }
45354537
45364538private:
45374539 ClassifiedBlocks &Blocks;
4540+ llvm::DenseSet<SwitchStmt *> &HandledSwitches;
45384541 DiagnosticEngine &DiagEngine;
45394542 ClassifiedBlock *CurrentBlock;
45404543 llvm::DenseSet<const Decl *> ParamsSet;
45414544 const ParamDecl *ErrParam;
45424545 bool IsResultParam;
45434546
4544- CallbackClassifier (ClassifiedBlocks &Blocks, DiagnosticEngine &DiagEngine,
4547+ CallbackClassifier (ClassifiedBlocks &Blocks,
4548+ llvm::DenseSet<SwitchStmt *> &HandledSwitches,
4549+ DiagnosticEngine &DiagEngine,
45454550 llvm::DenseSet<const Decl *> ParamsSet,
45464551 const ParamDecl *ErrParam, bool IsResultParam)
4547- : Blocks(Blocks), DiagEngine(DiagEngine),
4548- CurrentBlock (&Blocks.SuccessBlock), ParamsSet(ParamsSet),
4549- ErrParam(ErrParam), IsResultParam(IsResultParam) {}
4552+ : Blocks(Blocks), HandledSwitches(HandledSwitches),
4553+ DiagEngine (DiagEngine), CurrentBlock(&Blocks.SuccessBlock),
4554+ ParamsSet(ParamsSet), ErrParam(ErrParam), IsResultParam(IsResultParam) {
4555+ }
45504556
45514557 void classifyNodes (ArrayRef<ASTNode> Nodes) {
45524558 for (auto I = Nodes.begin (), E = Nodes.end (); I < E; ++I) {
@@ -4718,6 +4724,8 @@ struct CallbackClassifier {
47184724 if (DiagEngine.hadAnyError ())
47194725 return ;
47204726 }
4727+ // Mark this switch statement as having been transformed.
4728+ HandledSwitches.insert (SS);
47214729 }
47224730};
47234731
@@ -4776,6 +4784,9 @@ class AsyncConverter : private SourceEntityWalker {
47764784 // references to it
47774785 llvm::DenseMap<const Decl *, std::string> Names;
47784786
4787+ // / The switch statements that have been re-written by this transform.
4788+ llvm::DenseSet<SwitchStmt *> HandledSwitches;
4789+
47794790 // These are per-node (ie. are saved and restored on each convertNode call)
47804791 SourceLoc LastAddedLoc;
47814792 int NestedExprCount = 0 ;
@@ -4846,6 +4857,9 @@ class AsyncConverter : private SourceEntityWalker {
48464857 NestedExprCount++;
48474858 return true ;
48484859 }
4860+ // Note we don't walk into any nested local function decls. If we start
4861+ // doing so in the future, be sure to update the logic that deals with
4862+ // converting unhandled returns into placeholders in walkToStmtPre.
48494863 return false ;
48504864 }
48514865
@@ -4905,6 +4919,38 @@ class AsyncConverter : private SourceEntityWalker {
49054919 NestedExprCount++;
49064920 return true ;
49074921 }
4922+
4923+ bool replaceRangeWithPlaceholder (SourceRange range) {
4924+ return addCustom (range, [&]() {
4925+ OS << PLACEHOLDER_START;
4926+ addRange (range, /* toEndOfToken*/ true );
4927+ OS << PLACEHOLDER_END;
4928+ });
4929+ }
4930+
4931+ bool walkToStmtPre (Stmt *S) override {
4932+ // Some break and return statements need to be turned into placeholders,
4933+ // as they may no longer perform the control flow that the user is
4934+ // expecting.
4935+ if (!S->isImplicit ()) {
4936+ // For a break, if it's jumping out of a switch statement that we've
4937+ // re-written as a part of the transform, turn it into a placeholder, as
4938+ // it would have been lifted out of the switch statement.
4939+ if (auto *BS = dyn_cast<BreakStmt>(S)) {
4940+ if (auto *SS = dyn_cast<SwitchStmt>(BS->getTarget ())) {
4941+ if (HandledSwitches.contains (SS))
4942+ replaceRangeWithPlaceholder (S->getSourceRange ());
4943+ }
4944+ }
4945+
4946+ // For a return, if it's not nested inside another closure or function,
4947+ // turn it into a placeholder, as it will be lifted out of the callback.
4948+ if (isa<ReturnStmt>(S) && NestedExprCount == 0 )
4949+ replaceRangeWithPlaceholder (S->getSourceRange ());
4950+ }
4951+ return true ;
4952+ }
4953+
49084954#undef PLACEHOLDER_START
49094955#undef PLACEHOLDER_END
49104956
@@ -5107,9 +5153,9 @@ class AsyncConverter : private SourceEntityWalker {
51075153 if (!HandlerDesc.HasError ) {
51085154 Blocks.SuccessBlock .addAllNodes (CallbackBody);
51095155 } else if (!CallbackBody.empty ()) {
5110- CallbackClassifier::classifyInto (Blocks, DiagEngine, SuccessParams ,
5111- ErrParam, HandlerDesc. Type ,
5112- CallbackBody);
5156+ CallbackClassifier::classifyInto (Blocks, HandledSwitches, DiagEngine ,
5157+ SuccessParams, ErrParam ,
5158+ HandlerDesc. Type , CallbackBody);
51135159 if (DiagEngine.hadAnyError ()) {
51145160 // Can only fallback when the results are params, in which case only
51155161 // the names are used (defaulted to the names of the params if none)
0 commit comments