SemaAccess.cpp revision 25cf760b54d3b88633827501013bc51a29b28aba
1//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file provides Sema routines for C++ access control semantics. 11// 12//===----------------------------------------------------------------------===// 13 14#include "SemaInherit.h" 15#include "Sema.h" 16#include "clang/AST/ASTContext.h" 17using namespace clang; 18 19/// SetMemberAccessSpecifier - Set the access specifier of a member. 20/// Returns true on error (when the previous member decl access specifier 21/// is different from the new member decl access specifier). 22bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, 23 NamedDecl *PrevMemberDecl, 24 AccessSpecifier LexicalAS) { 25 if (!PrevMemberDecl) { 26 // Use the lexical access specifier. 27 MemberDecl->setAccess(LexicalAS); 28 return false; 29 } 30 31 // C++ [class.access.spec]p3: When a member is redeclared its access 32 // specifier must be same as its initial declaration. 33 if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { 34 Diag(MemberDecl->getLocation(), 35 diag::err_class_redeclared_with_different_access) 36 << MemberDecl << LexicalAS; 37 Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) 38 << PrevMemberDecl << PrevMemberDecl->getAccess(); 39 return true; 40 } 41 42 MemberDecl->setAccess(PrevMemberDecl->getAccess()); 43 return false; 44} 45 46/// Find a class on the derivation path between Derived and Base that is 47/// inaccessible. If @p NoPrivileges is true, special access rights (members 48/// and friends) are not considered. 49const CXXBaseSpecifier *Sema::FindInaccessibleBase( 50 QualType Derived, QualType Base, BasePaths &Paths, bool NoPrivileges) { 51 Base = Context.getCanonicalType(Base).getUnqualifiedType(); 52 assert(!Paths.isAmbiguous(Base) && 53 "Can't check base class access if set of paths is ambiguous"); 54 assert(Paths.isRecordingPaths() && 55 "Can't check base class access without recorded paths"); 56 57 58 const CXXBaseSpecifier *InaccessibleBase = 0; 59 60 const CXXRecordDecl *CurrentClassDecl = 0; 61 if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl())) 62 CurrentClassDecl = MD->getParent(); 63 64 for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end(); 65 Path != PathsEnd; ++Path) { 66 67 bool FoundInaccessibleBase = false; 68 69 for (BasePath::const_iterator Element = Path->begin(), 70 ElementEnd = Path->end(); Element != ElementEnd; ++Element) { 71 const CXXBaseSpecifier *Base = Element->Base; 72 73 switch (Base->getAccessSpecifier()) { 74 default: 75 assert(0 && "invalid access specifier"); 76 case AS_public: 77 // Nothing to do. 78 break; 79 case AS_private: 80 // FIXME: Check if the current function/class is a friend. 81 if (NoPrivileges || CurrentClassDecl != Element->Class) 82 FoundInaccessibleBase = true; 83 break; 84 case AS_protected: 85 // FIXME: Implement 86 break; 87 } 88 89 if (FoundInaccessibleBase) { 90 InaccessibleBase = Base; 91 break; 92 } 93 } 94 95 if (!FoundInaccessibleBase) { 96 // We found a path to the base, our work here is done. 97 return 0; 98 } 99 } 100 101 assert(InaccessibleBase && "no path found, but no inaccessible base"); 102 return InaccessibleBase; 103} 104 105/// CheckBaseClassAccess - Check that a derived class can access its base class 106/// and report an error if it can't. [class.access.base] 107bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, 108 unsigned InaccessibleBaseID, 109 BasePaths &Paths, SourceLocation AccessLoc, 110 DeclarationName Name) { 111 112 if (!getLangOptions().AccessControl) 113 return false; 114 const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase( 115 Derived, Base, Paths); 116 117 if (InaccessibleBase) { 118 Diag(AccessLoc, InaccessibleBaseID) 119 << Derived << Base << Name; 120 121 AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten(); 122 123 // If there's no written access specifier, then the inheritance specifier 124 // is implicitly private. 125 if (AS == AS_none) 126 Diag(InaccessibleBase->getSourceRange().getBegin(), 127 diag::note_inheritance_implicitly_private_here); 128 else 129 Diag(InaccessibleBase->getSourceRange().getBegin(), 130 diag::note_inheritance_specifier_here) << AS; 131 132 return true; 133 } 134 135 return false; 136} 137