@@ -272,6 +272,17 @@ class PotentialThrowReason {
272
272
CallRethrowsWithDefaultThrowingArgument,
273
273
};
274
274
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
+
275
286
private:
276
287
Expr *TheExpression;
277
288
Kind TheKind;
@@ -329,6 +340,26 @@ class Classification {
329
340
ThrowingKind Result = ThrowingKind::None;
330
341
Optional<PotentialThrowReason> Reason;
331
342
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
+
332
363
public:
333
364
Classification () : Result(ThrowingKind::None) {}
334
365
explicit Classification (ThrowingKind result, PotentialThrowReason reason,
@@ -364,17 +395,21 @@ class Classification {
364
395
return result;
365
396
}
366
397
367
- static Classification forRethrowingOnly (PotentialThrowReason reason) {
398
+ static Classification forRethrowingOnly (PotentialThrowReason reason, bool isAsync ) {
368
399
Classification result;
369
400
result.Result = ThrowingKind::RethrowingOnly;
370
401
result.Reason = reason;
402
+ result.IsAsync = isAsync;
371
403
return result;
372
404
}
373
405
374
406
void merge (Classification other) {
407
+ bool oldAsync = IsAsync;
408
+
375
409
if (other.getResult () > getResult ())
376
410
*this = other;
377
- IsAsync |= other.IsAsync ;
411
+
412
+ IsAsync = oldAsync | other.IsAsync ;
378
413
}
379
414
380
415
bool isInvalid () const { return IsInvalid; }
@@ -386,6 +421,10 @@ class Classification {
386
421
}
387
422
388
423
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
389
428
};
390
429
391
430
@@ -399,7 +438,7 @@ class ApplyClassifier {
399
438
DeclContext *RethrowsDC = nullptr ;
400
439
bool inRethrowsContext () const { return RethrowsDC != nullptr ; }
401
440
402
- // / Check to see if the given function application throws.
441
+ // / Check to see if the given function application throws or is async .
403
442
Classification classifyApply (ApplyExpr *E) {
404
443
// An apply expression is a potential throw site if the function throws.
405
444
// But if the expression didn't type-check, suppress diagnostics.
@@ -461,7 +500,8 @@ class ApplyClassifier {
461
500
if (!type) return Classification::forInvalidCode ();
462
501
463
502
// Use the most significant result from the arguments.
464
- Classification result;
503
+ Classification result = isAsync ? Classification::forAsync ()
504
+ : Classification ();
465
505
for (auto arg : llvm::reverse (args)) {
466
506
auto fnType = type->getAs <AnyFunctionType>();
467
507
if (!fnType) return Classification::forInvalidCode ();
@@ -527,7 +567,7 @@ class ApplyClassifier {
527
567
// If we're currently doing rethrows-checking on the body of the
528
568
// function which declares the parameter, it's rethrowing-only.
529
569
if (param->getDeclContext () == RethrowsDC)
530
- return Classification::forRethrowingOnly (reason);
570
+ return Classification::forRethrowingOnly (reason, /* async */ false );
531
571
532
572
// Otherwise, it throws unconditionally.
533
573
return Classification::forThrow (reason, /* async*/ false );
@@ -1235,8 +1275,12 @@ class Context {
1235
1275
highlight = apply->getSourceRange ();
1236
1276
1237
1277
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 ()))
1239
1282
diag = diag::async_call_without_await_in_autoclosure;
1283
+
1240
1284
ctx.Diags .diagnose (node.getStartLoc (), diag)
1241
1285
.fixItInsert (node.getStartLoc (), " await " )
1242
1286
.highlight (highlight);
@@ -1464,6 +1508,10 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
1464
1508
OldMaxThrowingKind = std::max (OldMaxThrowingKind, Self.MaxThrowingKind );
1465
1509
}
1466
1510
1511
+ void preserveCoverageFromOptionalOrForcedTryOperand () {
1512
+ OldFlags.mergeFrom (ContextFlags::asyncAwaitFlags (), Self.Flags );
1513
+ }
1514
+
1467
1515
void preserveCoverageFromInterpolatedString () {
1468
1516
OldFlags.mergeFrom (ContextFlags::HasAnyThrowSite, Self.Flags );
1469
1517
OldFlags.mergeFrom (ContextFlags::HasTryThrowSite, Self.Flags );
@@ -1808,6 +1856,8 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
1808
1856
if (!Flags.has (ContextFlags::HasTryThrowSite)) {
1809
1857
Ctx.Diags .diagnose (E->getLoc (), diag::no_throw_in_try);
1810
1858
}
1859
+
1860
+ scope.preserveCoverageFromOptionalOrForcedTryOperand ();
1811
1861
return ShouldNotRecurse;
1812
1862
}
1813
1863
@@ -1822,6 +1872,8 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
1822
1872
if (!Flags.has (ContextFlags::HasTryThrowSite)) {
1823
1873
Ctx.Diags .diagnose (E->getLoc (), diag::no_throw_in_try);
1824
1874
}
1875
+
1876
+ scope.preserveCoverageFromOptionalOrForcedTryOperand ();
1825
1877
return ShouldNotRecurse;
1826
1878
}
1827
1879
};
0 commit comments