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