//===---- 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 "SemaInherit.h" #include "Sema.h" #include "clang/AST/ASTContext.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; } /// 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, BasePaths& Paths, SourceLocation AccessLoc, DeclarationName Name) { 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"); if (!getLangOptions().AccessControl) return false; const CXXBaseSpecifier *InacessibleBase = 0; const CXXRecordDecl* CurrentClassDecl = 0; if (CXXMethodDecl *MD = dyn_cast_or_null(getCurFunctionDecl())) CurrentClassDecl = MD->getParent(); for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end(); Path != PathsEnd; ++Path) { bool FoundInaccessibleBase = false; for (BasePath::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 (CurrentClassDecl != Element->Class) FoundInaccessibleBase = true; break; case AS_protected: // FIXME: Implement break; } if (FoundInaccessibleBase) { InacessibleBase = Base; break; } } if (!FoundInaccessibleBase) { // We found a path to the base, our work here is done. InacessibleBase = 0; break; } } if (InacessibleBase) { Diag(AccessLoc, InaccessibleBaseID) << Derived << Base << Name; AccessSpecifier AS = InacessibleBase->getAccessSpecifierAsWritten(); // If there's no written access specifier, then the inheritance specifier // is implicitly private. if (AS == AS_none) Diag(InacessibleBase->getSourceRange().getBegin(), diag::note_inheritance_implicitly_private_here); else Diag(InacessibleBase->getSourceRange().getBegin(), diag::note_inheritance_specifier_here) << AS; return true; } return false; }