@@ -272,6 +272,17 @@ class PotentialThrowReason {
272272 CallRethrowsWithDefaultThrowingArgument,
273273 };
274274
275+ static StringRef kindToString (Kind k) {
276+ switch (k) {
277+ case Kind::Throw: return " Throw" ;
278+ case Kind::CallThrows: return " CallThrows" ;
279+ case Kind::CallRethrowsWithExplicitThrowingArgument:
280+ return " CallRethrowsWithExplicitThrowingArgument" ;
281+ case Kind::CallRethrowsWithDefaultThrowingArgument:
282+ return " CallRethrowsWithDefaultThrowingArgument" ;
283+ }
284+ }
285+
275286private:
276287 Expr *TheExpression;
277288 Kind TheKind;
@@ -329,6 +340,26 @@ class Classification {
329340 ThrowingKind Result = ThrowingKind::None;
330341 Optional<PotentialThrowReason> Reason;
331342
343+ void print (raw_ostream &out) const {
344+ out << " { IsInvalid = " << IsInvalid
345+ << " , IsAsync = " << IsAsync
346+ << " , Result = ThrowingKind::" ;
347+
348+ switch (Result) {
349+ case ThrowingKind::None: out << " None" ; break ;
350+ case ThrowingKind::RethrowingOnly: out << " RethrowingOnly" ; break ;
351+ case ThrowingKind::Throws: out << " Throws" ; break ;
352+ }
353+
354+ out << " , Reason = " ;
355+ if (!Reason)
356+ out << " nil" ;
357+ else
358+ out << PotentialThrowReason::kindToString (Reason.getValue ().getKind ());
359+
360+ out << " }" ;
361+ }
362+
332363public:
333364 Classification () : Result(ThrowingKind::None) {}
334365 explicit Classification (ThrowingKind result, PotentialThrowReason reason,
@@ -364,17 +395,21 @@ class Classification {
364395 return result;
365396 }
366397
367- static Classification forRethrowingOnly (PotentialThrowReason reason) {
398+ static Classification forRethrowingOnly (PotentialThrowReason reason, bool isAsync ) {
368399 Classification result;
369400 result.Result = ThrowingKind::RethrowingOnly;
370401 result.Reason = reason;
402+ result.IsAsync = isAsync;
371403 return result;
372404 }
373405
374406 void merge (Classification other) {
407+ bool oldAsync = IsAsync;
408+
375409 if (other.getResult () > getResult ())
376410 *this = other;
377- IsAsync |= other.IsAsync ;
411+
412+ IsAsync = oldAsync | other.IsAsync ;
378413 }
379414
380415 bool isInvalid () const { return IsInvalid; }
@@ -386,6 +421,10 @@ class Classification {
386421 }
387422
388423 bool isAsync () const { return IsAsync; }
424+
425+ #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
426+ LLVM_DUMP_METHOD void dump () const { print (llvm::errs ()); }
427+ #endif
389428};
390429
391430
@@ -399,7 +438,7 @@ class ApplyClassifier {
399438 DeclContext *RethrowsDC = nullptr ;
400439 bool inRethrowsContext () const { return RethrowsDC != nullptr ; }
401440
402- // / Check to see if the given function application throws.
441+ // / Check to see if the given function application throws or is async .
403442 Classification classifyApply (ApplyExpr *E) {
404443 // An apply expression is a potential throw site if the function throws.
405444 // But if the expression didn't type-check, suppress diagnostics.
@@ -461,7 +500,8 @@ class ApplyClassifier {
461500 if (!type) return Classification::forInvalidCode ();
462501
463502 // Use the most significant result from the arguments.
464- Classification result;
503+ Classification result = isAsync ? Classification::forAsync ()
504+ : Classification ();
465505 for (auto arg : llvm::reverse (args)) {
466506 auto fnType = type->getAs <AnyFunctionType>();
467507 if (!fnType) return Classification::forInvalidCode ();
@@ -527,7 +567,7 @@ class ApplyClassifier {
527567 // If we're currently doing rethrows-checking on the body of the
528568 // function which declares the parameter, it's rethrowing-only.
529569 if (param->getDeclContext () == RethrowsDC)
530- return Classification::forRethrowingOnly (reason);
570+ return Classification::forRethrowingOnly (reason, /* async */ false );
531571
532572 // Otherwise, it throws unconditionally.
533573 return Classification::forThrow (reason, /* async*/ false );
@@ -1235,8 +1275,12 @@ class Context {
12351275 highlight = apply->getSourceRange ();
12361276
12371277 auto diag = diag::async_call_without_await;
1238- if (isAutoClosure ())
1278+ // To produce a better error message, check if it is an autoclosure.
1279+ // We do not use 'Context::isAutoClosure' b/c it gives conservative answers.
1280+ if (Function && llvm::isa_and_nonnull<AutoClosureExpr>(
1281+ Function->getAbstractClosureExpr ()))
12391282 diag = diag::async_call_without_await_in_autoclosure;
1283+
12401284 ctx.Diags .diagnose (node.getStartLoc (), diag)
12411285 .fixItInsert (node.getStartLoc (), " await " )
12421286 .highlight (highlight);
@@ -1464,6 +1508,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
14641508 OldMaxThrowingKind = std::max (OldMaxThrowingKind, Self.MaxThrowingKind );
14651509 }
14661510
1511+ void preserveCoverageFromOptionalOrForcedTryOperand () {
1512+ OldFlags.mergeFrom (ContextFlags::asyncAwaitFlags (), Self.Flags );
1513+ }
1514+
14671515 void preserveCoverageFromInterpolatedString () {
14681516 OldFlags.mergeFrom (ContextFlags::HasAnyThrowSite, Self.Flags );
14691517 OldFlags.mergeFrom (ContextFlags::HasTryThrowSite, Self.Flags );
@@ -1808,6 +1856,8 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
18081856 if (!Flags.has (ContextFlags::HasTryThrowSite)) {
18091857 Ctx.Diags .diagnose (E->getLoc (), diag::no_throw_in_try);
18101858 }
1859+
1860+ scope.preserveCoverageFromOptionalOrForcedTryOperand ();
18111861 return ShouldNotRecurse;
18121862 }
18131863
@@ -1822,6 +1872,8 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
18221872 if (!Flags.has (ContextFlags::HasTryThrowSite)) {
18231873 Ctx.Diags .diagnose (E->getLoc (), diag::no_throw_in_try);
18241874 }
1875+
1876+ scope.preserveCoverageFromOptionalOrForcedTryOperand ();
18251877 return ShouldNotRecurse;
18261878 }
18271879};
0 commit comments