@@ -185,21 +185,8 @@ static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType,
185
185
186
186
static bool isValidCoroutineContext (Sema &S, SourceLocation Loc,
187
187
StringRef Keyword) {
188
- // 'co_await' and 'co_yield' are not permitted in unevaluated operands,
189
- // such as subexpressions of \c sizeof.
190
- //
191
- // [expr.await]p2, emphasis added: "An await-expression shall appear only in
192
- // a *potentially evaluated* expression within the compound-statement of a
193
- // function-body outside of a handler [...] A context within a function where
194
- // an await-expression can appear is called a suspension context of the
195
- // function." And per [expr.yield]p1: "A yield-expression shall appear only
196
- // within a suspension context of a function."
197
- if (S.isUnevaluatedContext ()) {
198
- S.Diag (Loc, diag::err_coroutine_unevaluated_context) << Keyword;
199
- return false ;
200
- }
201
-
202
- // Per [expr.await]p2, any other usage must be within a function.
188
+ // [expr.await]p2 dictates that 'co_await' and 'co_yield' must be used within
189
+ // a function body.
203
190
// FIXME: This also covers [expr.await]p2: "An await-expression shall not
204
191
// appear in a default argument." But the diagnostic QoI here could be
205
192
// improved to inform the user that default arguments specifically are not
@@ -668,12 +655,57 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
668
655
return true ;
669
656
}
670
657
658
+ // Recursively walks up the scope hierarchy until either a 'catch' or a function
659
+ // scope is found, whichever comes first.
660
+ static bool isWithinCatchScope (Scope *S) {
661
+ // 'co_await' and 'co_yield' keywords are disallowed within catch blocks, but
662
+ // lambdas that use 'co_await' are allowed. The loop below ends when a
663
+ // function scope is found in order to ensure the following behavior:
664
+ //
665
+ // void foo() { // <- function scope
666
+ // try { //
667
+ // co_await x; // <- 'co_await' is OK within a function scope
668
+ // } catch { // <- catch scope
669
+ // co_await x; // <- 'co_await' is not OK within a catch scope
670
+ // []() { // <- function scope
671
+ // co_await x; // <- 'co_await' is OK within a function scope
672
+ // }();
673
+ // }
674
+ // }
675
+ while (S && !(S->getFlags () & Scope::FnScope)) {
676
+ if (S->getFlags () & Scope::CatchScope)
677
+ return true ;
678
+ S = S->getParent ();
679
+ }
680
+ return false ;
681
+ }
682
+
683
+ // [expr.await]p2, emphasis added: "An await-expression shall appear only in
684
+ // a *potentially evaluated* expression within the compound-statement of a
685
+ // function-body *outside of a handler* [...] A context within a function
686
+ // where an await-expression can appear is called a suspension context of the
687
+ // function."
688
+ static void checkSuspensionContext (Sema &S, SourceLocation Loc,
689
+ StringRef Keyword) {
690
+ // First emphasis of [expr.await]p2: must be a potentially evaluated context.
691
+ // That is, 'co_await' and 'co_yield' cannot appear in subexpressions of
692
+ // \c sizeof.
693
+ if (S.isUnevaluatedContext ())
694
+ S.Diag (Loc, diag::err_coroutine_unevaluated_context) << Keyword;
695
+
696
+ // Second emphasis of [expr.await]p2: must be outside of an exception handler.
697
+ if (isWithinCatchScope (S.getCurScope ()))
698
+ S.Diag (Loc, diag::err_coroutine_within_handler) << Keyword;
699
+ }
700
+
671
701
ExprResult Sema::ActOnCoawaitExpr (Scope *S, SourceLocation Loc, Expr *E) {
672
702
if (!ActOnCoroutineBodyStart (S, Loc, " co_await" )) {
673
703
CorrectDelayedTyposInExpr (E);
674
704
return ExprError ();
675
705
}
676
706
707
+ checkSuspensionContext (*this , Loc, " co_await" );
708
+
677
709
if (E->getType ()->isPlaceholderType ()) {
678
710
ExprResult R = CheckPlaceholderExpr (E);
679
711
if (R.isInvalid ()) return ExprError ();
@@ -771,6 +803,8 @@ ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
771
803
return ExprError ();
772
804
}
773
805
806
+ checkSuspensionContext (*this , Loc, " co_yield" );
807
+
774
808
// Build yield_value call.
775
809
ExprResult Awaitable = buildPromiseCall (
776
810
*this , getCurFunction ()->CoroutinePromise , Loc, " yield_value" , E);
0 commit comments