1 //===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file provides Sema routines for C++ access control semantics.
12 //===----------------------------------------------------------------------===//
14 #include "SemaInherit.h"
16 #include "clang/AST/ASTContext.h"
17 using namespace clang
;
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).
22 bool Sema::SetMemberAccessSpecifier(NamedDecl
*MemberDecl
,
23 NamedDecl
*PrevMemberDecl
,
24 AccessSpecifier LexicalAS
) {
25 if (!PrevMemberDecl
) {
26 // Use the lexical access specifier.
27 MemberDecl
->setAccess(LexicalAS
);
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();
42 MemberDecl
->setAccess(PrevMemberDecl
->getAccess());
46 /// 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.
49 const CXXBaseSpecifier
*Sema::FindInaccessibleBase(
50 QualType Derived
, QualType Base
, BasePaths
&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");
59 const CXXBaseSpecifier
*InaccessibleBase
= 0;
61 const CXXRecordDecl
*CurrentClassDecl
= 0;
62 if (CXXMethodDecl
*MD
= dyn_cast_or_null
<CXXMethodDecl
>(getCurFunctionDecl()))
63 CurrentClassDecl
= MD
->getParent();
65 for (BasePaths::paths_iterator Path
= Paths
.begin(), PathsEnd
= Paths
.end();
66 Path
!= PathsEnd
; ++Path
) {
68 bool FoundInaccessibleBase
= false;
70 for (BasePath::const_iterator Element
= Path
->begin(),
71 ElementEnd
= Path
->end(); Element
!= ElementEnd
; ++Element
) {
72 const CXXBaseSpecifier
*Base
= Element
->Base
;
74 switch (Base
->getAccessSpecifier()) {
76 assert(0 && "invalid access specifier");
81 // FIXME: Check if the current function/class is a friend.
82 if (NoPrivileges
|| CurrentClassDecl
!= Element
->Class
)
83 FoundInaccessibleBase
= true;
90 if (FoundInaccessibleBase
) {
91 InaccessibleBase
= Base
;
96 if (!FoundInaccessibleBase
) {
97 // We found a path to the base, our work here is done.
102 assert(InaccessibleBase
&& "no path found, but no inaccessible base");
103 return InaccessibleBase
;
106 /// CheckBaseClassAccess - Check that a derived class can access its base class
107 /// and report an error if it can't. [class.access.base]
108 bool Sema::CheckBaseClassAccess(QualType Derived
, QualType Base
,
109 unsigned InaccessibleBaseID
,
110 BasePaths
&Paths
, SourceLocation AccessLoc
,
111 DeclarationName Name
) {
113 if (!getLangOptions().AccessControl
)
115 const CXXBaseSpecifier
*InaccessibleBase
= FindInaccessibleBase(
116 Derived
, Base
, Paths
);
118 if (InaccessibleBase
) {
119 Diag(AccessLoc
, InaccessibleBaseID
)
120 << Derived
<< Base
<< Name
;
122 AccessSpecifier AS
= InaccessibleBase
->getAccessSpecifierAsWritten();
124 // If there's no written access specifier, then the inheritance specifier
125 // is implicitly private.
127 Diag(InaccessibleBase
->getSourceRange().getBegin(),
128 diag::note_inheritance_implicitly_private_here
);
130 Diag(InaccessibleBase
->getSourceRange().getBegin(),
131 diag::note_inheritance_specifier_here
) << AS
;