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 "clang/Sema/SemaInternal.h"
15 #include "clang/Sema/DelayedDiagnostic.h"
16 #include "clang/Sema/Initialization.h"
17 #include "clang/Sema/Lookup.h"
18 #include "clang/AST/ASTContext.h"
19 #include "clang/AST/CXXInheritance.h"
20 #include "clang/AST/DeclCXX.h"
21 #include "clang/AST/DeclFriend.h"
22 #include "clang/AST/DependentDiagnostic.h"
23 #include "clang/AST/ExprCXX.h"
25 using namespace clang
;
28 /// A copy of Sema's enum without AR_delayed.
35 /// SetMemberAccessSpecifier - Set the access specifier of a member.
36 /// Returns true on error (when the previous member decl access specifier
37 /// is different from the new member decl access specifier).
38 bool Sema::SetMemberAccessSpecifier(NamedDecl
*MemberDecl
,
39 NamedDecl
*PrevMemberDecl
,
40 AccessSpecifier LexicalAS
) {
41 if (!PrevMemberDecl
) {
42 // Use the lexical access specifier.
43 MemberDecl
->setAccess(LexicalAS
);
47 // C++ [class.access.spec]p3: When a member is redeclared its access
48 // specifier must be same as its initial declaration.
49 if (LexicalAS
!= AS_none
&& LexicalAS
!= PrevMemberDecl
->getAccess()) {
50 Diag(MemberDecl
->getLocation(),
51 diag::err_class_redeclared_with_different_access
)
52 << MemberDecl
<< LexicalAS
;
53 Diag(PrevMemberDecl
->getLocation(), diag::note_previous_access_declaration
)
54 << PrevMemberDecl
<< PrevMemberDecl
->getAccess();
56 MemberDecl
->setAccess(LexicalAS
);
60 MemberDecl
->setAccess(PrevMemberDecl
->getAccess());
64 static CXXRecordDecl
*FindDeclaringClass(NamedDecl
*D
) {
65 DeclContext
*DC
= D
->getDeclContext();
67 // This can only happen at top: enum decls only "publish" their
69 if (isa
<EnumDecl
>(DC
))
70 DC
= cast
<EnumDecl
>(DC
)->getDeclContext();
72 CXXRecordDecl
*DeclaringClass
= cast
<CXXRecordDecl
>(DC
);
73 while (DeclaringClass
->isAnonymousStructOrUnion())
74 DeclaringClass
= cast
<CXXRecordDecl
>(DeclaringClass
->getDeclContext());
75 return DeclaringClass
;
79 struct EffectiveContext
{
80 EffectiveContext() : Inner(0), Dependent(false) {}
82 explicit EffectiveContext(DeclContext
*DC
)
84 Dependent(DC
->isDependentContext()) {
86 // C++ [class.access.nest]p1:
87 // A nested class is a member and as such has the same access
88 // rights as any other member.
89 // C++ [class.access]p2:
90 // A member of a class can also access all the names to which
91 // the class has access. A local class of a member function
92 // may access the same names that the member function itself
94 // This almost implies that the privileges of nesting are transitive.
95 // Technically it says nothing about the local classes of non-member
96 // functions (which can gain privileges through friendship), but we
97 // take that as an oversight.
99 if (isa
<CXXRecordDecl
>(DC
)) {
100 CXXRecordDecl
*Record
= cast
<CXXRecordDecl
>(DC
)->getCanonicalDecl();
101 Records
.push_back(Record
);
102 DC
= Record
->getDeclContext();
103 } else if (isa
<FunctionDecl
>(DC
)) {
104 FunctionDecl
*Function
= cast
<FunctionDecl
>(DC
)->getCanonicalDecl();
105 Functions
.push_back(Function
);
106 DC
= Function
->getDeclContext();
107 } else if (DC
->isFileContext()) {
110 DC
= DC
->getParent();
115 bool isDependent() const { return Dependent
; }
117 bool includesClass(const CXXRecordDecl
*R
) const {
118 R
= R
->getCanonicalDecl();
119 return std::find(Records
.begin(), Records
.end(), R
)
123 /// Retrieves the innermost "useful" context. Can be null if we're
124 /// doing access-control without privileges.
125 DeclContext
*getInnerContext() const {
129 typedef llvm::SmallVectorImpl
<CXXRecordDecl
*>::const_iterator record_iterator
;
132 llvm::SmallVector
<FunctionDecl
*, 4> Functions
;
133 llvm::SmallVector
<CXXRecordDecl
*, 4> Records
;
137 /// Like sema::AccessedEntity, but kindly lets us scribble all over
139 struct AccessTarget
: public AccessedEntity
{
140 AccessTarget(const AccessedEntity
&Entity
)
141 : AccessedEntity(Entity
) {
145 AccessTarget(ASTContext
&Context
,
147 CXXRecordDecl
*NamingClass
,
148 DeclAccessPair FoundDecl
,
149 QualType BaseObjectType
)
150 : AccessedEntity(Context
, Member
, NamingClass
, FoundDecl
, BaseObjectType
) {
154 AccessTarget(ASTContext
&Context
,
156 CXXRecordDecl
*BaseClass
,
157 CXXRecordDecl
*DerivedClass
,
158 AccessSpecifier Access
)
159 : AccessedEntity(Context
, Base
, BaseClass
, DerivedClass
, Access
) {
163 bool hasInstanceContext() const {
164 return HasInstanceContext
;
167 class SavedInstanceContext
{
169 ~SavedInstanceContext() {
170 Target
.HasInstanceContext
= Has
;
174 friend struct AccessTarget
;
175 explicit SavedInstanceContext(AccessTarget
&Target
)
176 : Target(Target
), Has(Target
.HasInstanceContext
) {}
177 AccessTarget
&Target
;
181 SavedInstanceContext
saveInstanceContext() {
182 return SavedInstanceContext(*this);
185 void suppressInstanceContext() {
186 HasInstanceContext
= false;
189 const CXXRecordDecl
*resolveInstanceContext(Sema
&S
) const {
190 assert(HasInstanceContext
);
191 if (CalculatedInstanceContext
)
192 return InstanceContext
;
194 CalculatedInstanceContext
= true;
195 DeclContext
*IC
= S
.computeDeclContext(getBaseObjectType());
196 InstanceContext
= (IC
? cast
<CXXRecordDecl
>(IC
)->getCanonicalDecl() : 0);
197 return InstanceContext
;
200 const CXXRecordDecl
*getDeclaringClass() const {
201 return DeclaringClass
;
206 HasInstanceContext
= (isMemberAccess() &&
207 !getBaseObjectType().isNull() &&
208 getTargetDecl()->isCXXInstanceMember());
209 CalculatedInstanceContext
= false;
212 if (isMemberAccess())
213 DeclaringClass
= FindDeclaringClass(getTargetDecl());
215 DeclaringClass
= getBaseClass();
216 DeclaringClass
= DeclaringClass
->getCanonicalDecl();
219 bool HasInstanceContext
: 1;
220 mutable bool CalculatedInstanceContext
: 1;
221 mutable const CXXRecordDecl
*InstanceContext
;
222 const CXXRecordDecl
*DeclaringClass
;
227 /// Checks whether one class might instantiate to the other.
228 static bool MightInstantiateTo(const CXXRecordDecl
*From
,
229 const CXXRecordDecl
*To
) {
230 // Declaration names are always preserved by instantiation.
231 if (From
->getDeclName() != To
->getDeclName())
234 const DeclContext
*FromDC
= From
->getDeclContext()->getPrimaryContext();
235 const DeclContext
*ToDC
= To
->getDeclContext()->getPrimaryContext();
236 if (FromDC
== ToDC
) return true;
237 if (FromDC
->isFileContext() || ToDC
->isFileContext()) return false;
243 /// Checks whether one class is derived from another, inclusively.
244 /// Properly indicates when it couldn't be determined due to
247 /// This should probably be donated to AST or at least Sema.
248 static AccessResult
IsDerivedFromInclusive(const CXXRecordDecl
*Derived
,
249 const CXXRecordDecl
*Target
) {
250 assert(Derived
->getCanonicalDecl() == Derived
);
251 assert(Target
->getCanonicalDecl() == Target
);
253 if (Derived
== Target
) return AR_accessible
;
255 bool CheckDependent
= Derived
->isDependentContext();
256 if (CheckDependent
&& MightInstantiateTo(Derived
, Target
))
259 AccessResult OnFailure
= AR_inaccessible
;
260 llvm::SmallVector
<const CXXRecordDecl
*, 8> Queue
; // actually a stack
263 for (CXXRecordDecl::base_class_const_iterator
264 I
= Derived
->bases_begin(), E
= Derived
->bases_end(); I
!= E
; ++I
) {
266 const CXXRecordDecl
*RD
;
268 QualType T
= I
->getType();
269 if (const RecordType
*RT
= T
->getAs
<RecordType
>()) {
270 RD
= cast
<CXXRecordDecl
>(RT
->getDecl());
271 } else if (const InjectedClassNameType
*IT
272 = T
->getAs
<InjectedClassNameType
>()) {
275 assert(T
->isDependentType() && "non-dependent base wasn't a record?");
276 OnFailure
= AR_dependent
;
280 RD
= RD
->getCanonicalDecl();
281 if (RD
== Target
) return AR_accessible
;
282 if (CheckDependent
&& MightInstantiateTo(RD
, Target
))
283 OnFailure
= AR_dependent
;
288 if (Queue
.empty()) break;
290 Derived
= Queue
.back();
298 static bool MightInstantiateTo(Sema
&S
, DeclContext
*Context
,
299 DeclContext
*Friend
) {
300 if (Friend
== Context
)
303 assert(!Friend
->isDependentContext() &&
304 "can't handle friends with dependent contexts here");
306 if (!Context
->isDependentContext())
309 if (Friend
->isFileContext())
312 // TODO: this is very conservative
316 // Asks whether the type in 'context' can ever instantiate to the type
318 static bool MightInstantiateTo(Sema
&S
, CanQualType Context
, CanQualType Friend
) {
319 if (Friend
== Context
)
322 if (!Friend
->isDependentType() && !Context
->isDependentType())
325 // TODO: this is very conservative.
329 static bool MightInstantiateTo(Sema
&S
,
330 FunctionDecl
*Context
,
331 FunctionDecl
*Friend
) {
332 if (Context
->getDeclName() != Friend
->getDeclName())
335 if (!MightInstantiateTo(S
,
336 Context
->getDeclContext(),
337 Friend
->getDeclContext()))
340 CanQual
<FunctionProtoType
> FriendTy
341 = S
.Context
.getCanonicalType(Friend
->getType())
342 ->getAs
<FunctionProtoType
>();
343 CanQual
<FunctionProtoType
> ContextTy
344 = S
.Context
.getCanonicalType(Context
->getType())
345 ->getAs
<FunctionProtoType
>();
347 // There isn't any way that I know of to add qualifiers
348 // during instantiation.
349 if (FriendTy
.getQualifiers() != ContextTy
.getQualifiers())
352 if (FriendTy
->getNumArgs() != ContextTy
->getNumArgs())
355 if (!MightInstantiateTo(S
,
356 ContextTy
->getResultType(),
357 FriendTy
->getResultType()))
360 for (unsigned I
= 0, E
= FriendTy
->getNumArgs(); I
!= E
; ++I
)
361 if (!MightInstantiateTo(S
,
362 ContextTy
->getArgType(I
),
363 FriendTy
->getArgType(I
)))
369 static bool MightInstantiateTo(Sema
&S
,
370 FunctionTemplateDecl
*Context
,
371 FunctionTemplateDecl
*Friend
) {
372 return MightInstantiateTo(S
,
373 Context
->getTemplatedDecl(),
374 Friend
->getTemplatedDecl());
377 static AccessResult
MatchesFriend(Sema
&S
,
378 const EffectiveContext
&EC
,
379 const CXXRecordDecl
*Friend
) {
380 if (EC
.includesClass(Friend
))
381 return AR_accessible
;
383 if (EC
.isDependent()) {
385 = S
.Context
.getCanonicalType(S
.Context
.getTypeDeclType(Friend
));
387 for (EffectiveContext::record_iterator
388 I
= EC
.Records
.begin(), E
= EC
.Records
.end(); I
!= E
; ++I
) {
389 CanQualType ContextTy
390 = S
.Context
.getCanonicalType(S
.Context
.getTypeDeclType(*I
));
391 if (MightInstantiateTo(S
, ContextTy
, FriendTy
))
396 return AR_inaccessible
;
399 static AccessResult
MatchesFriend(Sema
&S
,
400 const EffectiveContext
&EC
,
401 CanQualType Friend
) {
402 if (const RecordType
*RT
= Friend
->getAs
<RecordType
>())
403 return MatchesFriend(S
, EC
, cast
<CXXRecordDecl
>(RT
->getDecl()));
405 // TODO: we can do better than this
406 if (Friend
->isDependentType())
409 return AR_inaccessible
;
412 /// Determines whether the given friend class template matches
413 /// anything in the effective context.
414 static AccessResult
MatchesFriend(Sema
&S
,
415 const EffectiveContext
&EC
,
416 ClassTemplateDecl
*Friend
) {
417 AccessResult OnFailure
= AR_inaccessible
;
419 // Check whether the friend is the template of a class in the
421 for (llvm::SmallVectorImpl
<CXXRecordDecl
*>::const_iterator
422 I
= EC
.Records
.begin(), E
= EC
.Records
.end(); I
!= E
; ++I
) {
423 CXXRecordDecl
*Record
= *I
;
425 // Figure out whether the current class has a template:
426 ClassTemplateDecl
*CTD
;
428 // A specialization of the template...
429 if (isa
<ClassTemplateSpecializationDecl
>(Record
)) {
430 CTD
= cast
<ClassTemplateSpecializationDecl
>(Record
)
431 ->getSpecializedTemplate();
433 // ... or the template pattern itself.
435 CTD
= Record
->getDescribedClassTemplate();
440 if (Friend
== CTD
->getCanonicalDecl())
441 return AR_accessible
;
443 // If the context isn't dependent, it can't be a dependent match.
444 if (!EC
.isDependent())
447 // If the template names don't match, it can't be a dependent
448 // match. This isn't true in C++0x because of template aliases.
449 if (!S
.LangOpts
.CPlusPlus0x
&& CTD
->getDeclName() != Friend
->getDeclName())
452 // If the class's context can't instantiate to the friend's
453 // context, it can't be a dependent match.
454 if (!MightInstantiateTo(S
, CTD
->getDeclContext(),
455 Friend
->getDeclContext()))
458 // Otherwise, it's a dependent match.
459 OnFailure
= AR_dependent
;
465 /// Determines whether the given friend function matches anything in
466 /// the effective context.
467 static AccessResult
MatchesFriend(Sema
&S
,
468 const EffectiveContext
&EC
,
469 FunctionDecl
*Friend
) {
470 AccessResult OnFailure
= AR_inaccessible
;
472 for (llvm::SmallVectorImpl
<FunctionDecl
*>::const_iterator
473 I
= EC
.Functions
.begin(), E
= EC
.Functions
.end(); I
!= E
; ++I
) {
475 return AR_accessible
;
477 if (EC
.isDependent() && MightInstantiateTo(S
, *I
, Friend
))
478 OnFailure
= AR_dependent
;
484 /// Determines whether the given friend function template matches
485 /// anything in the effective context.
486 static AccessResult
MatchesFriend(Sema
&S
,
487 const EffectiveContext
&EC
,
488 FunctionTemplateDecl
*Friend
) {
489 if (EC
.Functions
.empty()) return AR_inaccessible
;
491 AccessResult OnFailure
= AR_inaccessible
;
493 for (llvm::SmallVectorImpl
<FunctionDecl
*>::const_iterator
494 I
= EC
.Functions
.begin(), E
= EC
.Functions
.end(); I
!= E
; ++I
) {
496 FunctionTemplateDecl
*FTD
= (*I
)->getPrimaryTemplate();
498 FTD
= (*I
)->getDescribedFunctionTemplate();
502 FTD
= FTD
->getCanonicalDecl();
505 return AR_accessible
;
507 if (EC
.isDependent() && MightInstantiateTo(S
, FTD
, Friend
))
508 OnFailure
= AR_dependent
;
514 /// Determines whether the given friend declaration matches anything
515 /// in the effective context.
516 static AccessResult
MatchesFriend(Sema
&S
,
517 const EffectiveContext
&EC
,
518 FriendDecl
*FriendD
) {
519 // Whitelist accesses if there's an invalid or unsupported friend
521 if (FriendD
->isInvalidDecl() || FriendD
->isUnsupportedFriend())
522 return AR_accessible
;
524 if (TypeSourceInfo
*T
= FriendD
->getFriendType())
525 return MatchesFriend(S
, EC
, T
->getType()->getCanonicalTypeUnqualified());
528 = cast
<NamedDecl
>(FriendD
->getFriendDecl()->getCanonicalDecl());
530 // FIXME: declarations with dependent or templated scope.
532 if (isa
<ClassTemplateDecl
>(Friend
))
533 return MatchesFriend(S
, EC
, cast
<ClassTemplateDecl
>(Friend
));
535 if (isa
<FunctionTemplateDecl
>(Friend
))
536 return MatchesFriend(S
, EC
, cast
<FunctionTemplateDecl
>(Friend
));
538 if (isa
<CXXRecordDecl
>(Friend
))
539 return MatchesFriend(S
, EC
, cast
<CXXRecordDecl
>(Friend
));
541 assert(isa
<FunctionDecl
>(Friend
) && "unknown friend decl kind");
542 return MatchesFriend(S
, EC
, cast
<FunctionDecl
>(Friend
));
545 static AccessResult
GetFriendKind(Sema
&S
,
546 const EffectiveContext
&EC
,
547 const CXXRecordDecl
*Class
) {
548 AccessResult OnFailure
= AR_inaccessible
;
550 // Okay, check friends.
551 for (CXXRecordDecl::friend_iterator I
= Class
->friend_begin(),
552 E
= Class
->friend_end(); I
!= E
; ++I
) {
553 FriendDecl
*Friend
= *I
;
555 switch (MatchesFriend(S
, EC
, Friend
)) {
557 return AR_accessible
;
559 case AR_inaccessible
:
563 OnFailure
= AR_dependent
;
568 // That's it, give up.
574 /// A helper class for checking for a friend which will grant access
575 /// to a protected instance member.
576 struct ProtectedFriendContext
{
578 const EffectiveContext
&EC
;
579 const CXXRecordDecl
*NamingClass
;
583 /// The path down to the current base class.
584 llvm::SmallVector
<const CXXRecordDecl
*, 20> CurPath
;
586 ProtectedFriendContext(Sema
&S
, const EffectiveContext
&EC
,
587 const CXXRecordDecl
*InstanceContext
,
588 const CXXRecordDecl
*NamingClass
)
589 : S(S
), EC(EC
), NamingClass(NamingClass
),
590 CheckDependent(InstanceContext
->isDependentContext() ||
591 NamingClass
->isDependentContext()),
592 EverDependent(false) {}
594 /// Check classes in the current path for friendship, starting at
596 bool checkFriendshipAlongPath(unsigned I
) {
597 assert(I
< CurPath
.size());
598 for (unsigned E
= CurPath
.size(); I
!= E
; ++I
) {
599 switch (GetFriendKind(S
, EC
, CurPath
[I
])) {
600 case AR_accessible
: return true;
601 case AR_inaccessible
: continue;
602 case AR_dependent
: EverDependent
= true; continue;
608 /// Perform a search starting at the given class.
610 /// PrivateDepth is the index of the last (least derived) class
611 /// along the current path such that a notional public member of
612 /// the final class in the path would have access in that class.
613 bool findFriendship(const CXXRecordDecl
*Cur
, unsigned PrivateDepth
) {
614 // If we ever reach the naming class, check the current path for
615 // friendship. We can also stop recursing because we obviously
616 // won't find the naming class there again.
617 if (Cur
== NamingClass
)
618 return checkFriendshipAlongPath(PrivateDepth
);
620 if (CheckDependent
&& MightInstantiateTo(Cur
, NamingClass
))
621 EverDependent
= true;
623 // Recurse into the base classes.
624 for (CXXRecordDecl::base_class_const_iterator
625 I
= Cur
->bases_begin(), E
= Cur
->bases_end(); I
!= E
; ++I
) {
627 // If this is private inheritance, then a public member of the
628 // base will not have any access in classes derived from Cur.
629 unsigned BasePrivateDepth
= PrivateDepth
;
630 if (I
->getAccessSpecifier() == AS_private
)
631 BasePrivateDepth
= CurPath
.size() - 1;
633 const CXXRecordDecl
*RD
;
635 QualType T
= I
->getType();
636 if (const RecordType
*RT
= T
->getAs
<RecordType
>()) {
637 RD
= cast
<CXXRecordDecl
>(RT
->getDecl());
638 } else if (const InjectedClassNameType
*IT
639 = T
->getAs
<InjectedClassNameType
>()) {
642 assert(T
->isDependentType() && "non-dependent base wasn't a record?");
643 EverDependent
= true;
647 // Recurse. We don't need to clean up if this returns true.
648 CurPath
.push_back(RD
);
649 if (findFriendship(RD
->getCanonicalDecl(), BasePrivateDepth
))
657 bool findFriendship(const CXXRecordDecl
*Cur
) {
658 assert(CurPath
.empty());
659 CurPath
.push_back(Cur
);
660 return findFriendship(Cur
, 0);
665 /// Search for a class P that EC is a friend of, under the constraint
666 /// InstanceContext <= P <= NamingClass
667 /// and with the additional restriction that a protected member of
668 /// NamingClass would have some natural access in P.
670 /// That second condition isn't actually quite right: the condition in
671 /// the standard is whether the target would have some natural access
672 /// in P. The difference is that the target might be more accessible
673 /// along some path not passing through NamingClass. Allowing that
674 /// introduces two problems:
675 /// - It breaks encapsulation because you can suddenly access a
676 /// forbidden base class's members by subclassing it elsewhere.
677 /// - It makes access substantially harder to compute because it
678 /// breaks the hill-climbing algorithm: knowing that the target is
679 /// accessible in some base class would no longer let you change
680 /// the question solely to whether the base class is accessible,
681 /// because the original target might have been more accessible
682 /// because of crazy subclassing.
683 /// So we don't implement that.
684 static AccessResult
GetProtectedFriendKind(Sema
&S
, const EffectiveContext
&EC
,
685 const CXXRecordDecl
*InstanceContext
,
686 const CXXRecordDecl
*NamingClass
) {
687 assert(InstanceContext
->getCanonicalDecl() == InstanceContext
);
688 assert(NamingClass
->getCanonicalDecl() == NamingClass
);
690 ProtectedFriendContext
PRC(S
, EC
, InstanceContext
, NamingClass
);
691 if (PRC
.findFriendship(InstanceContext
)) return AR_accessible
;
692 if (PRC
.EverDependent
) return AR_dependent
;
693 return AR_inaccessible
;
696 static AccessResult
HasAccess(Sema
&S
,
697 const EffectiveContext
&EC
,
698 const CXXRecordDecl
*NamingClass
,
699 AccessSpecifier Access
,
700 const AccessTarget
&Target
) {
701 assert(NamingClass
->getCanonicalDecl() == NamingClass
&&
702 "declaration should be canonicalized before being passed here");
704 if (Access
== AS_public
) return AR_accessible
;
705 assert(Access
== AS_private
|| Access
== AS_protected
);
707 AccessResult OnFailure
= AR_inaccessible
;
709 for (EffectiveContext::record_iterator
710 I
= EC
.Records
.begin(), E
= EC
.Records
.end(); I
!= E
; ++I
) {
711 // All the declarations in EC have been canonicalized, so pointer
712 // equality from this point on will work fine.
713 const CXXRecordDecl
*ECRecord
= *I
;
716 if (Access
== AS_private
) {
717 if (ECRecord
== NamingClass
)
718 return AR_accessible
;
720 if (EC
.isDependent() && MightInstantiateTo(ECRecord
, NamingClass
))
721 OnFailure
= AR_dependent
;
725 assert(Access
== AS_protected
);
726 switch (IsDerivedFromInclusive(ECRecord
, NamingClass
)) {
727 case AR_accessible
: break;
728 case AR_inaccessible
: continue;
729 case AR_dependent
: OnFailure
= AR_dependent
; continue;
732 if (!Target
.hasInstanceContext())
733 return AR_accessible
;
735 const CXXRecordDecl
*InstanceContext
= Target
.resolveInstanceContext(S
);
736 if (!InstanceContext
) {
737 OnFailure
= AR_dependent
;
741 // C++ [class.protected]p1:
742 // An additional access check beyond those described earlier in
743 // [class.access] is applied when a non-static data member or
744 // non-static member function is a protected member of its naming
745 // class. As described earlier, access to a protected member is
746 // granted because the reference occurs in a friend or member of
747 // some class C. If the access is to form a pointer to member,
748 // the nested-name-specifier shall name C or a class derived from
749 // C. All other accesses involve a (possibly implicit) object
750 // expression. In this case, the class of the object expression
751 // shall be C or a class derived from C.
753 // We interpret this as a restriction on [M3]. Most of the
754 // conditions are encoded by not having any instance context.
755 switch (IsDerivedFromInclusive(InstanceContext
, ECRecord
)) {
756 case AR_accessible
: return AR_accessible
;
757 case AR_inaccessible
: continue;
758 case AR_dependent
: OnFailure
= AR_dependent
; continue;
763 // [M3] and [B3] say that, if the target is protected in N, we grant
764 // access if the access occurs in a friend or member of some class P
765 // that's a subclass of N and where the target has some natural
766 // access in P. The 'member' aspect is easy to handle because P
767 // would necessarily be one of the effective-context records, and we
768 // address that above. The 'friend' aspect is completely ridiculous
769 // to implement because there are no restrictions at all on P
770 // *unless* the [class.protected] restriction applies. If it does,
771 // however, we should ignore whether the naming class is a friend,
772 // and instead rely on whether any potential P is a friend.
773 if (Access
== AS_protected
&& Target
.hasInstanceContext()) {
774 const CXXRecordDecl
*InstanceContext
= Target
.resolveInstanceContext(S
);
775 if (!InstanceContext
) return AR_dependent
;
776 switch (GetProtectedFriendKind(S
, EC
, InstanceContext
, NamingClass
)) {
777 case AR_accessible
: return AR_accessible
;
778 case AR_inaccessible
: return OnFailure
;
779 case AR_dependent
: return AR_dependent
;
781 llvm_unreachable("impossible friendship kind");
784 switch (GetFriendKind(S
, EC
, NamingClass
)) {
785 case AR_accessible
: return AR_accessible
;
786 case AR_inaccessible
: return OnFailure
;
787 case AR_dependent
: return AR_dependent
;
790 // Silence bogus warnings
791 llvm_unreachable("impossible friendship kind");
795 /// Finds the best path from the naming class to the declaring class,
796 /// taking friend declarations into account.
798 /// C++0x [class.access.base]p5:
799 /// A member m is accessible at the point R when named in class N if
800 /// [M1] m as a member of N is public, or
801 /// [M2] m as a member of N is private, and R occurs in a member or
802 /// friend of class N, or
803 /// [M3] m as a member of N is protected, and R occurs in a member or
804 /// friend of class N, or in a member or friend of a class P
805 /// derived from N, where m as a member of P is public, private,
807 /// [M4] there exists a base class B of N that is accessible at R, and
808 /// m is accessible at R when named in class B.
810 /// C++0x [class.access.base]p4:
811 /// A base class B of N is accessible at R, if
812 /// [B1] an invented public member of B would be a public member of N, or
813 /// [B2] R occurs in a member or friend of class N, and an invented public
814 /// member of B would be a private or protected member of N, or
815 /// [B3] R occurs in a member or friend of a class P derived from N, and an
816 /// invented public member of B would be a private or protected member
818 /// [B4] there exists a class S such that B is a base class of S accessible
819 /// at R and S is a base class of N accessible at R.
821 /// Along a single inheritance path we can restate both of these
824 /// First, we note that M1-4 are equivalent to B1-4 if the member is
825 /// treated as a notional base of its declaring class with inheritance
826 /// access equivalent to the member's access. Therefore we need only
827 /// ask whether a class B is accessible from a class N in context R.
829 /// Let B_1 .. B_n be the inheritance path in question (i.e. where
830 /// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of
831 /// B_i). For i in 1..n, we will calculate ACAB(i), the access to the
832 /// closest accessible base in the path:
833 /// Access(a, b) = (* access on the base specifier from a to b *)
834 /// Merge(a, forbidden) = forbidden
835 /// Merge(a, private) = forbidden
836 /// Merge(a, b) = min(a,b)
837 /// Accessible(c, forbidden) = false
838 /// Accessible(c, private) = (R is c) || IsFriend(c, R)
839 /// Accessible(c, protected) = (R derived from c) || IsFriend(c, R)
840 /// Accessible(c, public) = true
843 /// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in
844 /// if Accessible(B_i, AccessToBase) then public else AccessToBase
846 /// B is an accessible base of N at R iff ACAB(1) = public.
848 /// \param FinalAccess the access of the "final step", or AS_public if
849 /// there is no final step.
850 /// \return null if friendship is dependent
851 static CXXBasePath
*FindBestPath(Sema
&S
,
852 const EffectiveContext
&EC
,
853 AccessTarget
&Target
,
854 AccessSpecifier FinalAccess
,
855 CXXBasePaths
&Paths
) {
856 // Derive the paths to the desired base.
857 const CXXRecordDecl
*Derived
= Target
.getNamingClass();
858 const CXXRecordDecl
*Base
= Target
.getDeclaringClass();
860 // FIXME: fail correctly when there are dependent paths.
861 bool isDerived
= Derived
->isDerivedFrom(const_cast<CXXRecordDecl
*>(Base
),
863 assert(isDerived
&& "derived class not actually derived from base");
866 CXXBasePath
*BestPath
= 0;
868 assert(FinalAccess
!= AS_none
&& "forbidden access after declaring class");
870 bool AnyDependent
= false;
872 // Derive the friend-modified access along each path.
873 for (CXXBasePaths::paths_iterator PI
= Paths
.begin(), PE
= Paths
.end();
875 AccessTarget::SavedInstanceContext _
= Target
.saveInstanceContext();
877 // Walk through the path backwards.
878 AccessSpecifier PathAccess
= FinalAccess
;
879 CXXBasePath::iterator I
= PI
->end(), E
= PI
->begin();
883 assert(PathAccess
!= AS_none
);
885 // If the declaration is a private member of a base class, there
886 // is no level of friendship in derived classes that can make it
888 if (PathAccess
== AS_private
) {
889 PathAccess
= AS_none
;
893 const CXXRecordDecl
*NC
= I
->Class
->getCanonicalDecl();
895 AccessSpecifier BaseAccess
= I
->Base
->getAccessSpecifier();
896 PathAccess
= std::max(PathAccess
, BaseAccess
);
898 switch (HasAccess(S
, EC
, NC
, PathAccess
, Target
)) {
899 case AR_inaccessible
: break;
901 PathAccess
= AS_public
;
903 // Future tests are not against members and so do not have
905 Target
.suppressInstanceContext();
913 // Note that we modify the path's Access field to the
914 // friend-modified access.
915 if (BestPath
== 0 || PathAccess
< BestPath
->Access
) {
917 BestPath
->Access
= PathAccess
;
919 // Short-circuit if we found a public path.
920 if (BestPath
->Access
== AS_public
)
927 assert((!BestPath
|| BestPath
->Access
!= AS_public
) &&
928 "fell out of loop with public path");
930 // We didn't find a public path, but at least one path was subject
931 // to dependent friendship, so delay the check.
938 /// Given that an entity has protected natural access, check whether
939 /// access might be denied because of the protected member access
942 /// \return true if a note was emitted
943 static bool TryDiagnoseProtectedAccess(Sema
&S
, const EffectiveContext
&EC
,
944 AccessTarget
&Target
) {
945 // Only applies to instance accesses.
946 if (!Target
.hasInstanceContext())
948 assert(Target
.isMemberAccess());
949 NamedDecl
*D
= Target
.getTargetDecl();
951 const CXXRecordDecl
*DeclaringClass
= Target
.getDeclaringClass();
952 DeclaringClass
= DeclaringClass
->getCanonicalDecl();
954 for (EffectiveContext::record_iterator
955 I
= EC
.Records
.begin(), E
= EC
.Records
.end(); I
!= E
; ++I
) {
956 const CXXRecordDecl
*ECRecord
= *I
;
957 switch (IsDerivedFromInclusive(ECRecord
, DeclaringClass
)) {
958 case AR_accessible
: break;
959 case AR_inaccessible
: continue;
960 case AR_dependent
: continue;
963 // The effective context is a subclass of the declaring class.
964 // If that class isn't a superclass of the instance context,
965 // then the [class.protected] restriction applies.
967 // To get this exactly right, this might need to be checked more
968 // holistically; it's not necessarily the case that gaining
969 // access here would grant us access overall.
971 const CXXRecordDecl
*InstanceContext
= Target
.resolveInstanceContext(S
);
972 assert(InstanceContext
&& "diagnosing dependent access");
974 switch (IsDerivedFromInclusive(InstanceContext
, ECRecord
)) {
975 case AR_accessible
: continue;
976 case AR_dependent
: continue;
977 case AR_inaccessible
:
978 S
.Diag(D
->getLocation(), diag::note_access_protected_restricted
)
979 << (InstanceContext
!= Target
.getNamingClass()->getCanonicalDecl())
980 << S
.Context
.getTypeDeclType(InstanceContext
)
981 << S
.Context
.getTypeDeclType(ECRecord
);
989 /// Diagnose the path which caused the given declaration or base class
990 /// to become inaccessible.
991 static void DiagnoseAccessPath(Sema
&S
,
992 const EffectiveContext
&EC
,
993 AccessTarget
&Entity
) {
994 AccessSpecifier Access
= Entity
.getAccess();
995 const CXXRecordDecl
*NamingClass
= Entity
.getNamingClass();
996 NamingClass
= NamingClass
->getCanonicalDecl();
998 NamedDecl
*D
= (Entity
.isMemberAccess() ? Entity
.getTargetDecl() : 0);
999 const CXXRecordDecl
*DeclaringClass
= Entity
.getDeclaringClass();
1001 // Easy case: the decl's natural access determined its path access.
1002 // We have to check against AS_private here in case Access is AS_none,
1003 // indicating a non-public member of a private base class.
1004 if (D
&& (Access
== D
->getAccess() || D
->getAccess() == AS_private
)) {
1005 switch (HasAccess(S
, EC
, DeclaringClass
, D
->getAccess(), Entity
)) {
1006 case AR_inaccessible
: {
1007 if (Access
== AS_protected
&&
1008 TryDiagnoseProtectedAccess(S
, EC
, Entity
))
1011 // Find an original declaration.
1012 while (D
->isOutOfLine()) {
1013 NamedDecl
*PrevDecl
= 0;
1014 if (isa
<VarDecl
>(D
))
1015 PrevDecl
= cast
<VarDecl
>(D
)->getPreviousDeclaration();
1016 else if (isa
<FunctionDecl
>(D
))
1017 PrevDecl
= cast
<FunctionDecl
>(D
)->getPreviousDeclaration();
1018 else if (isa
<TypedefDecl
>(D
))
1019 PrevDecl
= cast
<TypedefDecl
>(D
)->getPreviousDeclaration();
1020 else if (isa
<TagDecl
>(D
)) {
1021 if (isa
<RecordDecl
>(D
) && cast
<RecordDecl
>(D
)->isInjectedClassName())
1023 PrevDecl
= cast
<TagDecl
>(D
)->getPreviousDeclaration();
1025 if (!PrevDecl
) break;
1029 CXXRecordDecl
*DeclaringClass
= FindDeclaringClass(D
);
1030 Decl
*ImmediateChild
;
1031 if (D
->getDeclContext() == DeclaringClass
)
1034 DeclContext
*DC
= D
->getDeclContext();
1035 while (DC
->getParent() != DeclaringClass
)
1036 DC
= DC
->getParent();
1037 ImmediateChild
= cast
<Decl
>(DC
);
1040 // Check whether there's an AccessSpecDecl preceding this in the
1041 // chain of the DeclContext.
1042 bool Implicit
= true;
1043 for (CXXRecordDecl::decl_iterator
1044 I
= DeclaringClass
->decls_begin(), E
= DeclaringClass
->decls_end();
1046 if (*I
== ImmediateChild
) break;
1047 if (isa
<AccessSpecDecl
>(*I
)) {
1053 S
.Diag(D
->getLocation(), diag::note_access_natural
)
1054 << (unsigned) (Access
== AS_protected
)
1059 case AR_accessible
: break;
1062 llvm_unreachable("can't diagnose dependent access failures");
1068 CXXBasePath
&Path
= *FindBestPath(S
, EC
, Entity
, AS_public
, Paths
);
1070 CXXBasePath::iterator I
= Path
.end(), E
= Path
.begin();
1074 const CXXBaseSpecifier
*BS
= I
->Base
;
1075 AccessSpecifier BaseAccess
= BS
->getAccessSpecifier();
1077 // If this is public inheritance, or the derived class is a friend,
1079 if (BaseAccess
== AS_public
)
1082 switch (GetFriendKind(S
, EC
, I
->Class
)) {
1083 case AR_accessible
: continue;
1084 case AR_inaccessible
: break;
1086 llvm_unreachable("can't diagnose dependent access failures");
1089 // Check whether this base specifier is the tighest point
1090 // constraining access. We have to check against AS_private for
1091 // the same reasons as above.
1092 if (BaseAccess
== AS_private
|| BaseAccess
>= Access
) {
1094 // We're constrained by inheritance, but we want to say
1095 // "declared private here" if we're diagnosing a hierarchy
1096 // conversion and this is the final step.
1097 unsigned diagnostic
;
1098 if (D
) diagnostic
= diag::note_access_constrained_by_path
;
1099 else if (I
+ 1 == Path
.end()) diagnostic
= diag::note_access_natural
;
1100 else diagnostic
= diag::note_access_constrained_by_path
;
1102 S
.Diag(BS
->getSourceRange().getBegin(), diagnostic
)
1103 << BS
->getSourceRange()
1104 << (BaseAccess
== AS_protected
)
1105 << (BS
->getAccessSpecifierAsWritten() == AS_none
);
1108 S
.Diag(D
->getLocation(), diag::note_field_decl
);
1114 llvm_unreachable("access not apparently constrained by path");
1117 static void DiagnoseBadAccess(Sema
&S
, SourceLocation Loc
,
1118 const EffectiveContext
&EC
,
1119 AccessTarget
&Entity
) {
1120 const CXXRecordDecl
*NamingClass
= Entity
.getNamingClass();
1121 const CXXRecordDecl
*DeclaringClass
= Entity
.getDeclaringClass();
1122 NamedDecl
*D
= (Entity
.isMemberAccess() ? Entity
.getTargetDecl() : 0);
1124 S
.Diag(Loc
, Entity
.getDiag())
1125 << (Entity
.getAccess() == AS_protected
)
1126 << (D
? D
->getDeclName() : DeclarationName())
1127 << S
.Context
.getTypeDeclType(NamingClass
)
1128 << S
.Context
.getTypeDeclType(DeclaringClass
);
1129 DiagnoseAccessPath(S
, EC
, Entity
);
1132 /// Determines whether the accessed entity is accessible. Public members
1133 /// have been weeded out by this point.
1134 static AccessResult
IsAccessible(Sema
&S
,
1135 const EffectiveContext
&EC
,
1136 AccessTarget
&Entity
) {
1137 // Determine the actual naming class.
1138 CXXRecordDecl
*NamingClass
= Entity
.getNamingClass();
1139 while (NamingClass
->isAnonymousStructOrUnion())
1140 NamingClass
= cast
<CXXRecordDecl
>(NamingClass
->getParent());
1141 NamingClass
= NamingClass
->getCanonicalDecl();
1143 AccessSpecifier UnprivilegedAccess
= Entity
.getAccess();
1144 assert(UnprivilegedAccess
!= AS_public
&& "public access not weeded out");
1146 // Before we try to recalculate access paths, try to white-list
1147 // accesses which just trade in on the final step, i.e. accesses
1148 // which don't require [M4] or [B4]. These are by far the most
1149 // common forms of privileged access.
1150 if (UnprivilegedAccess
!= AS_none
) {
1151 switch (HasAccess(S
, EC
, NamingClass
, UnprivilegedAccess
, Entity
)) {
1153 // This is actually an interesting policy decision. We don't
1154 // *have* to delay immediately here: we can do the full access
1155 // calculation in the hope that friendship on some intermediate
1156 // class will make the declaration accessible non-dependently.
1157 // But that's not cheap, and odds are very good (note: assertion
1158 // made without data) that the friend declaration will determine
1160 return AR_dependent
;
1162 case AR_accessible
: return AR_accessible
;
1163 case AR_inaccessible
: break;
1167 AccessTarget::SavedInstanceContext _
= Entity
.saveInstanceContext();
1169 // We lower member accesses to base accesses by pretending that the
1170 // member is a base class of its declaring class.
1171 AccessSpecifier FinalAccess
;
1173 if (Entity
.isMemberAccess()) {
1174 // Determine if the declaration is accessible from EC when named
1175 // in its declaring class.
1176 NamedDecl
*Target
= Entity
.getTargetDecl();
1177 const CXXRecordDecl
*DeclaringClass
= Entity
.getDeclaringClass();
1179 FinalAccess
= Target
->getAccess();
1180 switch (HasAccess(S
, EC
, DeclaringClass
, FinalAccess
, Entity
)) {
1182 FinalAccess
= AS_public
;
1184 case AR_inaccessible
: break;
1185 case AR_dependent
: return AR_dependent
; // see above
1188 if (DeclaringClass
== NamingClass
)
1189 return (FinalAccess
== AS_public
? AR_accessible
: AR_inaccessible
);
1191 Entity
.suppressInstanceContext();
1193 FinalAccess
= AS_public
;
1196 assert(Entity
.getDeclaringClass() != NamingClass
);
1198 // Append the declaration's access if applicable.
1200 CXXBasePath
*Path
= FindBestPath(S
, EC
, Entity
, FinalAccess
, Paths
);
1202 return AR_dependent
;
1204 assert(Path
->Access
<= UnprivilegedAccess
&&
1205 "access along best path worse than direct?");
1206 if (Path
->Access
== AS_public
)
1207 return AR_accessible
;
1208 return AR_inaccessible
;
1211 static void DelayDependentAccess(Sema
&S
,
1212 const EffectiveContext
&EC
,
1214 const AccessTarget
&Entity
) {
1215 assert(EC
.isDependent() && "delaying non-dependent access");
1216 DeclContext
*DC
= EC
.getInnerContext();
1217 assert(DC
->isDependentContext() && "delaying non-dependent access");
1218 DependentDiagnostic::Create(S
.Context
, DC
, DependentDiagnostic::Access
,
1220 Entity
.isMemberAccess(),
1222 Entity
.getTargetDecl(),
1223 Entity
.getNamingClass(),
1224 Entity
.getBaseObjectType(),
1228 /// Checks access to an entity from the given effective context.
1229 static AccessResult
CheckEffectiveAccess(Sema
&S
,
1230 const EffectiveContext
&EC
,
1232 AccessTarget
&Entity
) {
1233 assert(Entity
.getAccess() != AS_public
&& "called for public access!");
1235 switch (IsAccessible(S
, EC
, Entity
)) {
1237 DelayDependentAccess(S
, EC
, Loc
, Entity
);
1238 return AR_dependent
;
1240 case AR_inaccessible
:
1241 if (!Entity
.isQuiet())
1242 DiagnoseBadAccess(S
, Loc
, EC
, Entity
);
1243 return AR_inaccessible
;
1246 return AR_accessible
;
1249 // silence unnecessary warning
1250 llvm_unreachable("invalid access result");
1251 return AR_accessible
;
1254 static Sema::AccessResult
CheckAccess(Sema
&S
, SourceLocation Loc
,
1255 AccessTarget
&Entity
) {
1256 // If the access path is public, it's accessible everywhere.
1257 if (Entity
.getAccess() == AS_public
)
1258 return Sema::AR_accessible
;
1260 if (S
.SuppressAccessChecking
)
1261 return Sema::AR_accessible
;
1263 // If we're currently parsing a top-level declaration, delay
1264 // diagnostics. This is the only case where parsing a declaration
1265 // can actually change our effective context for the purposes of
1267 if (S
.CurContext
->isFileContext() && S
.ParsingDeclDepth
) {
1268 S
.DelayedDiagnostics
.push_back(
1269 DelayedDiagnostic::makeAccess(Loc
, Entity
));
1270 return Sema::AR_delayed
;
1273 EffectiveContext
EC(S
.CurContext
);
1274 switch (CheckEffectiveAccess(S
, EC
, Loc
, Entity
)) {
1275 case AR_accessible
: return Sema::AR_accessible
;
1276 case AR_inaccessible
: return Sema::AR_inaccessible
;
1277 case AR_dependent
: return Sema::AR_dependent
;
1279 llvm_unreachable("falling off end");
1280 return Sema::AR_accessible
;
1283 void Sema::HandleDelayedAccessCheck(DelayedDiagnostic
&DD
, Decl
*Ctx
) {
1284 // Pretend we did this from the context of the newly-parsed
1285 // declaration. If that declaration itself forms a declaration context,
1286 // include it in the effective context so that parameters and return types of
1287 // befriended functions have that function's access priveledges.
1288 DeclContext
*DC
= Ctx
->getDeclContext();
1289 if (isa
<FunctionDecl
>(Ctx
))
1290 DC
= cast
<DeclContext
>(Ctx
);
1291 else if (FunctionTemplateDecl
*FnTpl
= dyn_cast
<FunctionTemplateDecl
>(Ctx
))
1292 DC
= cast
<DeclContext
>(FnTpl
->getTemplatedDecl());
1293 EffectiveContext
EC(DC
);
1295 AccessTarget
Target(DD
.getAccessData());
1297 if (CheckEffectiveAccess(*this, EC
, DD
.Loc
, Target
) == ::AR_inaccessible
)
1298 DD
.Triggered
= true;
1301 void Sema::HandleDependentAccessCheck(const DependentDiagnostic
&DD
,
1302 const MultiLevelTemplateArgumentList
&TemplateArgs
) {
1303 SourceLocation Loc
= DD
.getAccessLoc();
1304 AccessSpecifier Access
= DD
.getAccess();
1306 Decl
*NamingD
= FindInstantiatedDecl(Loc
, DD
.getAccessNamingClass(),
1308 if (!NamingD
) return;
1309 Decl
*TargetD
= FindInstantiatedDecl(Loc
, DD
.getAccessTarget(),
1311 if (!TargetD
) return;
1313 if (DD
.isAccessToMember()) {
1314 CXXRecordDecl
*NamingClass
= cast
<CXXRecordDecl
>(NamingD
);
1315 NamedDecl
*TargetDecl
= cast
<NamedDecl
>(TargetD
);
1316 QualType BaseObjectType
= DD
.getAccessBaseObjectType();
1317 if (!BaseObjectType
.isNull()) {
1318 BaseObjectType
= SubstType(BaseObjectType
, TemplateArgs
, Loc
,
1320 if (BaseObjectType
.isNull()) return;
1323 AccessTarget
Entity(Context
,
1324 AccessTarget::Member
,
1326 DeclAccessPair::make(TargetDecl
, Access
),
1328 Entity
.setDiag(DD
.getDiagnostic());
1329 CheckAccess(*this, Loc
, Entity
);
1331 AccessTarget
Entity(Context
,
1333 cast
<CXXRecordDecl
>(TargetD
),
1334 cast
<CXXRecordDecl
>(NamingD
),
1336 Entity
.setDiag(DD
.getDiagnostic());
1337 CheckAccess(*this, Loc
, Entity
);
1341 Sema::AccessResult
Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr
*E
,
1342 DeclAccessPair Found
) {
1343 if (!getLangOptions().AccessControl
||
1344 !E
->getNamingClass() ||
1345 Found
.getAccess() == AS_public
)
1346 return AR_accessible
;
1348 AccessTarget
Entity(Context
, AccessTarget::Member
, E
->getNamingClass(),
1350 Entity
.setDiag(diag::err_access
) << E
->getSourceRange();
1352 return CheckAccess(*this, E
->getNameLoc(), Entity
);
1355 /// Perform access-control checking on a previously-unresolved member
1356 /// access which has now been resolved to a member.
1357 Sema::AccessResult
Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr
*E
,
1358 DeclAccessPair Found
) {
1359 if (!getLangOptions().AccessControl
||
1360 Found
.getAccess() == AS_public
)
1361 return AR_accessible
;
1363 QualType BaseType
= E
->getBaseType();
1365 BaseType
= BaseType
->getAs
<PointerType
>()->getPointeeType();
1367 AccessTarget
Entity(Context
, AccessTarget::Member
, E
->getNamingClass(),
1369 Entity
.setDiag(diag::err_access
) << E
->getSourceRange();
1371 return CheckAccess(*this, E
->getMemberLoc(), Entity
);
1374 Sema::AccessResult
Sema::CheckDestructorAccess(SourceLocation Loc
,
1375 CXXDestructorDecl
*Dtor
,
1376 const PartialDiagnostic
&PDiag
) {
1377 if (!getLangOptions().AccessControl
)
1378 return AR_accessible
;
1380 // There's never a path involved when checking implicit destructor access.
1381 AccessSpecifier Access
= Dtor
->getAccess();
1382 if (Access
== AS_public
)
1383 return AR_accessible
;
1385 CXXRecordDecl
*NamingClass
= Dtor
->getParent();
1386 AccessTarget
Entity(Context
, AccessTarget::Member
, NamingClass
,
1387 DeclAccessPair::make(Dtor
, Access
),
1389 Entity
.setDiag(PDiag
); // TODO: avoid copy
1391 return CheckAccess(*this, Loc
, Entity
);
1394 /// Checks access to a constructor.
1395 Sema::AccessResult
Sema::CheckConstructorAccess(SourceLocation UseLoc
,
1396 CXXConstructorDecl
*Constructor
,
1397 const InitializedEntity
&Entity
,
1398 AccessSpecifier Access
,
1399 bool IsCopyBindingRefToTemp
) {
1400 if (!getLangOptions().AccessControl
||
1401 Access
== AS_public
)
1402 return AR_accessible
;
1404 CXXRecordDecl
*NamingClass
= Constructor
->getParent();
1405 AccessTarget
AccessEntity(Context
, AccessTarget::Member
, NamingClass
,
1406 DeclAccessPair::make(Constructor
, Access
),
1408 switch (Entity
.getKind()) {
1410 AccessEntity
.setDiag(IsCopyBindingRefToTemp
1411 ? diag::ext_rvalue_to_reference_access_ctor
1412 : diag::err_access_ctor
);
1415 case InitializedEntity::EK_Base
:
1416 AccessEntity
.setDiag(PDiag(diag::err_access_base
)
1417 << Entity
.isInheritedVirtualBase()
1418 << Entity
.getBaseSpecifier()->getType()
1419 << getSpecialMember(Constructor
));
1422 case InitializedEntity::EK_Member
: {
1423 const FieldDecl
*Field
= cast
<FieldDecl
>(Entity
.getDecl());
1424 AccessEntity
.setDiag(PDiag(diag::err_access_field
)
1426 << getSpecialMember(Constructor
));
1432 return CheckAccess(*this, UseLoc
, AccessEntity
);
1435 /// Checks direct (i.e. non-inherited) access to an arbitrary class
1437 Sema::AccessResult
Sema::CheckDirectMemberAccess(SourceLocation UseLoc
,
1439 const PartialDiagnostic
&Diag
) {
1440 AccessSpecifier Access
= Target
->getAccess();
1441 if (!getLangOptions().AccessControl
||
1442 Access
== AS_public
)
1443 return AR_accessible
;
1445 CXXRecordDecl
*NamingClass
= cast
<CXXRecordDecl
>(Target
->getDeclContext());
1446 AccessTarget
Entity(Context
, AccessTarget::Member
, NamingClass
,
1447 DeclAccessPair::make(Target
, Access
),
1449 Entity
.setDiag(Diag
);
1450 return CheckAccess(*this, UseLoc
, Entity
);
1454 /// Checks access to an overloaded operator new or delete.
1455 Sema::AccessResult
Sema::CheckAllocationAccess(SourceLocation OpLoc
,
1456 SourceRange PlacementRange
,
1457 CXXRecordDecl
*NamingClass
,
1458 DeclAccessPair Found
) {
1459 if (!getLangOptions().AccessControl
||
1461 Found
.getAccess() == AS_public
)
1462 return AR_accessible
;
1464 AccessTarget
Entity(Context
, AccessTarget::Member
, NamingClass
, Found
,
1466 Entity
.setDiag(diag::err_access
)
1469 return CheckAccess(*this, OpLoc
, Entity
);
1472 /// Checks access to an overloaded member operator, including
1473 /// conversion operators.
1474 Sema::AccessResult
Sema::CheckMemberOperatorAccess(SourceLocation OpLoc
,
1477 DeclAccessPair Found
) {
1478 if (!getLangOptions().AccessControl
||
1479 Found
.getAccess() == AS_public
)
1480 return AR_accessible
;
1482 const RecordType
*RT
= ObjectExpr
->getType()->getAs
<RecordType
>();
1483 assert(RT
&& "found member operator but object expr not of record type");
1484 CXXRecordDecl
*NamingClass
= cast
<CXXRecordDecl
>(RT
->getDecl());
1486 AccessTarget
Entity(Context
, AccessTarget::Member
, NamingClass
, Found
,
1487 ObjectExpr
->getType());
1488 Entity
.setDiag(diag::err_access
)
1489 << ObjectExpr
->getSourceRange()
1490 << (ArgExpr
? ArgExpr
->getSourceRange() : SourceRange());
1492 return CheckAccess(*this, OpLoc
, Entity
);
1495 Sema::AccessResult
Sema::CheckAddressOfMemberAccess(Expr
*OvlExpr
,
1496 DeclAccessPair Found
) {
1497 if (!getLangOptions().AccessControl
||
1498 Found
.getAccess() == AS_none
||
1499 Found
.getAccess() == AS_public
)
1500 return AR_accessible
;
1502 OverloadExpr
*Ovl
= OverloadExpr::find(OvlExpr
).Expression
;
1503 CXXRecordDecl
*NamingClass
= Ovl
->getNamingClass();
1505 AccessTarget
Entity(Context
, AccessTarget::Member
, NamingClass
, Found
,
1506 Context
.getTypeDeclType(NamingClass
));
1507 Entity
.setDiag(diag::err_access
)
1508 << Ovl
->getSourceRange();
1510 return CheckAccess(*this, Ovl
->getNameLoc(), Entity
);
1513 /// Checks access for a hierarchy conversion.
1515 /// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
1516 /// or a derived-to-base conversion (false)
1517 /// \param ForceCheck true if this check should be performed even if access
1518 /// control is disabled; some things rely on this for semantics
1519 /// \param ForceUnprivileged true if this check should proceed as if the
1520 /// context had no special privileges
1521 /// \param ADK controls the kind of diagnostics that are used
1522 Sema::AccessResult
Sema::CheckBaseClassAccess(SourceLocation AccessLoc
,
1525 const CXXBasePath
&Path
,
1528 bool ForceUnprivileged
) {
1529 if (!ForceCheck
&& !getLangOptions().AccessControl
)
1530 return AR_accessible
;
1532 if (Path
.Access
== AS_public
)
1533 return AR_accessible
;
1535 CXXRecordDecl
*BaseD
, *DerivedD
;
1536 BaseD
= cast
<CXXRecordDecl
>(Base
->getAs
<RecordType
>()->getDecl());
1537 DerivedD
= cast
<CXXRecordDecl
>(Derived
->getAs
<RecordType
>()->getDecl());
1539 AccessTarget
Entity(Context
, AccessTarget::Base
, BaseD
, DerivedD
,
1542 Entity
.setDiag(DiagID
) << Derived
<< Base
;
1544 if (ForceUnprivileged
) {
1545 switch (CheckEffectiveAccess(*this, EffectiveContext(),
1546 AccessLoc
, Entity
)) {
1547 case ::AR_accessible
: return Sema::AR_accessible
;
1548 case ::AR_inaccessible
: return Sema::AR_inaccessible
;
1549 case ::AR_dependent
: return Sema::AR_dependent
;
1551 llvm_unreachable("unexpected result from CheckEffectiveAccess");
1553 return CheckAccess(*this, AccessLoc
, Entity
);
1556 /// Checks access to all the declarations in the given result set.
1557 void Sema::CheckLookupAccess(const LookupResult
&R
) {
1558 assert(getLangOptions().AccessControl
1559 && "performing access check without access control");
1560 assert(R
.getNamingClass() && "performing access check without naming class");
1562 for (LookupResult::iterator I
= R
.begin(), E
= R
.end(); I
!= E
; ++I
) {
1563 if (I
.getAccess() != AS_public
) {
1564 AccessTarget
Entity(Context
, AccessedEntity::Member
,
1565 R
.getNamingClass(), I
.getPair(),
1566 R
.getBaseObjectType());
1567 Entity
.setDiag(diag::err_access
);
1569 CheckAccess(*this, R
.getNameLoc(), Entity
);
1574 void Sema::ActOnStartSuppressingAccessChecks() {
1575 assert(!SuppressAccessChecking
&&
1576 "Tried to start access check suppression when already started.");
1577 SuppressAccessChecking
= true;
1580 void Sema::ActOnStopSuppressingAccessChecks() {
1581 assert(SuppressAccessChecking
&&
1582 "Tried to stop access check suprression when already stopped.");
1583 SuppressAccessChecking
= false;