//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file provides Sema routines for C++ access control semantics. // //===----------------------------------------------------------------------===// #include "Sema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" using namespace clang; /// SetMemberAccessSpecifier - Set the access specifier of a member. /// Returns true on error (when the previous member decl access specifier /// is different from the new member decl access specifier). bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, NamedDecl *PrevMemberDecl, AccessSpecifier LexicalAS) { if (!PrevMemberDecl) { // Use the lexical access specifier. MemberDecl->setAccess(LexicalAS); return false; } // C++ [class.access.spec]p3: When a member is redeclared its access // specifier must be same as its initial declaration. if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { Diag(MemberDecl->getLocation(), diag::err_class_redeclared_with_different_access) << MemberDecl << LexicalAS; Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) << PrevMemberDecl << PrevMemberDecl->getAccess(); return true; } MemberDecl->setAccess(PrevMemberDecl->getAccess()); return false; } /// Find a class on the derivation path between Derived and Base that is /// inaccessible. If @p NoPrivileges is true, special access rights (members /// and friends) are not considered. const CXXBaseSpecifier *Sema::FindInaccessibleBase( QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) { Base = Context.getCanonicalType(Base).getUnqualifiedType(); assert(!Paths.isAmbiguous(Base) && "Can't check base class access if set of paths is ambiguous"); assert(Paths.isRecordingPaths() && "Can't check base class access without recorded paths"); const CXXBaseSpecifier *InaccessibleBase = 0; const CXXRecordDecl *CurrentClassDecl = 0; if (CXXMethodDecl *MD = dyn_cast_or_null(getCurFunctionDecl())) CurrentClassDecl = MD->getParent(); for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end(); Path != PathsEnd; ++Path) { bool FoundInaccessibleBase = false; for (CXXBasePath::const_iterator Element = Path->begin(), ElementEnd = Path->end(); Element != ElementEnd; ++Element) { const CXXBaseSpecifier *Base = Element->Base; switch (Base->getAccessSpecifier()) { default: assert(0 && "invalid access specifier"); case AS_public: // Nothing to do. break; case AS_private: // FIXME: Check if the current function/class is a friend. if (NoPrivileges || CurrentClassDecl != Element->Class) FoundInaccessibleBase = true; break; case AS_protected: // FIXME: Implement break; } if (FoundInaccessibleBase) { InaccessibleBase = Base; break; } } if (!FoundInaccessibleBase) { // We found a path to the base, our work here is done. return 0; } } assert(InaccessibleBase && "no path found, but no inaccessible base"); return InaccessibleBase; } /// CheckBaseClassAccess - Check that a derived class can access its base class /// and report an error if it can't. [class.access.base] bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, unsigned InaccessibleBaseID, CXXBasePaths &Paths, SourceLocation AccessLoc, DeclarationName Name) { if (!getLangOptions().AccessControl) return false; const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase( Derived, Base, Paths); if (InaccessibleBase) { Diag(AccessLoc, InaccessibleBaseID) << Derived << Base << Name; AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten(); // If there's no written access specifier, then the inheritance specifier // is implicitly private. if (AS == AS_none) Diag(InaccessibleBase->getSourceRange().getBegin(), diag::note_inheritance_implicitly_private_here); else Diag(InaccessibleBase->getSourceRange().getBegin(), diag::note_inheritance_specifier_here) << AS; return true; } return false; }