From 6781b05a9254f3aaf53126368d23ebda88e02c96 Mon Sep 17 00:00:00 2001
From: John McCall <rjmccall@apple.com>
Date: Tue, 2 Feb 2010 08:45:54 +0000
Subject: [PATCH] Access control for implicit destructor calls.  Diagnostic
 could be orders of magnitude clearer.

llvm-svn: 95078
---
 clang/lib/Sema/Sema.h              |  1 +
 clang/lib/Sema/SemaAccess.cpp      | 25 +++++++++++++++++++++++++
 clang/lib/Sema/SemaChecking.cpp    |  3 +++
 clang/lib/Sema/SemaDeclCXX.cpp     |  9 +++++----
 clang/test/CXX/class.access/p4.cpp | 29 +++++++++++++++++++++++++++++
 5 files changed, 63 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 9e28b519ff36..e49ce7331987 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -2417,6 +2417,7 @@ public:
                                    AccessSpecifier Access);
   bool CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D,
                               AccessSpecifier Access);
+  bool CheckDestructorAccess(SourceLocation Loc, QualType T);
   bool CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr,
                                  NamedDecl *D, AccessSpecifier Access);
   bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access);
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index ceee61df23a1..98beb610a5ea 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -306,6 +306,31 @@ bool Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
   return false;
 }
 
+bool Sema::CheckDestructorAccess(SourceLocation Loc,
+                                 QualType T) {
+  if (!getLangOptions().AccessControl)
+    return false;
+
+  const RecordType *Record = T->getAs<RecordType>();
+  if (!Record)
+    return false;
+
+  CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Record->getDecl());
+  CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
+
+  AccessSpecifier Access = Dtor->getAccess();
+  if (Access == AS_public)
+    return false;
+
+  LookupResult R(*this, Dtor->getDeclName(), Loc, LookupOrdinaryName);
+  R.suppressDiagnostics();
+
+  R.setNamingClass(NamingClass);
+  return CheckAccess(R, Dtor, Access);
+
+  // FIXME: protected check
+}
+
 /// Checks access to a constructor.
 bool Sema::CheckConstructorAccess(SourceLocation UseLoc,
                                   CXXConstructorDecl *Constructor,
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index c6b826b32703..0d9918f6e43f 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2637,6 +2637,9 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
         Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
       }
     }
+
+    if (getLangOptions().AccessControl)
+      CheckDestructorAccess(Param->getLocation(), Param->getType());
   }
 
   return HasInvalidParm;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 745bd513a25a..931c058670bb 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -3985,10 +3985,11 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
 void Sema::FinalizeVarWithDestructor(VarDecl *VD, QualType DeclInitType) {
   CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(
                                   DeclInitType->getAs<RecordType>()->getDecl());
-  if (!ClassDecl->hasTrivialDestructor())
-    if (CXXDestructorDecl *Destructor =
-        const_cast<CXXDestructorDecl*>(ClassDecl->getDestructor(Context)))
-      MarkDeclarationReferenced(VD->getLocation(), Destructor);
+  if (!ClassDecl->hasTrivialDestructor()) {
+    CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
+    MarkDeclarationReferenced(VD->getLocation(), Destructor);
+    CheckDestructorAccess(VD->getLocation(), VD->getType());
+  }
 }
 
 /// AddCXXDirectInitializerToDecl - This action is called immediately after
diff --git a/clang/test/CXX/class.access/p4.cpp b/clang/test/CXX/class.access/p4.cpp
index 97c632a07251..83e467d9b963 100644
--- a/clang/test/CXX/class.access/p4.cpp
+++ b/clang/test/CXX/class.access/p4.cpp
@@ -83,3 +83,32 @@ namespace test1 {
     ca(priv); // expected-error {{access to private member}}
   }
 }
+
+// Implicit constructor calls.
+namespace test2 {
+  class A {
+  private:
+    A(); // expected-note {{declared private here}}
+
+    static A foo;
+  };
+
+  A a; // expected-error {{access to private member}}
+  A A::foo; // okay
+}
+
+// Implicit destructor calls.
+namespace test3 {
+  class A{
+  private:
+    ~A(); // expected-note 3 {{declared private here}}
+    static A foo;
+  };
+
+  A a; // expected-error {{access to private member}}
+  A A::foo;
+
+  void foo(A param) { // expected-error {{access to private member}}
+    A local; // expected-error {{access to private member}}
+  }
+}