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" 17 using 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). 22 bool 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. 49 const CXXBaseSpecifier *Sema::FindInaccessibleBase( 50 QualType Derived, QualType Base, BasePaths &Paths, bool NoPrivileges) 51 { 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 (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end(); 66 Path != PathsEnd; ++Path) { 67 68 bool FoundInaccessibleBase = false; 69 70 for (BasePath::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] 108 bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, 109 unsigned InaccessibleBaseID, 110 BasePaths &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