@@ -4547,6 +4547,7 @@ struct CallbackClassifier {
4547
4547
// / names from `Body`. Errors are added through `DiagEngine`, possibly
4548
4548
// / resulting in partially filled out blocks.
4549
4549
static void classifyInto (ClassifiedBlocks &Blocks,
4550
+ llvm::DenseSet<SwitchStmt *> &HandledSwitches,
4550
4551
DiagnosticEngine &DiagEngine,
4551
4552
ArrayRef<const ParamDecl *> SuccessParams,
4552
4553
const ParamDecl *ErrParam, HandlerType ResultType,
@@ -4558,25 +4559,30 @@ struct CallbackClassifier {
4558
4559
if (ErrParam)
4559
4560
ParamsSet.insert (ErrParam);
4560
4561
4561
- CallbackClassifier Classifier (Blocks, DiagEngine, ParamsSet, ErrParam,
4562
+ CallbackClassifier Classifier (Blocks, HandledSwitches, DiagEngine,
4563
+ ParamsSet, ErrParam,
4562
4564
ResultType == HandlerType::RESULT);
4563
4565
Classifier.classifyNodes (Body);
4564
4566
}
4565
4567
4566
4568
private:
4567
4569
ClassifiedBlocks &Blocks;
4570
+ llvm::DenseSet<SwitchStmt *> &HandledSwitches;
4568
4571
DiagnosticEngine &DiagEngine;
4569
4572
ClassifiedBlock *CurrentBlock;
4570
4573
llvm::DenseSet<const Decl *> ParamsSet;
4571
4574
const ParamDecl *ErrParam;
4572
4575
bool IsResultParam;
4573
4576
4574
- CallbackClassifier (ClassifiedBlocks &Blocks, DiagnosticEngine &DiagEngine,
4577
+ CallbackClassifier (ClassifiedBlocks &Blocks,
4578
+ llvm::DenseSet<SwitchStmt *> &HandledSwitches,
4579
+ DiagnosticEngine &DiagEngine,
4575
4580
llvm::DenseSet<const Decl *> ParamsSet,
4576
4581
const ParamDecl *ErrParam, bool IsResultParam)
4577
- : Blocks(Blocks), DiagEngine(DiagEngine),
4578
- CurrentBlock (&Blocks.SuccessBlock), ParamsSet(ParamsSet),
4579
- ErrParam(ErrParam), IsResultParam(IsResultParam) {}
4582
+ : Blocks(Blocks), HandledSwitches(HandledSwitches),
4583
+ DiagEngine (DiagEngine), CurrentBlock(&Blocks.SuccessBlock),
4584
+ ParamsSet(ParamsSet), ErrParam(ErrParam), IsResultParam(IsResultParam) {
4585
+ }
4580
4586
4581
4587
void classifyNodes (ArrayRef<ASTNode> Nodes) {
4582
4588
for (auto I = Nodes.begin (), E = Nodes.end (); I < E; ++I) {
@@ -4710,6 +4716,7 @@ struct CallbackClassifier {
4710
4716
void classifySwitch (SwitchStmt *SS) {
4711
4717
if (!IsResultParam || singleSwitchSubject (SS) != ErrParam) {
4712
4718
CurrentBlock->addNode (SS);
4719
+ return ;
4713
4720
}
4714
4721
4715
4722
for (auto *CS : SS->getCases ()) {
@@ -4747,6 +4754,8 @@ struct CallbackClassifier {
4747
4754
if (DiagEngine.hadAnyError ())
4748
4755
return ;
4749
4756
}
4757
+ // Mark this switch statement as having been transformed.
4758
+ HandledSwitches.insert (SS);
4750
4759
}
4751
4760
};
4752
4761
@@ -4805,6 +4814,9 @@ class AsyncConverter : private SourceEntityWalker {
4805
4814
// references to it
4806
4815
llvm::DenseMap<const Decl *, std::string> Names;
4807
4816
4817
+ // / The switch statements that have been re-written by this transform.
4818
+ llvm::DenseSet<SwitchStmt *> HandledSwitches;
4819
+
4808
4820
// These are per-node (ie. are saved and restored on each convertNode call)
4809
4821
SourceLoc LastAddedLoc;
4810
4822
int NestedExprCount = 0 ;
@@ -4875,6 +4887,9 @@ class AsyncConverter : private SourceEntityWalker {
4875
4887
NestedExprCount++;
4876
4888
return true ;
4877
4889
}
4890
+ // Note we don't walk into any nested local function decls. If we start
4891
+ // doing so in the future, be sure to update the logic that deals with
4892
+ // converting unhandled returns into placeholders in walkToStmtPre.
4878
4893
return false ;
4879
4894
}
4880
4895
@@ -4892,18 +4907,16 @@ class AsyncConverter : private SourceEntityWalker {
4892
4907
bool AddPlaceholder = Placeholders.count (D);
4893
4908
StringRef Name = newNameFor (D, false );
4894
4909
if (AddPlaceholder || !Name.empty ())
4895
- return addCustom (DRE->getStartLoc (),
4896
- Lexer::getLocForEndOfToken (SM, DRE->getEndLoc ()),
4897
- [&]() {
4898
- if (AddPlaceholder)
4899
- OS << PLACEHOLDER_START;
4900
- if (!Name.empty ())
4901
- OS << Name;
4902
- else
4903
- D->getName ().print (OS);
4904
- if (AddPlaceholder)
4905
- OS << PLACEHOLDER_END;
4906
- });
4910
+ return addCustom (DRE->getSourceRange (), [&]() {
4911
+ if (AddPlaceholder)
4912
+ OS << PLACEHOLDER_START;
4913
+ if (!Name.empty ())
4914
+ OS << Name;
4915
+ else
4916
+ D->getName ().print (OS);
4917
+ if (AddPlaceholder)
4918
+ OS << PLACEHOLDER_END;
4919
+ });
4907
4920
}
4908
4921
} else if (isa<ForceValueExpr>(E) || isa<BindOptionalExpr>(E)) {
4909
4922
// Remove a force unwrap or optional chain of a returned success value,
@@ -4917,26 +4930,57 @@ class AsyncConverter : private SourceEntityWalker {
4917
4930
// completely valid.
4918
4931
if (auto *D = E->getReferencedDecl ().getDecl ()) {
4919
4932
if (Unwraps.count (D))
4920
- return addCustom (E->getStartLoc (), E-> getEndLoc (). getAdvancedLoc ( 1 ),
4933
+ return addCustom (E->getSourceRange ( ),
4921
4934
[&]() { OS << newNameFor (D, true ); });
4922
4935
}
4923
4936
} else if (NestedExprCount == 0 ) {
4924
4937
if (CallExpr *CE = TopHandler.getAsHandlerCall (E))
4925
- return addCustom (CE->getStartLoc (), CE->getEndLoc ().getAdvancedLoc (1 ),
4926
- [&]() { addHandlerCall (CE); });
4938
+ return addCustom (CE->getSourceRange (), [&]() { addHandlerCall (CE); });
4927
4939
4928
4940
if (auto *CE = dyn_cast<CallExpr>(E)) {
4929
4941
auto HandlerDesc = AsyncHandlerDesc::find (
4930
4942
getUnderlyingFunc (CE->getFn ()), StartNode.dyn_cast <Expr *>() == CE);
4931
4943
if (HandlerDesc.isValid ())
4932
- return addCustom (CE->getStartLoc (), CE-> getEndLoc (). getAdvancedLoc ( 1 ),
4944
+ return addCustom (CE->getSourceRange ( ),
4933
4945
[&]() { addAsyncAlternativeCall (CE, HandlerDesc); });
4934
4946
}
4935
4947
}
4936
4948
4937
4949
NestedExprCount++;
4938
4950
return true ;
4939
4951
}
4952
+
4953
+ bool replaceRangeWithPlaceholder (SourceRange range) {
4954
+ return addCustom (range, [&]() {
4955
+ OS << PLACEHOLDER_START;
4956
+ addRange (range, /* toEndOfToken*/ true );
4957
+ OS << PLACEHOLDER_END;
4958
+ });
4959
+ }
4960
+
4961
+ bool walkToStmtPre (Stmt *S) override {
4962
+ // Some break and return statements need to be turned into placeholders,
4963
+ // as they may no longer perform the control flow that the user is
4964
+ // expecting.
4965
+ if (!S->isImplicit ()) {
4966
+ // For a break, if it's jumping out of a switch statement that we've
4967
+ // re-written as a part of the transform, turn it into a placeholder, as
4968
+ // it would have been lifted out of the switch statement.
4969
+ if (auto *BS = dyn_cast<BreakStmt>(S)) {
4970
+ if (auto *SS = dyn_cast<SwitchStmt>(BS->getTarget ())) {
4971
+ if (HandledSwitches.contains (SS))
4972
+ replaceRangeWithPlaceholder (S->getSourceRange ());
4973
+ }
4974
+ }
4975
+
4976
+ // For a return, if it's not nested inside another closure or function,
4977
+ // turn it into a placeholder, as it will be lifted out of the callback.
4978
+ if (isa<ReturnStmt>(S) && NestedExprCount == 0 )
4979
+ replaceRangeWithPlaceholder (S->getSourceRange ());
4980
+ }
4981
+ return true ;
4982
+ }
4983
+
4940
4984
#undef PLACEHOLDER_START
4941
4985
#undef PLACEHOLDER_END
4942
4986
@@ -4945,11 +4989,10 @@ class AsyncConverter : private SourceEntityWalker {
4945
4989
return true ;
4946
4990
}
4947
4991
4948
- bool addCustom (SourceLoc End, SourceLoc NextAddedLoc,
4949
- std::function<void ()> Custom = {}) {
4950
- addRange (LastAddedLoc, End);
4992
+ bool addCustom (SourceRange Range, std::function<void ()> Custom = {}) {
4993
+ addRange (LastAddedLoc, Range.Start );
4951
4994
Custom ();
4952
- LastAddedLoc = NextAddedLoc ;
4995
+ LastAddedLoc = Lexer::getLocForEndOfToken (SM, Range. End ) ;
4953
4996
return false ;
4954
4997
}
4955
4998
@@ -5140,9 +5183,9 @@ class AsyncConverter : private SourceEntityWalker {
5140
5183
if (!HandlerDesc.HasError ) {
5141
5184
Blocks.SuccessBlock .addAllNodes (CallbackBody);
5142
5185
} else if (!CallbackBody.empty ()) {
5143
- CallbackClassifier::classifyInto (Blocks, DiagEngine, SuccessParams ,
5144
- ErrParam, HandlerDesc. Type ,
5145
- CallbackBody);
5186
+ CallbackClassifier::classifyInto (Blocks, HandledSwitches, DiagEngine ,
5187
+ SuccessParams, ErrParam ,
5188
+ HandlerDesc. Type , CallbackBody);
5146
5189
if (DiagEngine.hadAnyError ()) {
5147
5190
// Can only fallback when the results are params, in which case only
5148
5191
// the names are used (defaulted to the names of the params if none)
0 commit comments