@@ -1266,21 +1266,9 @@ namespace {
12661266 }
12671267 }
12681268
1269- // Key paths require any captured values to be ConcurrentValue-conforming.
1270- if (auto keyPath = dyn_cast<KeyPathExpr>(expr)) {
1271- for (const auto &component : keyPath->getComponents ()) {
1272- auto indexExpr = component.getIndexExpr ();
1273- if (!indexExpr || !indexExpr->getType ())
1274- continue ;
12751269
1276- if (shouldDiagnoseNonConcurrentValueViolations (ctx.LangOpts ) &&
1277- !isConcurrentValueType (getDeclContext (), indexExpr->getType ())) {
1278- ctx.Diags .diagnose (
1279- component.getLoc (), diag::non_concurrent_keypath_capture,
1280- indexExpr->getType ());
1281- }
1282- }
1283- }
1270+ if (auto keyPath = dyn_cast<KeyPathExpr>(expr))
1271+ checkKeyPathExpr (keyPath);
12841272
12851273 // The children of #selector expressions are not evaluated, so we do not
12861274 // need to do isolation checking there. This is convenient because such
@@ -1868,6 +1856,89 @@ namespace {
18681856 return true ;
18691857 }
18701858
1859+ // /
1860+ // / \return true iff a diagnostic was emitted
1861+ bool checkKeyPathExpr (KeyPathExpr *keyPath) {
1862+ bool diagnosed = false ;
1863+
1864+ // returns None if it is not a 'let'-bound var decl. Otherwise,
1865+ // the bool indicates whether a diagnostic was emitted.
1866+ auto checkLetBoundVarDecl = [&](KeyPathExpr::Component const & component)
1867+ -> Optional<bool > {
1868+ auto decl = component.getDeclRef ().getDecl ();
1869+ if (auto varDecl = dyn_cast<VarDecl>(decl)) {
1870+ if (varDecl->isLet ()) {
1871+ auto type = component.getComponentType ();
1872+ if (shouldDiagnoseNonConcurrentValueViolations (ctx.LangOpts )
1873+ && !isConcurrentValueType (getDeclContext (), type)) {
1874+ ctx.Diags .diagnose (
1875+ component.getLoc (), diag::non_concurrent_keypath_access,
1876+ type);
1877+ return true ;
1878+ }
1879+ return false ;
1880+ }
1881+ }
1882+ return None;
1883+ };
1884+
1885+ // check the components of the keypath.
1886+ for (const auto &component : keyPath->getComponents ()) {
1887+ // The decl referred to by the path component cannot be within an actor.
1888+ if (component.hasDeclRef ()) {
1889+ auto concDecl = component.getDeclRef ();
1890+ auto isolation = ActorIsolationRestriction::forDeclaration (concDecl);
1891+
1892+ switch (isolation.getKind ()) {
1893+ case ActorIsolationRestriction::Unsafe:
1894+ case ActorIsolationRestriction::Unrestricted:
1895+ break ; // OK. Does not refer to an actor-isolated member.
1896+
1897+ case ActorIsolationRestriction::GlobalActorUnsafe:
1898+ // Only check if we're in code that's adopted concurrency features.
1899+ if (!shouldDiagnoseExistingDataRaces (getDeclContext ()))
1900+ break ; // do not check
1901+
1902+ LLVM_FALLTHROUGH; // otherwise, perform checking
1903+
1904+ case ActorIsolationRestriction::GlobalActor:
1905+ case ActorIsolationRestriction::CrossActorSelf:
1906+ // 'let'-bound decls with this isolation are OK, just check them.
1907+ if (auto wasLetBound = checkLetBoundVarDecl (component)) {
1908+ diagnosed = wasLetBound.getValue ();
1909+ break ;
1910+ }
1911+ LLVM_FALLTHROUGH; // otherwise, it's invalid so diagnose it.
1912+
1913+ case ActorIsolationRestriction::ActorSelf: {
1914+ auto decl = concDecl.getDecl ();
1915+ ctx.Diags .diagnose (component.getLoc (),
1916+ diag::actor_isolated_keypath_component,
1917+ decl->getDescriptiveKind (), decl->getName ());
1918+ diagnosed = true ;
1919+ break ;
1920+ }
1921+ }; // end switch
1922+ }
1923+
1924+ // Captured values in a path component must conform to ConcurrentValue.
1925+ // These captured values appear in Subscript, aka "index" components,
1926+ // such as \Type.dict[k] where k is a captured dictionary key.
1927+ if (auto indexExpr = component.getIndexExpr ()) {
1928+ auto type = indexExpr->getType ();
1929+ if (type && shouldDiagnoseNonConcurrentValueViolations (ctx.LangOpts )
1930+ && !isConcurrentValueType (getDeclContext (), type)) {
1931+ ctx.Diags .diagnose (
1932+ component.getLoc (), diag::non_concurrent_keypath_capture,
1933+ indexExpr->getType ());
1934+ diagnosed = true ;
1935+ }
1936+ }
1937+ }
1938+
1939+ return diagnosed;
1940+ }
1941+
18711942 // / Check a reference to a local or global.
18721943 bool checkNonMemberReference (
18731944 ConcreteDeclRef valueRef, SourceLoc loc, DeclRefExpr *declRefExpr) {
0 commit comments