@@ -422,87 +422,11 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
422
422
}
423
423
424
424
void checkConsumeExpr (ConsumeExpr *consumeExpr) {
425
- auto *subExpr = consumeExpr->getSubExpr ();
426
- bool noncopyable =
427
- subExpr->getType ()->getCanonicalType ()->isNoncopyable ();
428
-
429
- bool partial = false ;
430
- Expr *current = subExpr;
431
- while (current) {
432
- if (auto *dre = dyn_cast<DeclRefExpr>(current)) {
433
- if (partial & !noncopyable) {
434
- Ctx.Diags .diagnose (consumeExpr->getLoc (),
435
- diag::consume_expression_partial_copyable);
436
- return ;
437
- }
438
- // The chain of member_ref_exprs and load_exprs terminates at a
439
- // declref_expr. This is legal.
440
- return ;
441
- }
442
- // Look through loads.
443
- if (auto *le = dyn_cast<LoadExpr>(current)) {
444
- current = le->getSubExpr ();
445
- continue ;
446
- }
447
- auto *mre = dyn_cast<MemberRefExpr>(current);
448
- if (mre) {
449
- auto *vd = dyn_cast<VarDecl>(mre->getMember ().getDecl ());
450
- if (!vd) {
451
- Ctx.Diags .diagnose (consumeExpr->getLoc (),
452
- diag::consume_expression_non_storage);
453
- return ;
454
- }
455
- partial = true ;
456
- AccessStrategy strategy = vd->getAccessStrategy (
457
- mre->getAccessSemantics (), AccessKind::Read,
458
- DC->getParentModule (), ResilienceExpansion::Minimal);
459
- if (strategy.getKind () != AccessStrategy::Storage) {
460
- if (noncopyable) {
461
- Ctx.Diags .diagnose (consumeExpr->getLoc (),
462
- diag::consume_expression_non_storage);
463
- Ctx.Diags .diagnose (
464
- mre->getLoc (),
465
- diag::note_consume_expression_non_storage_property);
466
- } else {
467
- Ctx.Diags .diagnose (consumeExpr->getLoc (),
468
- diag::consume_expression_partial_copyable);
469
- }
470
- return ;
471
- }
472
- current = mre->getBase ();
473
- continue ;
474
- }
475
- auto *ce = dyn_cast<CallExpr>(current);
476
- if (ce) {
477
- if (noncopyable) {
478
- Ctx.Diags .diagnose (consumeExpr->getLoc (),
479
- diag::consume_expression_non_storage);
480
- Ctx.Diags .diagnose (ce->getLoc (),
481
- diag::note_consume_expression_non_storage_call);
482
- } else {
483
- Ctx.Diags .diagnose (consumeExpr->getLoc (),
484
- diag::consume_expression_partial_copyable);
485
- }
486
- return ;
487
- }
488
- auto *se = dyn_cast<SubscriptExpr>(current);
489
- if (se) {
490
- if (noncopyable) {
491
- Ctx.Diags .diagnose (consumeExpr->getLoc (),
492
- diag::consume_expression_non_storage);
493
- Ctx.Diags .diagnose (
494
- se->getLoc (),
495
- diag::note_consume_expression_non_storage_subscript);
496
- } else {
497
- Ctx.Diags .diagnose (consumeExpr->getLoc (),
498
- diag::consume_expression_partial_copyable);
499
- }
500
- return ;
501
- }
502
- Ctx.Diags .diagnose (consumeExpr->getLoc (),
503
- diag::consume_expression_not_passed_lvalue);
504
- return ;
505
- }
425
+ auto diags = findSyntacticErrorForConsume (DC->getParentModule (),
426
+ consumeExpr->getLoc (),
427
+ consumeExpr->getSubExpr ());
428
+ for (auto &diag : diags)
429
+ diag.emit (Ctx);
506
430
}
507
431
508
432
void checkCopyExpr (CopyExpr *copyExpr) {
@@ -1521,6 +1445,82 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
1521
1445
}
1522
1446
}
1523
1447
1448
+ DeferredDiags swift::findSyntacticErrorForConsume (
1449
+ ModuleDecl *module , SourceLoc loc, Expr *subExpr) {
1450
+ assert (!isa<ConsumeExpr>(subExpr) && " operates on the sub-expr of a consume" );
1451
+
1452
+ DeferredDiags result;
1453
+ const bool noncopyable =
1454
+ subExpr->getType ()->getCanonicalType ()->isNoncopyable ();
1455
+
1456
+ bool partial = false ;
1457
+ Expr *current = subExpr;
1458
+ while (current) {
1459
+ if (auto *dre = dyn_cast<DeclRefExpr>(current)) {
1460
+ if (partial & !noncopyable)
1461
+ result.emplace_back (loc, diag::consume_expression_partial_copyable);
1462
+
1463
+ // The chain of member_ref_exprs and load_exprs terminates at a
1464
+ // declref_expr. This is legal.
1465
+ break ;
1466
+ }
1467
+ // Look through loads.
1468
+ if (auto *le = dyn_cast<LoadExpr>(current)) {
1469
+ current = le->getSubExpr ();
1470
+ continue ;
1471
+ }
1472
+ auto *mre = dyn_cast<MemberRefExpr>(current);
1473
+ if (mre) {
1474
+ auto *vd = dyn_cast<VarDecl>(mre->getMember ().getDecl ());
1475
+ if (!vd) {
1476
+ result.emplace_back (loc, diag::consume_expression_non_storage);
1477
+ break ;
1478
+ }
1479
+ partial = true ;
1480
+ AccessStrategy strategy = vd->getAccessStrategy (
1481
+ mre->getAccessSemantics (), AccessKind::Read,
1482
+ module , ResilienceExpansion::Minimal);
1483
+ if (strategy.getKind () != AccessStrategy::Storage) {
1484
+ if (noncopyable) {
1485
+ result.emplace_back (loc, diag::consume_expression_non_storage);
1486
+ result.emplace_back (mre->getLoc (),
1487
+ diag::note_consume_expression_non_storage_property);
1488
+ break ;
1489
+ }
1490
+ result.emplace_back (loc, diag::consume_expression_partial_copyable);
1491
+ break ;
1492
+ }
1493
+ current = mre->getBase ();
1494
+ continue ;
1495
+ }
1496
+ auto *ce = dyn_cast<CallExpr>(current);
1497
+ if (ce) {
1498
+ if (noncopyable) {
1499
+ result.emplace_back (loc, diag::consume_expression_non_storage);
1500
+ result.emplace_back (ce->getLoc (),
1501
+ diag::note_consume_expression_non_storage_call);
1502
+ break ;
1503
+ }
1504
+ result.emplace_back (loc, diag::consume_expression_partial_copyable);
1505
+ break ;
1506
+ }
1507
+ auto *se = dyn_cast<SubscriptExpr>(current);
1508
+ if (se) {
1509
+ if (noncopyable) {
1510
+ result.emplace_back (loc, diag::consume_expression_non_storage);
1511
+ result.emplace_back (se->getLoc (),
1512
+ diag::note_consume_expression_non_storage_subscript);
1513
+ break ;
1514
+ }
1515
+ result.emplace_back (loc, diag::consume_expression_partial_copyable);
1516
+ break ;
1517
+ }
1518
+ result.emplace_back (loc, diag::consume_expression_not_passed_lvalue);
1519
+ break ;
1520
+ }
1521
+ return result;
1522
+ }
1523
+
1524
1524
1525
1525
// / Diagnose recursive use of properties within their own accessors
1526
1526
static void diagRecursivePropertyAccess (const Expr *E, const DeclContext *DC) {
@@ -6722,3 +6722,9 @@ bool swift::diagnoseUnhandledThrowsInAsyncContext(DeclContext *dc,
6722
6722
6723
6723
return false ;
6724
6724
}
6725
+
6726
+ void DeferredDiag::emit (swift::ASTContext &ctx) {
6727
+ assert (loc && " no loc... already emitted?" );
6728
+ ctx.Diags .diagnose (loc, diag);
6729
+ loc = SourceLoc ();
6730
+ }
0 commit comments