@@ -1266,21 +1266,9 @@ namespace {
1266
1266
}
1267
1267
}
1268
1268
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 ;
1275
1269
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);
1284
1272
1285
1273
// The children of #selector expressions are not evaluated, so we do not
1286
1274
// need to do isolation checking there. This is convenient because such
@@ -1868,6 +1856,89 @@ namespace {
1868
1856
return true ;
1869
1857
}
1870
1858
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
+
1871
1942
// / Check a reference to a local or global.
1872
1943
bool checkNonMemberReference (
1873
1944
ConcreteDeclRef valueRef, SourceLoc loc, DeclRefExpr *declRefExpr) {
0 commit comments