@@ -637,42 +637,6 @@ static bool isAsyncCall(const ApplyExpr *call) {
637
637
return funcType->isAsync ();
638
638
}
639
639
640
- // / Extract the correct expression for diagnosing actor state being passed inout
641
- // /
642
- // / This unwraps most expression types, working toward an offending DeclRefExpr
643
- // / or to the LookupExpr before the DeclRef.
644
- // /
645
- // / The return will either be a LookupExpr or a DeclRefExpr.
646
- // / If part of the sub-expression isn't interesting, returns nullptr
647
- static const Expr *getInoutTopExpr (const InOutExpr *arg) {
648
- const Expr * currentExpr = arg->getSubExpr ();
649
- while (currentExpr) {
650
- if (const InOutExpr *inout = dyn_cast<InOutExpr>(currentExpr)) {
651
- return nullptr ; // The AST walker will hit this again
652
- } else if (const LookupExpr *baseArg = dyn_cast<LookupExpr>(currentExpr)) {
653
- if (isa<DeclRefExpr>(baseArg->getBase ()))
654
- return baseArg;
655
- currentExpr = baseArg->getBase ();
656
- } else if (const DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(currentExpr))
657
- return declRef;
658
- else if (const BindOptionalExpr *bindingOp =
659
- dyn_cast<BindOptionalExpr>(currentExpr))
660
- currentExpr = bindingOp->getSubExpr ();
661
- else if (const ForceValueExpr *forceOp =
662
- dyn_cast<ForceValueExpr>(currentExpr))
663
- currentExpr = forceOp->getSubExpr ();
664
- else if (const ImplicitConversionExpr *convExpr =
665
- dyn_cast<ImplicitConversionExpr>(currentExpr))
666
- currentExpr = convExpr->getSubExpr ();
667
- else if (const IdentityExpr *identExpr =
668
- dyn_cast<IdentityExpr>(currentExpr))
669
- currentExpr = identExpr->getSubExpr ();
670
- else
671
- return currentExpr;
672
- }
673
- llvm_unreachable (" The current expression is a nullptr!" );
674
- }
675
-
676
640
// / Determine whether we should diagnose data races within the current context.
677
641
// /
678
642
// / By default, we do this only in code that makes use of concurrency
@@ -998,55 +962,65 @@ namespace {
998
962
if (!isAsyncCall (call))
999
963
return false ;
1000
964
1001
- const Expr *subArg = getInoutTopExpr (arg);
1002
- if (subArg == nullptr ) // Subexpression isn't interesting
1003
- return false ;
1004
- ValueDecl *valueDecl = nullptr ;
1005
- if (const DeclRefExpr *declExpr = dyn_cast<DeclRefExpr>(subArg))
1006
- valueDecl = declExpr->getDecl ();
1007
- else if (const LookupExpr * member = dyn_cast<LookupExpr>(subArg))
1008
- valueDecl = member->getMember ().getDecl ();
1009
- else
1010
- llvm_unreachable (" Unhandled expression type" );
1011
- auto isolation = ActorIsolationRestriction::forDeclaration (valueDecl);
1012
- switch (isolation) {
1013
- case ActorIsolationRestriction::Unrestricted:
1014
- case ActorIsolationRestriction::LocalCapture:
1015
- case ActorIsolationRestriction::Unsafe:
1016
- break ;
1017
- case ActorIsolationRestriction::GlobalActor: {
1018
- ctx.Diags .diagnose (call->getLoc (),
1019
- diag::actor_isolated_inout_state,
1020
- valueDecl->getDescriptiveKind (),
1021
- valueDecl->getName (),
1022
- call->implicitlyAsync ());
1023
- valueDecl->diagnose (diag::kind_declared_here,
1024
- valueDecl->getDescriptiveKind ());
1025
- return true ;
1026
- }
1027
- case ActorIsolationRestriction::ActorSelf: {
1028
- if (isPartialApply) {
1029
- // The partially applied InoutArg is a property of actor. This can
1030
- // really only happen when the property is a struct with a mutating
1031
- // async method.
1032
- if (auto partialApply = dyn_cast<ApplyExpr>(call->getFn ())) {
1033
- ValueDecl *fnDecl =
1034
- cast<DeclRefExpr>(partialApply->getFn ())->getDecl ();
1035
- ctx.Diags .diagnose (
1036
- call->getLoc (), diag::actor_isolated_mutating_func,
1037
- fnDecl->getName (), valueDecl->getDescriptiveKind (),
1038
- valueDecl->getName ());
1039
- return true ;
965
+ bool result = false ;
966
+ auto checkDiagnostic = [this , call, isPartialApply,
967
+ &result](ValueDecl *decl, SourceLoc argLoc) {
968
+ auto isolation = ActorIsolationRestriction::forDeclaration (decl);
969
+ switch (isolation) {
970
+ case ActorIsolationRestriction::Unrestricted:
971
+ case ActorIsolationRestriction::LocalCapture:
972
+ case ActorIsolationRestriction::Unsafe:
973
+ break ;
974
+ case ActorIsolationRestriction::GlobalActor: {
975
+ ctx.Diags .diagnose (argLoc, diag::actor_isolated_inout_state,
976
+ decl->getDescriptiveKind (), decl->getName (),
977
+ call->implicitlyAsync ());
978
+ decl->diagnose (diag::kind_declared_here, decl->getDescriptiveKind ());
979
+ result = true ;
980
+ break ;
981
+ }
982
+ case ActorIsolationRestriction::ActorSelf: {
983
+ if (isPartialApply) {
984
+ // The partially applied InoutArg is a property of actor. This
985
+ // can really only happen when the property is a struct with a
986
+ // mutating async method.
987
+ if (auto partialApply = dyn_cast<ApplyExpr>(call->getFn ())) {
988
+ ValueDecl *fnDecl =
989
+ cast<DeclRefExpr>(partialApply->getFn ())->getDecl ();
990
+ ctx.Diags .diagnose (call->getLoc (),
991
+ diag::actor_isolated_mutating_func,
992
+ fnDecl->getName (), decl->getDescriptiveKind (),
993
+ decl->getName ());
994
+ result = true ;
995
+ }
996
+ } else {
997
+ ctx.Diags .diagnose (argLoc, diag::actor_isolated_inout_state,
998
+ decl->getDescriptiveKind (), decl->getName (),
999
+ call->implicitlyAsync ());
1000
+ result = true ;
1040
1001
}
1041
- } else {
1042
- ctx.Diags .diagnose (
1043
- subArg->getLoc (), diag::actor_isolated_inout_state,
1044
- valueDecl->getDescriptiveKind (), valueDecl->getName (), call->implicitlyAsync ());
1045
- return true ;
1002
+ break ;
1046
1003
}
1047
- }
1048
- }
1049
- return false ;
1004
+ }
1005
+ };
1006
+ auto expressionWalker = [baseArg = arg->getSubExpr (),
1007
+ checkDiagnostic](Expr *expr) -> Expr * {
1008
+ if (isa<InOutExpr>(expr))
1009
+ return nullptr ; // AST walker will hit this again
1010
+ if (LookupExpr *lookup = dyn_cast<LookupExpr>(expr)) {
1011
+ if (isa<DeclRefExpr>(lookup->getBase ())) {
1012
+ checkDiagnostic (lookup->getMember ().getDecl (), baseArg->getLoc ());
1013
+ return nullptr ; // Diagnosed. Don't keep walking
1014
+ }
1015
+ }
1016
+ if (DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(expr)) {
1017
+ checkDiagnostic (declRef->getDecl (), baseArg->getLoc ());
1018
+ return nullptr ; // Diagnosed. Don't keep walking
1019
+ }
1020
+ return expr;
1021
+ };
1022
+ arg->getSubExpr ()->forEachChildExpr (expressionWalker);
1023
+ return result;
1050
1024
}
1051
1025
1052
1026
// / Get the actor isolation of the innermost relevant context.
0 commit comments