[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