@@ -422,87 +422,11 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
422422 }
423423
424424 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);
506430 }
507431
508432 void checkCopyExpr (CopyExpr *copyExpr) {
@@ -1521,6 +1445,82 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
15211445 }
15221446}
15231447
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+
15241524
15251525// / Diagnose recursive use of properties within their own accessors
15261526static void diagRecursivePropertyAccess (const Expr *E, const DeclContext *DC) {
@@ -6723,3 +6723,9 @@ bool swift::diagnoseUnhandledThrowsInAsyncContext(DeclContext *dc,
67236723
67246724 return false ;
67256725}
6726+
6727+ void DeferredDiag::emit (swift::ASTContext &ctx) {
6728+ assert (loc && " no loc... already emitted?" );
6729+ ctx.Diags .diagnose (loc, diag);
6730+ loc = SourceLoc ();
6731+ }
0 commit comments