SemaAccess.cpp revision a8f32e0965ee19ecc53cd796e34268377a20357c
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 "Sema.h"
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/CXXInheritance.h"
17#include "clang/AST/DeclCXX.h"
18using namespace clang;
19
20/// SetMemberAccessSpecifier - Set the access specifier of a member.
21/// Returns true on error (when the previous member decl access specifier
22/// is different from the new member decl access specifier).
23bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
24                                    NamedDecl *PrevMemberDecl,
25                                    AccessSpecifier LexicalAS) {
26  if (!PrevMemberDecl) {
27    // Use the lexical access specifier.
28    MemberDecl->setAccess(LexicalAS);
29    return false;
30  }
31
32  // C++ [class.access.spec]p3: When a member is redeclared its access
33  // specifier must be same as its initial declaration.
34  if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
35    Diag(MemberDecl->getLocation(),
36         diag::err_class_redeclared_with_different_access)
37      << MemberDecl << LexicalAS;
38    Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
39      << PrevMemberDecl << PrevMemberDecl->getAccess();
40    return true;
41  }
42
43  MemberDecl->setAccess(PrevMemberDecl->getAccess());
44  return false;
45}
46
47/// Find a class on the derivation path between Derived and Base that is
48/// inaccessible. If @p NoPrivileges is true, special access rights (members
49/// and friends) are not considered.
50const CXXBaseSpecifier *Sema::FindInaccessibleBase(
51    QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) {
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 (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
66      Path != PathsEnd; ++Path) {
67
68    bool FoundInaccessibleBase = false;
69
70    for (CXXBasePath::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]
108bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
109                                unsigned InaccessibleBaseID,
110                                CXXBasePaths &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