@@ -4517,6 +4517,7 @@ struct CallbackClassifier {
4517
4517
// / names from `Body`. Errors are added through `DiagEngine`, possibly
4518
4518
// / resulting in partially filled out blocks.
4519
4519
static void classifyInto (ClassifiedBlocks &Blocks,
4520
+ llvm::DenseSet<SwitchStmt *> &HandledSwitches,
4520
4521
DiagnosticEngine &DiagEngine,
4521
4522
ArrayRef<const ParamDecl *> SuccessParams,
4522
4523
const ParamDecl *ErrParam, HandlerType ResultType,
@@ -4528,25 +4529,30 @@ struct CallbackClassifier {
4528
4529
if (ErrParam)
4529
4530
ParamsSet.insert (ErrParam);
4530
4531
4531
- CallbackClassifier Classifier (Blocks, DiagEngine, ParamsSet, ErrParam,
4532
+ CallbackClassifier Classifier (Blocks, HandledSwitches, DiagEngine,
4533
+ ParamsSet, ErrParam,
4532
4534
ResultType == HandlerType::RESULT);
4533
4535
Classifier.classifyNodes (Body);
4534
4536
}
4535
4537
4536
4538
private:
4537
4539
ClassifiedBlocks &Blocks;
4540
+ llvm::DenseSet<SwitchStmt *> &HandledSwitches;
4538
4541
DiagnosticEngine &DiagEngine;
4539
4542
ClassifiedBlock *CurrentBlock;
4540
4543
llvm::DenseSet<const Decl *> ParamsSet;
4541
4544
const ParamDecl *ErrParam;
4542
4545
bool IsResultParam;
4543
4546
4544
- CallbackClassifier (ClassifiedBlocks &Blocks, DiagnosticEngine &DiagEngine,
4547
+ CallbackClassifier (ClassifiedBlocks &Blocks,
4548
+ llvm::DenseSet<SwitchStmt *> &HandledSwitches,
4549
+ DiagnosticEngine &DiagEngine,
4545
4550
llvm::DenseSet<const Decl *> ParamsSet,
4546
4551
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
+ }
4550
4556
4551
4557
void classifyNodes (ArrayRef<ASTNode> Nodes) {
4552
4558
for (auto I = Nodes.begin (), E = Nodes.end (); I < E; ++I) {
@@ -4718,6 +4724,8 @@ struct CallbackClassifier {
4718
4724
if (DiagEngine.hadAnyError ())
4719
4725
return ;
4720
4726
}
4727
+ // Mark this switch statement as having been transformed.
4728
+ HandledSwitches.insert (SS);
4721
4729
}
4722
4730
};
4723
4731
@@ -4776,6 +4784,9 @@ class AsyncConverter : private SourceEntityWalker {
4776
4784
// references to it
4777
4785
llvm::DenseMap<const Decl *, std::string> Names;
4778
4786
4787
+ // / The switch statements that have been re-written by this transform.
4788
+ llvm::DenseSet<SwitchStmt *> HandledSwitches;
4789
+
4779
4790
// These are per-node (ie. are saved and restored on each convertNode call)
4780
4791
SourceLoc LastAddedLoc;
4781
4792
int NestedExprCount = 0 ;
@@ -4846,6 +4857,9 @@ class AsyncConverter : private SourceEntityWalker {
4846
4857
NestedExprCount++;
4847
4858
return true ;
4848
4859
}
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.
4849
4863
return false ;
4850
4864
}
4851
4865
@@ -4905,6 +4919,38 @@ class AsyncConverter : private SourceEntityWalker {
4905
4919
NestedExprCount++;
4906
4920
return true ;
4907
4921
}
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
+
4908
4954
#undef PLACEHOLDER_START
4909
4955
#undef PLACEHOLDER_END
4910
4956
@@ -5107,9 +5153,9 @@ class AsyncConverter : private SourceEntityWalker {
5107
5153
if (!HandlerDesc.HasError ) {
5108
5154
Blocks.SuccessBlock .addAllNodes (CallbackBody);
5109
5155
} 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);
5113
5159
if (DiagEngine.hadAnyError ()) {
5114
5160
// Can only fallback when the results are params, in which case only
5115
5161
// the names are used (defaulted to the names of the params if none)
0 commit comments