SemaAccess.cpp revision 14734f7d2a69f9076e8a06954f06d3313063e7f9
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/// CheckBaseClassAccess - Check that a derived class can access its base class 47/// and report an error if it can't. [class.access.base] 48bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, 49 BasePaths& Paths, SourceLocation AccessLoc) { 50 Base = Context.getCanonicalType(Base).getUnqualifiedType(); 51 assert(!Paths.isAmbiguous(Base) && 52 "Can't check base class access if set of paths is ambiguous"); 53 assert(Paths.isRecordingPaths() && 54 "Can't check base class access without recorded paths"); 55 56 const CXXBaseSpecifier *InacessibleBase = 0; 57 58 const CXXRecordDecl* CurrentClassDecl = 0; 59 if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl())) 60 CurrentClassDecl = MD->getParent(); 61 62 for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end(); 63 Path != PathsEnd; ++Path) { 64 65 bool FoundInaccessibleBase = false; 66 67 for (BasePath::const_iterator Element = Path->begin(), 68 ElementEnd = Path->end(); Element != ElementEnd; ++Element) { 69 const CXXBaseSpecifier *Base = Element->Base; 70 71 switch (Base->getAccessSpecifier()) { 72 default: 73 assert(0 && "invalid access specifier"); 74 case AS_public: 75 // Nothing to do. 76 break; 77 case AS_private: 78 // FIXME: Check if the current function/class is a friend. 79 if (CurrentClassDecl != Element->Class) 80 FoundInaccessibleBase = true; 81 break; 82 case AS_protected: 83 // FIXME: Implement 84 break; 85 } 86 87 if (FoundInaccessibleBase) { 88 InacessibleBase = Base; 89 break; 90 } 91 } 92 93 if (!FoundInaccessibleBase) { 94 // We found a path to the base, our work here is done. 95 InacessibleBase = 0; 96 break; 97 } 98 } 99 100 if (InacessibleBase) { 101 Diag(AccessLoc, diag::err_conv_to_inaccessible_base) 102 << Derived << Base; 103 104 AccessSpecifier AS = InacessibleBase->getAccessSpecifierAsWritten(); 105 106 // If there's no written access specifier, then the inheritance specifier 107 // is implicitly private. 108 if (AS == AS_none) 109 Diag(InacessibleBase->getSourceRange().getBegin(), 110 diag::note_inheritance_implicitly_private_here); 111 else 112 Diag(InacessibleBase->getSourceRange().getBegin(), 113 diag::note_inheritance_specifier_here) << AS; 114 115 return true; 116 } 117 118 return false; 119} 120