blob: b7cc37b6c9a76e0dfd839d2b8d1b20cce3f24370 [file] [log] [blame]
Anders Carlsson29f006b2009-03-27 05:05:05 +00001//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
Anders Carlsson60d6b0d2009-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 Carlssonc60e8882009-03-27 04:54:36 +000013
14#include "Sema.h"
Anders Carlssonc4f1e872009-03-27 06:03:27 +000015#include "clang/AST/ASTContext.h"
Douglas Gregora8f32e02009-10-06 17:59:45 +000016#include "clang/AST/CXXInheritance.h"
17#include "clang/AST/DeclCXX.h"
Anders Carlssonc60e8882009-03-27 04:54:36 +000018using namespace clang;
19
Anders Carlsson29f006b2009-03-27 05:05:05 +000020/// 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).
Mike Stump1eb44332009-09-09 15:08:12 +000023bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
Anders Carlssonc60e8882009-03-27 04:54:36 +000024 NamedDecl *PrevMemberDecl,
25 AccessSpecifier LexicalAS) {
26 if (!PrevMemberDecl) {
27 // Use the lexical access specifier.
28 MemberDecl->setAccess(LexicalAS);
29 return false;
30 }
Mike Stump1eb44332009-09-09 15:08:12 +000031
Anders Carlssonc60e8882009-03-27 04:54:36 +000032 // 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()) {
Mike Stump1eb44332009-09-09 15:08:12 +000035 Diag(MemberDecl->getLocation(),
36 diag::err_class_redeclared_with_different_access)
Anders Carlssonc60e8882009-03-27 04:54:36 +000037 << MemberDecl << LexicalAS;
38 Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
39 << PrevMemberDecl << PrevMemberDecl->getAccess();
John McCall44e067b2009-12-23 00:37:40 +000040
41 MemberDecl->setAccess(LexicalAS);
Anders Carlssonc60e8882009-03-27 04:54:36 +000042 return true;
43 }
Mike Stump1eb44332009-09-09 15:08:12 +000044
Anders Carlssonc60e8882009-03-27 04:54:36 +000045 MemberDecl->setAccess(PrevMemberDecl->getAccess());
46 return false;
47}
Anders Carlsson29f006b2009-03-27 05:05:05 +000048
Sebastian Redl726212f2009-07-18 14:32:15 +000049/// Find a class on the derivation path between Derived and Base that is
50/// inaccessible. If @p NoPrivileges is true, special access rights (members
51/// and friends) are not considered.
52const CXXBaseSpecifier *Sema::FindInaccessibleBase(
Douglas Gregora8f32e02009-10-06 17:59:45 +000053 QualType Derived, QualType Base, CXXBasePaths &Paths, bool NoPrivileges) {
Anders Carlssonc4f1e872009-03-27 06:03:27 +000054 Base = Context.getCanonicalType(Base).getUnqualifiedType();
Mike Stump1eb44332009-09-09 15:08:12 +000055 assert(!Paths.isAmbiguous(Base) &&
Anders Carlssonc4f1e872009-03-27 06:03:27 +000056 "Can't check base class access if set of paths is ambiguous");
57 assert(Paths.isRecordingPaths() &&
58 "Can't check base class access without recorded paths");
Anders Carlssonc4f1e872009-03-27 06:03:27 +000059
Sebastian Redl726212f2009-07-18 14:32:15 +000060
61 const CXXBaseSpecifier *InaccessibleBase = 0;
62
63 const CXXRecordDecl *CurrentClassDecl = 0;
Anders Carlssonf8080a32009-03-27 19:01:12 +000064 if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl()))
65 CurrentClassDecl = MD->getParent();
66
Douglas Gregora8f32e02009-10-06 17:59:45 +000067 for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
Anders Carlssonc4f1e872009-03-27 06:03:27 +000068 Path != PathsEnd; ++Path) {
Sebastian Redl726212f2009-07-18 14:32:15 +000069
Anders Carlssonc4f1e872009-03-27 06:03:27 +000070 bool FoundInaccessibleBase = false;
Sebastian Redl726212f2009-07-18 14:32:15 +000071
Douglas Gregora8f32e02009-10-06 17:59:45 +000072 for (CXXBasePath::const_iterator Element = Path->begin(),
Anders Carlssonc4f1e872009-03-27 06:03:27 +000073 ElementEnd = Path->end(); Element != ElementEnd; ++Element) {
74 const CXXBaseSpecifier *Base = Element->Base;
Sebastian Redl726212f2009-07-18 14:32:15 +000075
Anders Carlssonc4f1e872009-03-27 06:03:27 +000076 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:
Anders Carlssonf8080a32009-03-27 19:01:12 +000083 // FIXME: Check if the current function/class is a friend.
Sebastian Redl726212f2009-07-18 14:32:15 +000084 if (NoPrivileges || CurrentClassDecl != Element->Class)
Anders Carlssonf8080a32009-03-27 19:01:12 +000085 FoundInaccessibleBase = true;
Anders Carlssonc4f1e872009-03-27 06:03:27 +000086 break;
Sebastian Redl726212f2009-07-18 14:32:15 +000087 case AS_protected:
Anders Carlsson14734f72009-03-28 04:17:27 +000088 // FIXME: Implement
89 break;
Anders Carlssonc4f1e872009-03-27 06:03:27 +000090 }
Sebastian Redl726212f2009-07-18 14:32:15 +000091
Anders Carlssonc4f1e872009-03-27 06:03:27 +000092 if (FoundInaccessibleBase) {
Sebastian Redl726212f2009-07-18 14:32:15 +000093 InaccessibleBase = Base;
Anders Carlssonc4f1e872009-03-27 06:03:27 +000094 break;
95 }
96 }
Sebastian Redl726212f2009-07-18 14:32:15 +000097
Anders Carlssonc4f1e872009-03-27 06:03:27 +000098 if (!FoundInaccessibleBase) {
99 // We found a path to the base, our work here is done.
Sebastian Redl726212f2009-07-18 14:32:15 +0000100 return 0;
Anders Carlssonc4f1e872009-03-27 06:03:27 +0000101 }
102 }
103
Sebastian Redl726212f2009-07-18 14:32:15 +0000104 assert(InaccessibleBase && "no path found, but no inaccessible base");
105 return InaccessibleBase;
106}
107
108/// CheckBaseClassAccess - Check that a derived class can access its base class
109/// and report an error if it can't. [class.access.base]
Mike Stump1eb44332009-09-09 15:08:12 +0000110bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
Sebastian Redl726212f2009-07-18 14:32:15 +0000111 unsigned InaccessibleBaseID,
Douglas Gregora8f32e02009-10-06 17:59:45 +0000112 CXXBasePaths &Paths, SourceLocation AccessLoc,
Sebastian Redl726212f2009-07-18 14:32:15 +0000113 DeclarationName Name) {
114
115 if (!getLangOptions().AccessControl)
116 return false;
117 const CXXBaseSpecifier *InaccessibleBase = FindInaccessibleBase(
118 Derived, Base, Paths);
119
120 if (InaccessibleBase) {
Mike Stump1eb44332009-09-09 15:08:12 +0000121 Diag(AccessLoc, InaccessibleBaseID)
Anders Carlssond8f9cb02009-05-13 21:11:42 +0000122 << Derived << Base << Name;
Anders Carlssonc4f1e872009-03-27 06:03:27 +0000123
Sebastian Redl726212f2009-07-18 14:32:15 +0000124 AccessSpecifier AS = InaccessibleBase->getAccessSpecifierAsWritten();
125
Anders Carlssonc4f1e872009-03-27 06:03:27 +0000126 // If there's no written access specifier, then the inheritance specifier
127 // is implicitly private.
128 if (AS == AS_none)
Sebastian Redl726212f2009-07-18 14:32:15 +0000129 Diag(InaccessibleBase->getSourceRange().getBegin(),
Anders Carlssonc4f1e872009-03-27 06:03:27 +0000130 diag::note_inheritance_implicitly_private_here);
131 else
Sebastian Redl726212f2009-07-18 14:32:15 +0000132 Diag(InaccessibleBase->getSourceRange().getBegin(),
Anders Carlssonc4f1e872009-03-27 06:03:27 +0000133 diag::note_inheritance_specifier_here) << AS;
134
135 return true;
136 }
Sebastian Redl726212f2009-07-18 14:32:15 +0000137
Anders Carlsson29f006b2009-03-27 05:05:05 +0000138 return false;
139}