[cfe-commits] r94268 - in /cfe/trunk: include/clang/AST/CXXInheritance.h include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/Specifiers.h lib/AST/CXXInheritance.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/Lookup.h lib/Sema/Sema.h lib/Sema/SemaAccess.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaLookup.cpp test/CXX/class.access/class.access.base/p1.cpp test/SemaCXX/access-control-check.cpp

John McCall rjmccall at apple.com
Fri Jan 22 16:46:33 PST 2010


Author: rjmccall
Date: Fri Jan 22 18:46:32 2010
New Revision: 94268

URL: http://llvm.org/viewvc/llvm-project?rev=94268&view=rev
Log:
Implement elementary access control.


Added:
    cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp
Modified:
    cfe/trunk/include/clang/AST/CXXInheritance.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/Specifiers.h
    cfe/trunk/lib/AST/CXXInheritance.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/Lookup.h
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaAccess.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/test/SemaCXX/access-control-check.cpp

Modified: cfe/trunk/include/clang/AST/CXXInheritance.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CXXInheritance.h?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/CXXInheritance.h (original)
+++ cfe/trunk/include/clang/AST/CXXInheritance.h Fri Jan 22 18:46:32 2010
@@ -65,12 +65,21 @@
 /// subobject is being used.
 class CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> {
 public:
-  /// \brief The access along this inheritance path.
+  CXXBasePath() : Access(AS_public) {}
+
+  /// \brief The access along this inheritance path.  This is only
+  /// calculated when recording paths.  AS_none is a special value
+  /// used to indicate a path which permits no legal access.
   AccessSpecifier Access;
 
   /// \brief The set of declarations found inside this base class
   /// subobject.
   DeclContext::lookup_result Decls;
+
+  void clear() {
+    llvm::SmallVectorImpl<CXXBasePathElement>::clear();
+    Access = AS_public;
+  }
 };
 
 /// BasePaths - Represents the set of paths from a derived class to
@@ -138,10 +147,6 @@
   /// to help build the set of paths.
   CXXBasePath ScratchPath;
 
-  /// ScratchAccess - A stack of accessibility annotations used by
-  /// Sema::lookupInBases.
-  llvm::SmallVector<AccessSpecifier, 4> ScratchAccess;
-  
   /// DetectedVirtual - The base class that is virtual.
   const RecordType *DetectedVirtual;
   

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Jan 22 18:46:32 2010
@@ -817,6 +817,15 @@
   /// GraphViz.
   void viewInheritance(ASTContext& Context) const;
 
+  /// MergeAccess - Calculates the access of a decl that is reached
+  /// along a path.
+  static AccessSpecifier MergeAccess(AccessSpecifier PathAccess,
+                                     AccessSpecifier DeclAccess) {
+    assert(DeclAccess != AS_none);
+    if (DeclAccess == AS_private) return AS_none;
+    return (PathAccess > DeclAccess ? PathAccess : DeclAccess);
+  }
+
   static bool classof(const Decl *D) {
     return D->getKind() == CXXRecord ||
            D->getKind() == ClassTemplateSpecialization ||

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jan 22 18:46:32 2010
@@ -412,6 +412,15 @@
   "%0 redeclared with '%1' access">;
 def note_previous_access_declaration : Note<
   "previously declared '%1' here">;
+def err_access_outside_class : Error<
+  "access to %select{private|protected}0 member outside any class context">;
+def note_access_natural : Note<"declared %select{private|protected}0 here">;
+def note_access_constrained_by_path : Note<
+  "access to decl constrained by %select{private|protected}0 inheritance">;
+def err_access_protected : Error<
+  "access to protected member of %0 from %1, which is not a subclass">;
+def err_access_private : Error<
+  "access to private member of %0 from %1">;
   
 // C++ name lookup
 def err_incomplete_nested_name_spec : Error<

Modified: cfe/trunk/include/clang/Basic/Specifiers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Specifiers.h?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/Specifiers.h (original)
+++ cfe/trunk/include/clang/Basic/Specifiers.h Fri Jan 22 18:46:32 2010
@@ -68,13 +68,14 @@
     bool ModeAttr : 1;
   };  
 
