aaronpuchert created this revision.
aaronpuchert added a reviewer: aaron.ballman.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
aaronpuchert requested review of this revision.

Public members are always in scope, protected members in derived classes
with sufficient access.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D87194

Files:
  clang/lib/Analysis/ThreadSafety.cpp
  clang/test/SemaCXX/warn-thread-safety-negative.cpp

Index: clang/test/SemaCXX/warn-thread-safety-negative.cpp
===================================================================
--- clang/test/SemaCXX/warn-thread-safety-negative.cpp
+++ clang/test/SemaCXX/warn-thread-safety-negative.cpp
@@ -108,6 +108,54 @@
   ns::fq(); // expected-warning {{calling function 'fq' requires negative capability '!globalMutex'}}
 }
 
+class Base {
+public:
+  void nopub() EXCLUSIVE_LOCKS_REQUIRED(!pub);
+  void noprot() EXCLUSIVE_LOCKS_REQUIRED(!prot);
+  void nopriv() EXCLUSIVE_LOCKS_REQUIRED(!priv);
+
+  void inClass() {
+    nopub();  // expected-warning {{calling function 'nopub' requires negative capability '!pub'}}
+    noprot(); // expected-warning {{calling function 'noprot' requires negative capability '!prot'}}
+    nopriv(); // expected-warning {{calling function 'nopriv' requires negative capability '!priv'}}
+  }
+
+  Mutex pub;
+
+protected:
+  Mutex prot;
+
+private:
+  Mutex priv;
+};
+
+class Derived : private Base {
+public:
+  void nopubDerived() EXCLUSIVE_LOCKS_REQUIRED(!pub);
+  void noprotDerived() EXCLUSIVE_LOCKS_REQUIRED(!prot);
+
+  void inDerivedClass() {
+    nopub();  // expected-warning {{calling function 'nopub' requires negative capability '!pub'}}
+    noprot(); // expected-warning {{calling function 'noprot' requires negative capability '!prot'}}
+    nopriv();
+  }
+};
+
+class MoreDerived : public Derived {
+public:
+  void inDerivedClassWithInacessibleBase() {
+    nopubDerived(); // expected-warning {{calling function 'nopubDerived' requires negative capability '!pub'}}
+    noprotDerived();
+  }
+};
+
+void outside() {
+  Base x;
+  x.nopub(); // expected-warning {{calling function 'nopub' requires negative capability '!x.pub'}}
+  x.noprot();
+  x.nopriv();
+}
+
 }  // end namespace ScopeTest
 
 namespace DoubleAttribute {
Index: clang/lib/Analysis/ThreadSafety.cpp
===================================================================
--- clang/lib/Analysis/ThreadSafety.cpp
+++ clang/lib/Analysis/ThreadSafety.cpp
@@ -16,6 +16,7 @@
 
 #include "clang/Analysis/Analyses/ThreadSafety.h"
 #include "clang/AST/Attr.h"
+#include "clang/AST/CXXInheritance.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclGroup.h"
@@ -1275,10 +1276,28 @@
 
   // Members are in scope from methods of the same class.
   if (const auto *P = dyn_cast<til::Project>(SExp)) {
+    const ValueDecl *VD = P->clangDecl();
+    // Public members are always accessible.
+    if (VD->getAccess() == AS_public)
+      return true;
+    // We are ignoring friends here.
     if (!CurrentMethod)
       return false;
-    const ValueDecl *VD = P->clangDecl();
-    return VD->getDeclContext() == CurrentMethod->getDeclContext();
+    const auto *CapRecord = cast<CXXRecordDecl>(VD->getDeclContext()),
+               *MethodRecord =
+                   cast<CXXRecordDecl>(CurrentMethod->getDeclContext());
+    // If we're in the same record, all members are accessible.
+    if (CapRecord == MethodRecord)
+      return true;
+    // Additionally in derived classes, protected members are accessible.
+    if (VD->getAccess() == AS_protected) {
+      CXXBasePaths Paths;
+      if (!MethodRecord->isDerivedFrom(CapRecord, Paths))
+        return false;
+      for (const CXXBasePath &Path : Paths)
+        if (Path.Access != AS_none)
+          return true;
+    }
   }
 
   return false;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to