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