-  /// AccessSpecifier - A C++ access specifier (none, public, private,
-  /// protected).
+  /// AccessSpecifier - A C++ access specifier (public, private,
+  /// protected), plus the special value "none" which means
+  /// different things in different contexts.
   enum AccessSpecifier {
-    AS_none,
     AS_public,
     AS_protected,
-    AS_private
+    AS_private,
+    AS_none
   };
 }
 

Modified: cfe/trunk/lib/AST/CXXInheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CXXInheritance.cpp?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/lib/AST/CXXInheritance.cpp (original)
+++ cfe/trunk/lib/AST/CXXInheritance.cpp Fri Jan 22 18:46:32 2010
@@ -61,7 +61,6 @@
   Paths.clear();
   ClassSubobjects.clear();
   ScratchPath.clear();
-  ScratchAccess.clear();
   DetectedVirtual = 0;
 }
 
@@ -147,6 +146,10 @@
                                   CXXBasePaths &Paths) const {
   bool FoundPath = false;
 
+  // The access of the path down to this record.
+  AccessSpecifier AccessToHere = Paths.ScratchPath.Access;
+  bool IsFirstStep = Paths.ScratchPath.empty();
+
   ASTContext &Context = getASTContext();
   for (base_class_const_iterator BaseSpec = bases_begin(),
          BaseSpecEnd = bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) {
@@ -191,20 +194,30 @@
         Element.SubobjectNumber = Subobjects.second;
       Paths.ScratchPath.push_back(Element);
 
-      // C++0x [class.access.base]p1 (paraphrased):
-      //   The access of a member of a base class is the less permissive
-      //   of its access within the base class and the access of the base
-      //   class within the derived class.
-      // We're just calculating the access along the path, so we ignore
-      // the access specifiers of whatever decls we've found.
-      AccessSpecifier PathAccess = Paths.ScratchPath.Access;
-      Paths.ScratchAccess.push_back(PathAccess);
-      Paths.ScratchPath.Access
-        = std::max(PathAccess, BaseSpec->getAccessSpecifier());
+      // Calculate the "top-down" access to this base class.
+      // The spec actually describes this bottom-up, but top-down is
+      // equivalent because the definition works out as follows:
+      // 1. Write down the access along each step in the inheritance
+      //    chain, followed by the access of the decl itself.
+      //    For example, in
+      //      class A { public: int foo; };
+      //      class B : protected A {};
+      //      class C : public B {};
+      //      class D : private C {};
+      //    we would write:
+      //      private public protected public
+      // 2. If 'private' appears anywhere except far-left, access is denied.
+      // 3. Otherwise, overall access is determined by the most restrictive
+      //    access in the sequence.
+      if (IsFirstStep)
+        Paths.ScratchPath.Access = BaseSpec->getAccessSpecifier();
+      else
+        Paths.ScratchPath.Access
+          = MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier());
     }
         
     if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) {
-      // We've found a path that terminates that this base.
+      // We've found a path that terminates at this base.
       FoundPath = true;
       if (Paths.isRecordingPaths()) {
         // We have a path. Make a copy of it before moving on.
@@ -237,8 +250,6 @@
     // collecting paths).
     if (Paths.isRecordingPaths()) {
       Paths.ScratchPath.pop_back();
-      Paths.ScratchPath.Access = Paths.ScratchAccess.back();
-      Paths.ScratchAccess.pop_back();
     }
 
     // If we set a virtual earlier, and this isn't a path, forget it again.
@@ -246,6 +257,9 @@
       Paths.DetectedVirtual = 0;
     }
   }
