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