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