+
+  // Reset the scratch path access.
+  Paths.ScratchPath.Access = AccessToHere;
   
   return FoundPath;
 }

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Fri Jan 22 18:46:32 2010
@@ -983,7 +983,7 @@
 
   // Parse an (optional) access specifier.
   AccessSpecifier Access = getAccessSpecifierIfPresent();
-  if (Access)
+  if (Access != AS_none)
     ConsumeToken();
 
   // Parse the 'virtual' keyword (again!), in case it came after the

Modified: cfe/trunk/lib/Sema/Lookup.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Lookup.h?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Lookup.h (original)
+++ cfe/trunk/lib/Sema/Lookup.h Fri Jan 22 18:46:32 2010
@@ -131,6 +131,7 @@
                Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration)
     : ResultKind(NotFound),
       Paths(0),
+      NamingClass(0),
       SemaRef(SemaRef),
       Name(Name),
       NameLoc(NameLoc),
@@ -150,6 +151,7 @@
   LookupResult(TemporaryToken _, const LookupResult &Other)
     : ResultKind(NotFound),
       Paths(0),
+      NamingClass(0),
       SemaRef(Other.SemaRef),
       Name(Other.Name),
       NameLoc(Other.NameLoc),
@@ -245,6 +247,37 @@
     return IDNS;
   }
 
+  /// \brief Returns whether these results arose from performing a
+  /// lookup into a class.
+  bool isClassLookup() const {
+    return NamingClass != 0;
+  }
+
+  /// \brief Returns the 'naming class' for this lookup, i.e. the
+  /// class which was looked into to find these results.
+  ///
+  /// C++0x [class.access.base]p5:
+  ///   The access to a member is affected by the class in which the
+  ///   member is named. This naming class is the class in which the
+  ///   member name was looked up and found. [Note: this class can be
+  ///   explicit, e.g., when a qualified-id is used, or implicit,
+  ///   e.g., when a class member access operator (5.2.5) is used
+  ///   (including cases where an implicit "this->" is added). If both
+  ///   a class member access operator and a qualified-id are used to
+  ///   name the member (as in p->T::m), the class naming the member
+  ///   is the class named by the nested-name-specifier of the
+  ///   qualified-id (that is, T). -- end note ]
+  ///
+  /// This is set by the lookup routines when they find results in a class.
+  CXXRecordDecl *getNamingClass() const {
+    return NamingClass;
+  }
+
+  /// \brief Sets the 'naming class' for this lookup.
+  void setNamingClass(CXXRecordDecl *Record) {
+    NamingClass = Record;
+  }
+
   /// \brief Add a declaration to these results with its natural access.
   /// Does not test the acceptance criteria.
   void addDecl(NamedDecl *D) {
@@ -465,6 +498,8 @@
   void diagnose() {
     if (isAmbiguous())
       SemaRef.DiagnoseAmbiguousLookup(*this);
+    else if (isClassLookup() && SemaRef.getLangOptions().AccessControl)
+      SemaRef.CheckAccess(*this);
   }
 
   void setAmbiguous(AmbiguityKind AK) {
@@ -504,6 +539,7 @@
   AmbiguityKind Ambiguity; // ill-defined unless ambiguous
   UnresolvedSet<8> Decls;
   CXXBasePaths *Paths;
+  CXXRecordDecl *NamingClass;
 
   // Parameters.
   Sema &SemaRef;

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Jan 22 18:46:32 2010
@@ -2361,6 +2361,9 @@
                                                CXXBasePaths &Paths,
                                                bool NoPrivileges = false);
 
+  void CheckAccess(const LookupResult &R);
+  bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access);
+
   bool CheckBaseClassAccess(QualType Derived, QualType Base,
                             unsigned InaccessibleBaseID,
                             CXXBasePaths& Paths, SourceLocation AccessLoc,

Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Fri Jan 22 18:46:32 2010
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Sema.h"
+#include "Lookup.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclCXX.h"
@@ -137,3 +138,101 @@
 
   return false;
 }
