diff options
Diffstat (limited to 'clang/lib/AST/CXXInheritance.cpp')
-rw-r--r-- | clang/lib/AST/CXXInheritance.cpp | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp index d575ccd9826..72083286926 100644 --- a/clang/lib/AST/CXXInheritance.cpp +++ b/clang/lib/AST/CXXInheritance.cpp @@ -61,7 +61,6 @@ void CXXBasePaths::clear() { Paths.clear(); ClassSubobjects.clear(); ScratchPath.clear(); - ScratchAccess.clear(); DetectedVirtual = 0; } @@ -147,6 +146,10 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, 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 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, 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 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, // 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 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, Paths.DetectedVirtual = 0; } } + + // Reset the scratch path access. + Paths.ScratchPath.Access = AccessToHere; return FoundPath; } |