blob: e1a737806193410fab6f585bdbe406bf6523d71b [file] [log] [blame]
Anders Carlsson9aa04122009-03-27 05:05:05 +00001//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
Anders Carlssonb9b485c2009-03-27 04:43:36 +00002//
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//===----------------------------------------------------------------------===//
Anders Carlssonae9c08c2009-03-27 04:54:36 +000013
Anders Carlsson501c2a92009-03-27 06:03:27 +000014#include "SemaInherit.h"
Anders Carlssonae9c08c2009-03-27 04:54:36 +000015#include "Sema.h"
Anders Carlsson501c2a92009-03-27 06:03:27 +000016#include "clang/AST/ASTContext.h"
Anders Carlssonae9c08c2009-03-27 04:54:36 +000017using namespace clang;
18
Anders Carlsson9aa04122009-03-27 05:05:05 +000019/// 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).
Mike Stump25cf7602009-09-09 15:08:12 +000022bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
Anders Carlssonae9c08c2009-03-27 04:54:36 +000023 NamedDecl *PrevMemberDecl,
24 AccessSpecifier LexicalAS) {
25 if (!PrevMemberDecl) {
26 // Use the lexical access specifier.
27 MemberDecl->setAccess(LexicalAS);
28 return false;
29 }
Mike Stump25cf7602009-09-09 15:08:12 +000030
Anders Carlssonae9c08c2009-03-27 04:54:36 +000031 // 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()) {
Mike Stump25cf7602009-09-09 15:08:12 +000034 Diag(MemberDecl->getLocation(),
35 diag::err_class_redeclared_with_different_access)
Anders Carlssonae9c08c2009-03-27 04:54:36 +000036 << MemberDecl << LexicalAS;
37 Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
38 << PrevMemberDecl << PrevMemberDecl->getAccess();
39 return true;
40 }
Mike Stump25cf7602009-09-09 15:08:12 +000041
Anders Carlssonae9c08c2009-03-27 04:54:36 +000042 MemberDecl->setAccess(PrevMemberDecl->getAccess());
43 return false;
44}
Anders Carlsson9aa04122009-03-27 05:05:05 +000045
Sebastian Redl44793342009-07-18 14:32:15 +000046/// 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(
Mike Stump25cf7602009-09-09 15:08:12 +000050 QualType Derived, QualType Base, BasePaths &Paths, bool NoPrivileges) {
Anders Carlsson501c2a92009-03-27 06:03:27 +000051 Base = Context.getCanonicalType(Base).getUnqualifiedType();
Mike Stump25cf7602009-09-09 15:08:12 +000052 assert(!Paths.isAmbiguous(Base) &&
Anders Carlsson501c2a92009-03-27 06:03:27 +000053 "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");
Anders Carlsson501c2a92009-03-27 06:03:27 +000056
Sebastian Redl44793342009-07-18 14:32:15 +000057
58 const CXXBaseSpecifier *InaccessibleBase = 0;
59
60 const CXXRecordDecl *CurrentClassDecl = 0;
Anders Carlsson81379302009-03-27 19:01:12 +000061 if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl()))
62 CurrentClassDecl = MD->getParent();
63
Sebastian Redl44793342009-07-18 14:32:15 +000064 for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
Anders Carlsson501c2a92009-03-27 06:03:27 +000065 Path != PathsEnd; ++Path) {
Sebastian Redl44793342009-07-18 14:32:15 +000066
Anders Carlsson501c2a92009-03-27 06:03:27 +000067 bool FoundInaccessibleBase = false;
Sebastian Redl44793342009-07-18 14:32:15 +000068
69 for (BasePath::const_iterator Element = Path->begin(),
Anders Carlsson501c2a92009-03-27 06:03:27 +000070 ElementEnd = Path->end(); Element != ElementEnd; ++Element) {
71 const CXXBaseSpecifier *Base = Element->Base;
Sebastian Redl44793342009-07-18 14:32:15 +000072
Anders Carlsson501c2a92009-03-27 06:03:27 +000073 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:
Anders Carlsson81379302009-03-27 19:01:12 +000080 // FIXME: Check if the current function/class is a friend.
Sebastian Redl44793342009-07-18 14:32:15 +000081 if (NoPrivileges || CurrentClassDecl != Element->Class)
Anders Carlsson81379302009-03-27 19:01:12 +000082 FoundInaccessibleBase = true;
Anders Carlsson501c2a92009-03-27 06:03:27 +000083 break;
Sebastian Redl44793342009-07-18 14:32:15 +000084 case AS_protected:
Anders Carlsson164293f2009-03-28 04:17:27 +000085 // FIXME: Implement
86 break;
Anders Carlsson501c2a92009-03-27 06:03:27 +000087 }
Sebastian Redl44793342009-07-18 14:32:15 +000088
Anders Carlsson501c2a92009-03-27 06:03:27 +000089 if (FoundInaccessibleBase) {
Sebastian Redl44793342009-07-18 14:32:15 +000090 InaccessibleBase = Base;
Anders Carlsson501c2a92009-03-27 06:03:27 +000091 break;
92 }
93 }
Sebastian Redl44793342009-07-18 14:32:15 +000094
Anders Carlsson501c2a92009-03-27 06:03:27 +000095 if (!FoundInaccessibleBase) {
96 // We found a path to the base, our work here is done.
Sebastian Redl44793342009-07-18 14:32:15 +000097 return 0;
Anders Carlsson501c2a92009-03-27 06:03:27 +000098 }
99 }
100
Sebastian Redl44793342009-07-18 14:32:15 +0000101 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]
Mike Stump25cf7602009-09-09 15:08:12 +0000107bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
Sebastian Redl44793342009-07-18 14:32:15 +0000108 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) {
Mike Stump25cf7602009-09-09 15:08:12 +0000118 Diag(AccessLoc, InaccessibleBaseID)
Anders Carlsson9ecd3152009-05-13 21:11:42 +0000119 << Derived << Base << Name;
Anders Carlsson501c2a92009-03-27 06:03:27 +0000120
Sebastian Redl44793342009-07-18 14:32:15 +0000121 AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten();
122
Anders Carlsson501c2a92009-03-27 06:03:27 +0000123 // If there's no written access specifier, then the inheritance specifier
124 // is implicitly private.
125 if (AS == AS_none)
Sebastian Redl44793342009-07-18 14:32:15 +0000126 Diag(InaccessibleBase->getSourceRange().getBegin(),
Anders Carlsson501c2a92009-03-27 06:03:27 +0000127 diag::note_inheritance_implicitly_private_here);
128 else
Sebastian Redl44793342009-07-18 14:32:15 +0000129 Diag(InaccessibleBase->getSourceRange().getBegin(),
Anders Carlsson501c2a92009-03-27 06:03:27 +0000130 diag::note_inheritance_specifier_here) << AS;
131
132 return true;
133 }
Sebastian Redl44793342009-07-18 14:32:15 +0000134
Anders Carlsson9aa04122009-03-27 05:05:05 +0000135 return false;
136}