blob: bae69ac6dc74aa7089ea4e4b5ccfa0ebef7d5de9 [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
Anders Carlssonc4f1e872009-03-27 06:03:27 +000014#include "SemaInherit.h"
Anders Carlssonc60e8882009-03-27 04:54:36 +000015#include "Sema.h"
Anders Carlssonc4f1e872009-03-27 06:03:27 +000016#include "clang/AST/ASTContext.h"
Anders Carlssonc60e8882009-03-27 04:54:36 +000017using namespace clang;
18
Anders Carlsson29f006b2009-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).
Anders Carlssonc60e8882009-03-27 04:54:36 +000022bool 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}
Anders Carlsson29f006b2009-03-27 05:05:05 +000045
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,
Anders Carlssond8f9cb02009-05-13 21:11:42 +000049 unsigned InaccessibleBaseID,
50 BasePaths& Paths, SourceLocation AccessLoc,
51 DeclarationName Name) {
Anders Carlssonc4f1e872009-03-27 06:03:27 +000052 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
Anders Carlssona33d9b42009-05-13 19:49:53 +000058 if (!getLangOptions().AccessControl)
59 return false;
60
Anders Carlssonc4f1e872009-03-27 06:03:27 +000061 const CXXBaseSpecifier *InacessibleBase = 0;
62
Anders Carlsson14734f72009-03-28 04:17:27 +000063 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
Anders Carlssonc4f1e872009-03-27 06:03:27 +000067 for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end();
68 Path != PathsEnd; ++Path) {
69
70 bool FoundInaccessibleBase = false;
71
72 for (BasePath::const_iterator Element = Path->begin(),
73 ElementEnd = Path->end(); Element != ElementEnd; ++Element) {
74 const CXXBaseSpecifier *Base = Element->Base;
75
76 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.
84 if (CurrentClassDecl != Element->Class)
85 FoundInaccessibleBase = true;
Anders Carlssonc4f1e872009-03-27 06:03:27 +000086 break;
Anders Carlsson14734f72009-03-28 04:17:27 +000087 case AS_protected:
88 // FIXME: Implement
89 break;
Anders Carlssonc4f1e872009-03-27 06:03:27 +000090 }
91
92 if (FoundInaccessibleBase) {
93 InacessibleBase = Base;
94 break;
95 }
96 }
97
98 if (!FoundInaccessibleBase) {
99 // We found a path to the base, our work here is done.
100 InacessibleBase = 0;
101 break;
102 }
103 }
104
105 if (InacessibleBase) {
Anders Carlssond8f9cb02009-05-13 21:11:42 +0000106 Diag(AccessLoc, InaccessibleBaseID)
107 << Derived << Base << Name;
Anders Carlssonc4f1e872009-03-27 06:03:27 +0000108
109 AccessSpecifier AS = InacessibleBase->getAccessSpecifierAsWritten();
110
111 // If there's no written access specifier, then the inheritance specifier
112 // is implicitly private.
113 if (AS == AS_none)
114 Diag(InacessibleBase->getSourceRange().getBegin(),
115 diag::note_inheritance_implicitly_private_here);
116 else
117 Diag(InacessibleBase->getSourceRange().getBegin(),
118 diag::note_inheritance_specifier_here) << AS;
119
120 return true;
121 }
122
Anders Carlsson29f006b2009-03-27 05:05:05 +0000123 return false;
124}