+
+/// Diagnose the path which caused the given declaration to become
+/// inaccessible.
+static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D,
+                               AccessSpecifier Access) {
+  // Easy case: the decl's natural access determined its path access.
+  if (Access == D->getAccess() || D->getAccess() == AS_private) {
+    S.Diag(D->getLocation(), diag::note_access_natural)
+      << (unsigned) (Access == AS_protected);
+    return;
+  }
+
+  // TODO: flesh this out
+  S.Diag(D->getLocation(), diag::note_access_constrained_by_path)
+    << (unsigned) (Access == AS_protected);
+}
+
+/// Checks access to the given declaration in the current context.
+///
+/// \param R the means via which the access was made; must have a naming
+///   class set
+/// \param D the declaration accessed
+/// \param Access the best access along any inheritance path from the
+///   naming class to the declaration.  AS_none means the path is impossible
+bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D,
+                       AccessSpecifier Access) {
+  assert(R.getNamingClass() && "performing access check without naming class");
+
+  // If the access path is public, it's accessible everywhere.
+  if (Access == AS_public)
+    return false;
+
+  // Otherwise, derive the current class context.
+  DeclContext *DC = CurContext;
+  while (isa<CXXRecordDecl>(DC) &&
+         cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion())
+    DC = DC->getParent();
+
+  CXXRecordDecl *CurRecord;
+  if (isa<CXXRecordDecl>(DC))
+    CurRecord = cast<CXXRecordDecl>(DC);
+  else if (isa<CXXMethodDecl>(DC))
+    CurRecord = cast<CXXMethodDecl>(DC)->getParent();
+  else {
+    Diag(R.getNameLoc(), diag::err_access_outside_class)
+      << (Access == AS_protected);
+    DiagnoseAccessPath(*this, R, D, Access);
+    return true;
+  }
+
+  CXXRecordDecl *NamingClass = R.getNamingClass();
+  while (NamingClass->isAnonymousStructOrUnion())
+    // This should be guaranteed by the fact that the decl has
+    // non-public access.  If not, we should make it guaranteed!
+    NamingClass = cast<CXXRecordDecl>(NamingClass);
+
+  // White-list accesses from within the declaring class.
+  if (Access != AS_none &&
+      CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl())
+    return false;
+
+  // Protected access.
+  if (Access == AS_protected) {
+    // FIXME: implement [class.protected]p1
+    if (CurRecord->isDerivedFrom(NamingClass))
+      return false;
+
+    // FIXME: dependent classes
+  }
+
+  // FIXME: friends
+
+  // Okay, it's a bad access, reject it.
+
+  
+  CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+
+  if (Access == AS_protected) {
+    Diag(R.getNameLoc(), diag::err_access_protected)
+      << Context.getTypeDeclType(DeclaringClass)
+      << Context.getTypeDeclType(CurRecord);
+    DiagnoseAccessPath(*this, R, D, Access);
+    return true;
+  }
+
+  assert(Access == AS_private || Access == AS_none);
+  Diag(R.getNameLoc(), diag::err_access_private)
+    << Context.getTypeDeclType(DeclaringClass)
+    << Context.getTypeDeclType(CurRecord);
+  DiagnoseAccessPath(*this, R, D, Access);
+  return true;
+}
+
+/// Checks access to all the declarations in the given result set.
+void Sema::CheckAccess(const LookupResult &R) {
+  for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+    CheckAccess(R, *I, I.getAccess());
+}

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jan 22 18:46:32 2010
@@ -5732,8 +5732,10 @@
                                             IdLoc, Id, Owned(Val));
 
   // Register this decl in the current scope stack.
