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