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