-  if (New)
+  if (New) {
+    New->setAccess(TheEnumDecl->getAccess());
     PushOnScopeChains(New, S);
+  }
 
   return DeclPtrTy::make(New);
 }

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Fri Jan 22 18:46:32 2010
@@ -967,6 +967,8 @@
   // Perform qualified name lookup into the LookupCtx.
   if (LookupDirect(R, LookupCtx)) {
     R.resolveKind();
+    if (isa<CXXRecordDecl>(LookupCtx))
+      R.setNamingClass(cast<CXXRecordDecl>(LookupCtx));
     return true;
   }
 
@@ -1039,6 +1041,8 @@
                                 R.getLookupName().getAsOpaquePtr(), Paths))
     return false;
 
+  R.setNamingClass(LookupRec);
+
   // C++ [class.member.lookup]p2:
   //   [...] If the resulting set of declarations are not all from
   //   sub-objects of the same type, or the set has a nonstatic member
@@ -1111,8 +1115,12 @@
   // Lookup in a base class succeeded; return these results.
 
   DeclContext::lookup_iterator I, E;
-  for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I)
-    R.addDecl(*I, std::max(SubobjectAccess, (*I)->getAccess()));
+  for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) {
+    NamedDecl *D = *I;
+    AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess,
+                                                    D->getAccess());
+    R.addDecl(D, AS);
+  }
   R.resolveKind();
   return true;
 }

Added: cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp?rev=94268&view=auto

==============================================================================
--- cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp (added)
+++ cfe/trunk/test/CXX/class.access/class.access.base/p1.cpp Fri Jan 22 18:46:32 2010
@@ -0,0 +1,152 @@
+// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+
+// C++0x [class.access.base]p1(a):
+//   If a class is declared to be a base class for another class using
+//   the public access specifier, the public members of the base class
+//   are accessible as public members of the derived class and protected
+//   members of the base class are accessible as protected members of
+//   the derived class.
+namespace test0 {
+  class Base {
+  public: int pub; static int spub;
+  protected: int prot; static int sprot; // expected-note 4 {{declared protected here}}
+  private: int priv; static int spriv; // expected-note 8 {{declared private here}}
+  };
+
+  class Test : public Base {
+    void test() {
+      pub++;
+      spub++;
+      prot++;
+      sprot++;
+      priv++; // expected-error {{private member}}
+      spriv++; // expected-error {{private member}}
+
+      Base::pub++;
+      Base::spub++;
+      Base::prot++;
+      Base::sprot++;
+      Base::priv++; // expected-error {{private member}}
+      Base::spriv++; // expected-error {{private member}}
+    }
+  };
+
+  void test(Test *t) {
+    t->pub++;
+    t->spub++;
+    t->prot++; // expected-error {{protected member}}
+    t->sprot++; // expected-error {{protected member}}
+    t->priv++; // expected-error {{private member}}
+    t->spriv++; // expected-error {{private member}}
+
+    t->Base::pub++;
+    t->Base::spub++;
+    t->Base::prot++; // expected-error {{protected member}}
+    t->Base::sprot++; // expected-error {{protected member}}
+    t->Base::priv++; // expected-error {{private member}}
+    t->Base::spriv++; // expected-error {{private member}}
+  }
+}
+
+// C++0x [class.access.base]p1(b):
+//   If a class is declared to be a base class for another class using
+//   the protected access specifier, the public and protected members
+//   of the base class are accessible as protected members of the
+//   derived class.
+namespace test1 {
+  class Base { // expected-note 6 {{constrained by protected inheritance}}
+  public: int pub; static int spub; // expected-note 2 {{constrained by protected inheritance}}
+  protected: int prot; static int sprot; // expected-note 4 {{declared protected here}}
+  private: int priv; static int spriv; // expected-note 8 {{declared private here}}
+  };
+
+  class Test : protected Base {
+    void test() {
+      pub++;
+      spub++;
+      prot++;
+      sprot++;
+      priv++; // expected-error {{private member}}
+      spriv++; // expected-error {{private member}}
+
+      Base::pub++;
+      Base::spub++;
+      Base::prot++;
+      Base::sprot++;
+      Base::priv++; // expected-error {{private member}}
+      Base::spriv++; // expected-error {{private member}}
+    }
+  };
+
+  void test(Test *t) {
+    t->pub++; // expected-error {{protected member}}
+    t->spub++; // expected-error {{protected member}}
+    t->prot++; // expected-error {{protected member}}
+    t->sprot++; // expected-error {{protected member}}
+    t->priv++; // expected-error {{private member}}
+    t->spriv++; // expected-error {{private member}}
+
+    // Two possible errors here: one for Base, one for the member
+    t->Base::pub++; // expected-error {{protected member}}
+    t->Base::spub++; // expected-error {{protected member}}
+    t->Base::prot++; // expected-error 2 {{protected member}}
+    t->Base::sprot++; // expected-error 2 {{protected member}}
+    t->Base::priv++; // expected-error {{protected member}} expected-error {{private member}}
+    t->Base::spriv++; // expected-error {{protected member}} expected-error {{private member}}
+  }
+}
+
+// C++0x [class.access.base]p1(b):
+//   If a class is declared to be a base class for another class using
+//   the private access specifier, the public and protected members of
+//   the base class are accessible as private members of the derived
+//   class.
+namespace test2 {
+  class Base { //expected-note 6 {{constrained by private inheritance}}
+  public:
+    int pub; // expected-note {{constrained by private inheritance}}
+    static int spub; // expected-note {{constrained by private inheritance}}
+  protected:
+    int prot; // expected-note {{constrained by private inheritance}} \
+              // expected-note {{declared protected here}}
+    static int sprot; // expected-note {{constrained by private inheritance}} \
+                      // expected-note {{declared protected here}}
+  private:
+    int priv; // expected-note 4 {{declared private here}}
+    static int spriv; // expected-note 4 {{declared private here}}
+  };
+
+  class Test : private Base { // expected-note 6 {{'private' inheritance specifier here}}
+    void test() {
+      pub++;
+      spub++;
+      prot++;
+      sprot++;
+      priv++; // expected-error {{private member}}
+      spriv++; // expected-error {{private member}}
+
+      Base::pub++;
+      Base::spub++;
+      Base::prot++;
+      Base::sprot++;
+      Base::priv++; // expected-error {{private member}}
+      Base::spriv++; // expected-error {{private member}}
+    }
+  };
+
+  void test(Test *t) {
+    t->pub++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+    t->spub++; // expected-error {{private member}}
+    t->prot++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+    t->sprot++; // expected-error {{private member}}
+    t->priv++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+    t->spriv++; // expected-error {{private member}}
+
+    t->Base::pub++; // expected-error {{private member}} expected-error {{inaccessible base class}}
+    t->Base::spub++; // expected-error {{private member}}
+    t->Base::prot++; // expected-error {{protected member}} expected-error {{private member}} expected-error {{inaccessible base class}}
+    t->Base::sprot++; // expected-error {{protected member}} expected-error {{private member}}
+    t->Base::priv++; // expected-error 2 {{private member}} expected-error {{inaccessible base class}}
+    t->Base::spriv++; // expected-error 2 {{private member}}
+  }
+}

Modified: cfe/trunk/test/SemaCXX/access-control-check.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/access-control-check.cpp?rev=94268&r1=94267&r2=94268&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/access-control-check.cpp (original)
+++ cfe/trunk/test/SemaCXX/access-control-check.cpp Fri Jan 22 18:46:32 2010
@@ -5,12 +5,11 @@
 };
 
 class P {
-  int iP;
-  int PPR();
+  int iP; // expected-note {{declared private here}}
+  int PPR(); // expected-note {{declared private here}}
 };
 
 class N : M,P {
   N() {}
-  // FIXME. No access violation is reported in method call or member access.
-  int PR() { return iP + PPR(); }
+  int PR() { return iP + PPR(); } // expected-error 2 {{access to private member of 'class P'}}
 };





More information about the cfe-commits mailing list