2009-03-27 13:05:05 +08:00
|
|
|
//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
|
2009-03-27 12:43:36 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file provides Sema routines for C++ access control semantics.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-03-27 12:54:36 +08:00
|
|
|
|
2010-08-26 06:03:47 +08:00
|
|
|
#include "clang/Sema/SemaInternal.h"
|
2009-03-27 14:03:27 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2009-10-07 01:59:45 +08:00
|
|
|
#include "clang/AST/CXXInheritance.h"
|
|
|
|
#include "clang/AST/DeclCXX.h"
|
2010-03-12 09:19:31 +08:00
|
|
|
#include "clang/AST/DeclFriend.h"
|
2011-11-04 03:00:24 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2010-03-24 13:22:00 +08:00
|
|
|
#include "clang/AST/DependentDiagnostic.h"
|
2010-01-27 09:50:18 +08:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Sema/DelayedDiagnostic.h"
|
|
|
|
#include "clang/Sema/Initialization.h"
|
|
|
|
#include "clang/Sema/Lookup.h"
|
2010-01-27 09:50:18 +08:00
|
|
|
|
2009-03-27 12:54:36 +08:00
|
|
|
using namespace clang;
|
2010-08-26 10:13:20 +08:00
|
|
|
using namespace sema;
|
2009-03-27 12:54:36 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
/// A copy of Sema's enum without AR_delayed.
|
|
|
|
enum AccessResult {
|
|
|
|
AR_accessible,
|
|
|
|
AR_inaccessible,
|
|
|
|
AR_dependent
|
|
|
|
};
|
|
|
|
|
2009-03-27 13:05:05 +08:00
|
|
|
/// SetMemberAccessSpecifier - Set the access specifier of a member.
|
|
|
|
/// Returns true on error (when the previous member decl access specifier
|
|
|
|
/// is different from the new member decl access specifier).
|
2009-09-09 23:08:12 +08:00
|
|
|
bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
|
2009-03-27 12:54:36 +08:00
|
|
|
NamedDecl *PrevMemberDecl,
|
|
|
|
AccessSpecifier LexicalAS) {
|
|
|
|
if (!PrevMemberDecl) {
|
|
|
|
// Use the lexical access specifier.
|
|
|
|
MemberDecl->setAccess(LexicalAS);
|
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-27 12:54:36 +08:00
|
|
|
// C++ [class.access.spec]p3: When a member is redeclared its access
|
|
|
|
// specifier must be same as its initial declaration.
|
|
|
|
if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Diag(MemberDecl->getLocation(),
|
|
|
|
diag::err_class_redeclared_with_different_access)
|
2009-03-27 12:54:36 +08:00
|
|
|
<< MemberDecl << LexicalAS;
|
|
|
|
Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
|
|
|
|
<< PrevMemberDecl << PrevMemberDecl->getAccess();
|
2009-12-23 08:37:40 +08:00
|
|
|
|
|
|
|
MemberDecl->setAccess(LexicalAS);
|
2009-03-27 12:54:36 +08:00
|
|
|
return true;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-27 12:54:36 +08:00
|
|
|
MemberDecl->setAccess(PrevMemberDecl->getAccess());
|
|
|
|
return false;
|
|
|
|
}
|
2009-03-27 13:05:05 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
|
|
|
|
DeclContext *DC = D->getDeclContext();
|
|
|
|
|
|
|
|
// This can only happen at top: enum decls only "publish" their
|
|
|
|
// immediate members.
|
|
|
|
if (isa<EnumDecl>(DC))
|
|
|
|
DC = cast<EnumDecl>(DC)->getDeclContext();
|
|
|
|
|
|
|
|
CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
|
|
|
|
while (DeclaringClass->isAnonymousStructOrUnion())
|
|
|
|
DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
|
|
|
|
return DeclaringClass;
|
|
|
|
}
|
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
namespace {
|
|
|
|
struct EffectiveContext {
|
2014-05-26 14:22:03 +08:00
|
|
|
EffectiveContext() : Inner(nullptr), Dependent(false) {}
|
2010-02-10 17:31:12 +08:00
|
|
|
|
2010-03-24 15:46:06 +08:00
|
|
|
explicit EffectiveContext(DeclContext *DC)
|
|
|
|
: Inner(DC),
|
|
|
|
Dependent(DC->isDependentContext()) {
|
2010-03-24 13:22:00 +08:00
|
|
|
|
2013-04-29 18:13:55 +08:00
|
|
|
// C++11 [class.access.nest]p1:
|
2010-03-17 12:58:56 +08:00
|
|
|
// A nested class is a member and as such has the same access
|
|
|
|
// rights as any other member.
|
2013-04-29 18:13:55 +08:00
|
|
|
// C++11 [class.access]p2:
|
2010-03-17 12:58:56 +08:00
|
|
|
// A member of a class can also access all the names to which
|
2010-03-27 14:55:49 +08:00
|
|
|
// the class has access. A local class of a member function
|
|
|
|
// may access the same names that the member function itself
|
|
|
|
// may access.
|
|
|
|
// This almost implies that the privileges of nesting are transitive.
|
|
|
|
// Technically it says nothing about the local classes of non-member
|
|
|
|
// functions (which can gain privileges through friendship), but we
|
|
|
|
// take that as an oversight.
|
|
|
|
while (true) {
|
2012-08-25 06:54:02 +08:00
|
|
|
// We want to add canonical declarations to the EC lists for
|
|
|
|
// simplicity of checking, but we need to walk up through the
|
|
|
|
// actual current DC chain. Otherwise, something like a local
|
|
|
|
// extern or friend which happens to be the canonical
|
|
|
|
// declaration will really mess us up.
|
|
|
|
|
2010-03-27 14:55:49 +08:00
|
|
|
if (isa<CXXRecordDecl>(DC)) {
|
2012-08-25 06:54:02 +08:00
|
|
|
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
|
|
|
|
Records.push_back(Record->getCanonicalDecl());
|
2010-03-27 14:55:49 +08:00
|
|
|
DC = Record->getDeclContext();
|
|
|
|
} else if (isa<FunctionDecl>(DC)) {
|
2012-08-25 06:54:02 +08:00
|
|
|
FunctionDecl *Function = cast<FunctionDecl>(DC);
|
|
|
|
Functions.push_back(Function->getCanonicalDecl());
|
2011-10-10 06:38:36 +08:00
|
|
|
if (Function->getFriendObjectKind())
|
|
|
|
DC = Function->getLexicalDeclContext();
|
|
|
|
else
|
|
|
|
DC = Function->getDeclContext();
|
2010-03-27 14:55:49 +08:00
|
|
|
} else if (DC->isFileContext()) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
DC = DC->getParent();
|
|
|
|
}
|
2010-03-17 12:58:56 +08:00
|
|
|
}
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
bool isDependent() const { return Dependent; }
|
|
|
|
|
2010-03-17 12:58:56 +08:00
|
|
|
bool includesClass(const CXXRecordDecl *R) const {
|
|
|
|
R = R->getCanonicalDecl();
|
|
|
|
return std::find(Records.begin(), Records.end(), R)
|
|
|
|
!= Records.end();
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
|
|
|
|
2010-03-24 15:46:06 +08:00
|
|
|
/// Retrieves the innermost "useful" context. Can be null if we're
|
|
|
|
/// doing access-control without privileges.
|
|
|
|
DeclContext *getInnerContext() const {
|
|
|
|
return Inner;
|
2010-03-24 13:22:00 +08:00
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
|
2010-03-24 13:22:00 +08:00
|
|
|
|
2010-03-24 15:46:06 +08:00
|
|
|
DeclContext *Inner;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<FunctionDecl*, 4> Functions;
|
|
|
|
SmallVector<CXXRecordDecl*, 4> Records;
|
2010-03-24 13:22:00 +08:00
|
|
|
bool Dependent;
|
2010-02-10 17:31:12 +08:00
|
|
|
};
|
2010-04-07 05:38:20 +08:00
|
|
|
|
2010-11-29 06:53:37 +08:00
|
|
|
/// Like sema::AccessedEntity, but kindly lets us scribble all over
|
2010-04-07 05:38:20 +08:00
|
|
|
/// it.
|
2010-08-26 10:13:20 +08:00
|
|
|
struct AccessTarget : public AccessedEntity {
|
|
|
|
AccessTarget(const AccessedEntity &Entity)
|
2010-04-07 05:38:20 +08:00
|
|
|
: AccessedEntity(Entity) {
|
|
|
|
initialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
AccessTarget(ASTContext &Context,
|
|
|
|
MemberNonce _,
|
|
|
|
CXXRecordDecl *NamingClass,
|
|
|
|
DeclAccessPair FoundDecl,
|
2011-09-19 23:10:40 +08:00
|
|
|
QualType BaseObjectType)
|
2012-07-05 01:04:04 +08:00
|
|
|
: AccessedEntity(Context.getDiagAllocator(), Member, NamingClass,
|
|
|
|
FoundDecl, BaseObjectType) {
|
2010-04-07 05:38:20 +08:00
|
|
|
initialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
AccessTarget(ASTContext &Context,
|
|
|
|
BaseNonce _,
|
|
|
|
CXXRecordDecl *BaseClass,
|
|
|
|
CXXRecordDecl *DerivedClass,
|
|
|
|
AccessSpecifier Access)
|
2012-07-05 01:04:04 +08:00
|
|
|
: AccessedEntity(Context.getDiagAllocator(), Base, BaseClass, DerivedClass,
|
|
|
|
Access) {
|
2010-04-07 05:38:20 +08:00
|
|
|
initialize();
|
|
|
|
}
|
|
|
|
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
bool isInstanceMember() const {
|
|
|
|
return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember());
|
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
bool hasInstanceContext() const {
|
|
|
|
return HasInstanceContext;
|
|
|
|
}
|
|
|
|
|
|
|
|
class SavedInstanceContext {
|
|
|
|
public:
|
|
|
|
~SavedInstanceContext() {
|
|
|
|
Target.HasInstanceContext = Has;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2010-04-07 08:41:46 +08:00
|
|
|
friend struct AccessTarget;
|
2010-04-07 05:38:20 +08:00
|
|
|
explicit SavedInstanceContext(AccessTarget &Target)
|
|
|
|
: Target(Target), Has(Target.HasInstanceContext) {}
|
|
|
|
AccessTarget &Target;
|
|
|
|
bool Has;
|
|
|
|
};
|
|
|
|
|
|
|
|
SavedInstanceContext saveInstanceContext() {
|
|
|
|
return SavedInstanceContext(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void suppressInstanceContext() {
|
|
|
|
HasInstanceContext = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const CXXRecordDecl *resolveInstanceContext(Sema &S) const {
|
|
|
|
assert(HasInstanceContext);
|
|
|
|
if (CalculatedInstanceContext)
|
|
|
|
return InstanceContext;
|
|
|
|
|
|
|
|
CalculatedInstanceContext = true;
|
|
|
|
DeclContext *IC = S.computeDeclContext(getBaseObjectType());
|
2014-05-26 14:22:03 +08:00
|
|
|
InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl()
|
|
|
|
: nullptr);
|
2010-04-07 05:38:20 +08:00
|
|
|
return InstanceContext;
|
|
|
|
}
|
|
|
|
|
|
|
|
const CXXRecordDecl *getDeclaringClass() const {
|
|
|
|
return DeclaringClass;
|
|
|
|
}
|
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
/// The "effective" naming class is the canonical non-anonymous
|
|
|
|
/// class containing the actual naming class.
|
|
|
|
const CXXRecordDecl *getEffectiveNamingClass() const {
|
|
|
|
const CXXRecordDecl *namingClass = getNamingClass();
|
|
|
|
while (namingClass->isAnonymousStructOrUnion())
|
|
|
|
namingClass = cast<CXXRecordDecl>(namingClass->getParent());
|
|
|
|
return namingClass->getCanonicalDecl();
|
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
private:
|
|
|
|
void initialize() {
|
|
|
|
HasInstanceContext = (isMemberAccess() &&
|
|
|
|
!getBaseObjectType().isNull() &&
|
|
|
|
getTargetDecl()->isCXXInstanceMember());
|
|
|
|
CalculatedInstanceContext = false;
|
2014-05-26 14:22:03 +08:00
|
|
|
InstanceContext = nullptr;
|
2010-04-07 05:38:20 +08:00
|
|
|
|
|
|
|
if (isMemberAccess())
|
|
|
|
DeclaringClass = FindDeclaringClass(getTargetDecl());
|
|
|
|
else
|
|
|
|
DeclaringClass = getBaseClass();
|
|
|
|
DeclaringClass = DeclaringClass->getCanonicalDecl();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool HasInstanceContext : 1;
|
|
|
|
mutable bool CalculatedInstanceContext : 1;
|
|
|
|
mutable const CXXRecordDecl *InstanceContext;
|
|
|
|
const CXXRecordDecl *DeclaringClass;
|
|
|
|
};
|
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
2009-07-18 22:32:15 +08:00
|
|
|
|
2010-05-04 13:11:27 +08:00
|
|
|
/// Checks whether one class might instantiate to the other.
|
|
|
|
static bool MightInstantiateTo(const CXXRecordDecl *From,
|
|
|
|
const CXXRecordDecl *To) {
|
|
|
|
// Declaration names are always preserved by instantiation.
|
|
|
|
if (From->getDeclName() != To->getDeclName())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext();
|
|
|
|
const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext();
|
|
|
|
if (FromDC == ToDC) return true;
|
|
|
|
if (FromDC->isFileContext() || ToDC->isFileContext()) return false;
|
|
|
|
|
|
|
|
// Be conservative.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
/// Checks whether one class is derived from another, inclusively.
|
|
|
|
/// Properly indicates when it couldn't be determined due to
|
|
|
|
/// dependence.
|
|
|
|
///
|
|
|
|
/// This should probably be donated to AST or at least Sema.
|
|
|
|
static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
|
|
|
|
const CXXRecordDecl *Target) {
|
|
|
|
assert(Derived->getCanonicalDecl() == Derived);
|
|
|
|
assert(Target->getCanonicalDecl() == Target);
|
2010-03-24 17:04:37 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
if (Derived == Target) return AR_accessible;
|
2010-03-24 17:04:37 +08:00
|
|
|
|
2010-05-04 13:11:27 +08:00
|
|
|
bool CheckDependent = Derived->isDependentContext();
|
|
|
|
if (CheckDependent && MightInstantiateTo(Derived, Target))
|
|
|
|
return AR_dependent;
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessResult OnFailure = AR_inaccessible;
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
|
2010-04-07 05:38:20 +08:00
|
|
|
|
|
|
|
while (true) {
|
2011-11-15 07:00:43 +08:00
|
|
|
if (Derived->isDependentContext() && !Derived->hasDefinition())
|
|
|
|
return AR_dependent;
|
|
|
|
|
2014-03-13 23:41:46 +08:00
|
|
|
for (const auto &I : Derived->bases()) {
|
2010-04-07 05:38:20 +08:00
|
|
|
const CXXRecordDecl *RD;
|
|
|
|
|
2014-03-13 23:41:46 +08:00
|
|
|
QualType T = I.getType();
|
2010-04-07 05:38:20 +08:00
|
|
|
if (const RecordType *RT = T->getAs<RecordType>()) {
|
|
|
|
RD = cast<CXXRecordDecl>(RT->getDecl());
|
2010-05-04 13:11:27 +08:00
|
|
|
} else if (const InjectedClassNameType *IT
|
|
|
|
= T->getAs<InjectedClassNameType>()) {
|
|
|
|
RD = IT->getDecl();
|
2010-04-07 05:38:20 +08:00
|
|
|
} else {
|
|
|
|
assert(T->isDependentType() && "non-dependent base wasn't a record?");
|
|
|
|
OnFailure = AR_dependent;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
RD = RD->getCanonicalDecl();
|
|
|
|
if (RD == Target) return AR_accessible;
|
2010-05-04 13:11:27 +08:00
|
|
|
if (CheckDependent && MightInstantiateTo(RD, Target))
|
|
|
|
OnFailure = AR_dependent;
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
Queue.push_back(RD);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Queue.empty()) break;
|
|
|
|
|
2013-08-24 00:11:15 +08:00
|
|
|
Derived = Queue.pop_back_val();
|
2010-04-07 05:38:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return OnFailure;
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
static bool MightInstantiateTo(Sema &S, DeclContext *Context,
|
|
|
|
DeclContext *Friend) {
|
|
|
|
if (Friend == Context)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
assert(!Friend->isDependentContext() &&
|
|
|
|
"can't handle friends with dependent contexts here");
|
|
|
|
|
|
|
|
if (!Context->isDependentContext())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Friend->isFileContext())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// TODO: this is very conservative
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Asks whether the type in 'context' can ever instantiate to the type
|
|
|
|
// in 'friend'.
|
|
|
|
static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {
|
|
|
|
if (Friend == Context)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!Friend->isDependentType() && !Context->isDependentType())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// TODO: this is very conservative.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool MightInstantiateTo(Sema &S,
|
|
|
|
FunctionDecl *Context,
|
|
|
|
FunctionDecl *Friend) {
|
|
|
|
if (Context->getDeclName() != Friend->getDeclName())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!MightInstantiateTo(S,
|
|
|
|
Context->getDeclContext(),
|
|
|
|
Friend->getDeclContext()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
CanQual<FunctionProtoType> FriendTy
|
|
|
|
= S.Context.getCanonicalType(Friend->getType())
|
|
|
|
->getAs<FunctionProtoType>();
|
|
|
|
CanQual<FunctionProtoType> ContextTy
|
|
|
|
= S.Context.getCanonicalType(Context->getType())
|
|
|
|
->getAs<FunctionProtoType>();
|
|
|
|
|
|
|
|
// There isn't any way that I know of to add qualifiers
|
|
|
|
// during instantiation.
|
|
|
|
if (FriendTy.getQualifiers() != ContextTy.getQualifiers())
|
|
|
|
return false;
|
|
|
|
|
2014-01-21 04:26:09 +08:00
|
|
|
if (FriendTy->getNumParams() != ContextTy->getNumParams())
|
2010-03-24 13:22:00 +08:00
|
|
|
return false;
|
|
|
|
|
2014-01-26 00:55:45 +08:00
|
|
|
if (!MightInstantiateTo(S, ContextTy->getReturnType(),
|
|
|
|
FriendTy->getReturnType()))
|
2010-03-24 13:22:00 +08:00
|
|
|
return false;
|
|
|
|
|
2014-01-21 04:26:09 +08:00
|
|
|
for (unsigned I = 0, E = FriendTy->getNumParams(); I != E; ++I)
|
|
|
|
if (!MightInstantiateTo(S, ContextTy->getParamType(I),
|
|
|
|
FriendTy->getParamType(I)))
|
2010-03-24 13:22:00 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool MightInstantiateTo(Sema &S,
|
|
|
|
FunctionTemplateDecl *Context,
|
|
|
|
FunctionTemplateDecl *Friend) {
|
|
|
|
return MightInstantiateTo(S,
|
|
|
|
Context->getTemplatedDecl(),
|
|
|
|
Friend->getTemplatedDecl());
|
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
static AccessResult MatchesFriend(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
const CXXRecordDecl *Friend) {
|
2010-03-18 04:01:29 +08:00
|
|
|
if (EC.includesClass(Friend))
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_accessible;
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
if (EC.isDependent()) {
|
|
|
|
CanQualType FriendTy
|
|
|
|
= S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend));
|
|
|
|
|
|
|
|
for (EffectiveContext::record_iterator
|
|
|
|
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
|
|
|
|
CanQualType ContextTy
|
|
|
|
= S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
|
|
|
|
if (MightInstantiateTo(S, ContextTy, FriendTy))
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_dependent;
|
2010-03-24 13:22:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_inaccessible;
|
2010-03-18 04:01:29 +08:00
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
static AccessResult MatchesFriend(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
CanQualType Friend) {
|
2010-03-24 13:22:00 +08:00
|
|
|
if (const RecordType *RT = Friend->getAs<RecordType>())
|
|
|
|
return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
// TODO: we can do better than this
|
|
|
|
if (Friend->isDependentType())
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_dependent;
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_inaccessible;
|
2010-03-24 13:22:00 +08:00
|
|
|
}
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
/// Determines whether the given friend class template matches
|
|
|
|
/// anything in the effective context.
|
2010-04-07 05:38:20 +08:00
|
|
|
static AccessResult MatchesFriend(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
ClassTemplateDecl *Friend) {
|
|
|
|
AccessResult OnFailure = AR_inaccessible;
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-03-25 14:39:04 +08:00
|
|
|
// Check whether the friend is the template of a class in the
|
|
|
|
// context chain.
|
2011-07-23 18:55:15 +08:00
|
|
|
for (SmallVectorImpl<CXXRecordDecl*>::const_iterator
|
2010-03-24 13:22:00 +08:00
|
|
|
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
|
|
|
|
CXXRecordDecl *Record = *I;
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-03-25 14:39:04 +08:00
|
|
|
// Figure out whether the current class has a template:
|
2010-03-24 13:22:00 +08:00
|
|
|
ClassTemplateDecl *CTD;
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
// A specialization of the template...
|
|
|
|
if (isa<ClassTemplateSpecializationDecl>(Record)) {
|
|
|
|
CTD = cast<ClassTemplateSpecializationDecl>(Record)
|
|
|
|
->getSpecializedTemplate();
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
// ... or the template pattern itself.
|
|
|
|
} else {
|
|
|
|
CTD = Record->getDescribedClassTemplate();
|
|
|
|
if (!CTD) continue;
|
2010-03-18 04:01:29 +08:00
|
|
|
}
|
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
// It's a match.
|
|
|
|
if (Friend == CTD->getCanonicalDecl())
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_accessible;
|
2010-03-24 13:22:00 +08:00
|
|
|
|
2010-03-25 14:39:04 +08:00
|
|
|
// If the context isn't dependent, it can't be a dependent match.
|
|
|
|
if (!EC.isDependent())
|
|
|
|
continue;
|
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
// If the template names don't match, it can't be a dependent
|
2011-05-06 05:57:07 +08:00
|
|
|
// match.
|
|
|
|
if (CTD->getDeclName() != Friend->getDeclName())
|
2010-03-24 13:22:00 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// If the class's context can't instantiate to the friend's
|
|
|
|
// context, it can't be a dependent match.
|
|
|
|
if (!MightInstantiateTo(S, CTD->getDeclContext(),
|
|
|
|
Friend->getDeclContext()))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Otherwise, it's a dependent match.
|
2010-04-07 05:38:20 +08:00
|
|
|
OnFailure = AR_dependent;
|
2010-03-18 04:01:29 +08:00
|
|
|
}
|
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
return OnFailure;
|
|
|
|
}
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
/// Determines whether the given friend function matches anything in
|
|
|
|
/// the effective context.
|
2010-04-07 05:38:20 +08:00
|
|
|
static AccessResult MatchesFriend(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
FunctionDecl *Friend) {
|
|
|
|
AccessResult OnFailure = AR_inaccessible;
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
for (SmallVectorImpl<FunctionDecl*>::const_iterator
|
2010-03-27 14:55:49 +08:00
|
|
|
I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
|
|
|
|
if (Friend == *I)
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_accessible;
|
2010-03-24 13:22:00 +08:00
|
|
|
|
2010-03-27 14:55:49 +08:00
|
|
|
if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
|
2010-04-07 05:38:20 +08:00
|
|
|
OnFailure = AR_dependent;
|
2010-03-27 14:55:49 +08:00
|
|
|
}
|
2010-03-24 13:22:00 +08:00
|
|
|
|
2010-03-27 14:55:49 +08:00
|
|
|
return OnFailure;
|
2010-03-24 13:22:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Determines whether the given friend function template matches
|
|
|
|
/// anything in the effective context.
|
2010-04-07 05:38:20 +08:00
|
|
|
static AccessResult MatchesFriend(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
FunctionTemplateDecl *Friend) {
|
|
|
|
if (EC.Functions.empty()) return AR_inaccessible;
|
2010-03-27 14:55:49 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessResult OnFailure = AR_inaccessible;
|
2010-03-24 13:22:00 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
for (SmallVectorImpl<FunctionDecl*>::const_iterator
|
2010-03-27 14:55:49 +08:00
|
|
|
I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-03-27 14:55:49 +08:00
|
|
|
FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();
|
|
|
|
if (!FTD)
|
|
|
|
FTD = (*I)->getDescribedFunctionTemplate();
|
|
|
|
if (!FTD)
|
|
|
|
continue;
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-03-27 14:55:49 +08:00
|
|
|
FTD = FTD->getCanonicalDecl();
|
2010-03-18 04:01:29 +08:00
|
|
|
|
2010-03-27 14:55:49 +08:00
|
|
|
if (Friend == FTD)
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_accessible;
|
2010-03-27 14:55:49 +08:00
|
|
|
|
|
|
|
if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
|
2010-04-07 05:38:20 +08:00
|
|
|
OnFailure = AR_dependent;
|
2010-03-27 14:55:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return OnFailure;
|
2010-03-18 04:01:29 +08:00
|
|
|
}
|
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
/// Determines whether the given friend declaration matches anything
|
|
|
|
/// in the effective context.
|
2010-04-07 05:38:20 +08:00
|
|
|
static AccessResult MatchesFriend(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
FriendDecl *FriendD) {
|
2010-10-16 14:59:13 +08:00
|
|
|
// Whitelist accesses if there's an invalid or unsupported friend
|
|
|
|
// declaration.
|
|
|
|
if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend())
|
2010-10-13 07:13:28 +08:00
|
|
|
return AR_accessible;
|
|
|
|
|
2010-03-26 02:04:51 +08:00
|
|
|
if (TypeSourceInfo *T = FriendD->getFriendType())
|
|
|
|
return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
|
2010-03-24 13:22:00 +08:00
|
|
|
|
|
|
|
NamedDecl *Friend
|
|
|
|
= cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());
|
|
|
|
|
|
|
|
// FIXME: declarations with dependent or templated scope.
|
|
|
|
|
|
|
|
if (isa<ClassTemplateDecl>(Friend))
|
|
|
|
return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
|
|
|
|
|
|
|
|
if (isa<FunctionTemplateDecl>(Friend))
|
|
|
|
return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
|
|
|
|
|
|
|
|
if (isa<CXXRecordDecl>(Friend))
|
|
|
|
return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
|
|
|
|
|
|
|
|
assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");
|
|
|
|
return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
|
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
static AccessResult GetFriendKind(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
const CXXRecordDecl *Class) {
|
|
|
|
AccessResult OnFailure = AR_inaccessible;
|
2010-03-17 12:58:56 +08:00
|
|
|
|
2010-03-12 09:19:31 +08:00
|
|
|
// Okay, check friends.
|
2014-03-14 01:00:06 +08:00
|
|
|
for (auto *Friend : Class->friends()) {
|
2010-03-18 04:01:29 +08:00
|
|
|
switch (MatchesFriend(S, EC, Friend)) {
|
2010-04-07 05:38:20 +08:00
|
|
|
case AR_accessible:
|
|
|
|
return AR_accessible;
|
2010-03-17 12:58:56 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
case AR_inaccessible:
|
|
|
|
continue;
|
2010-03-12 09:19:31 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
case AR_dependent:
|
|
|
|
OnFailure = AR_dependent;
|
2010-03-18 04:01:29 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-03-12 09:19:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// That's it, give up.
|
2010-03-17 12:58:56 +08:00
|
|
|
return OnFailure;
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
|
|
|
|
2010-08-28 15:56:00 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
/// A helper class for checking for a friend which will grant access
|
|
|
|
/// to a protected instance member.
|
|
|
|
struct ProtectedFriendContext {
|
|
|
|
Sema &S;
|
|
|
|
const EffectiveContext &EC;
|
|
|
|
const CXXRecordDecl *NamingClass;
|
|
|
|
bool CheckDependent;
|
|
|
|
bool EverDependent;
|
|
|
|
|
|
|
|
/// The path down to the current base class.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<const CXXRecordDecl*, 20> CurPath;
|
2010-08-28 15:56:00 +08:00
|
|
|
|
|
|
|
ProtectedFriendContext(Sema &S, const EffectiveContext &EC,
|
|
|
|
const CXXRecordDecl *InstanceContext,
|
|
|
|
const CXXRecordDecl *NamingClass)
|
|
|
|
: S(S), EC(EC), NamingClass(NamingClass),
|
|
|
|
CheckDependent(InstanceContext->isDependentContext() ||
|
|
|
|
NamingClass->isDependentContext()),
|
|
|
|
EverDependent(false) {}
|
|
|
|
|
2010-08-28 16:47:21 +08:00
|
|
|
/// Check classes in the current path for friendship, starting at
|
|
|
|
/// the given index.
|
|
|
|
bool checkFriendshipAlongPath(unsigned I) {
|
|
|
|
assert(I < CurPath.size());
|
|
|
|
for (unsigned E = CurPath.size(); I != E; ++I) {
|
|
|
|
switch (GetFriendKind(S, EC, CurPath[I])) {
|
2010-08-28 15:56:00 +08:00
|
|
|
case AR_accessible: return true;
|
|
|
|
case AR_inaccessible: continue;
|
|
|
|
case AR_dependent: EverDependent = true; continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Perform a search starting at the given class.
|
2010-08-28 16:47:21 +08:00
|
|
|
///
|
|
|
|
/// PrivateDepth is the index of the last (least derived) class
|
|
|
|
/// along the current path such that a notional public member of
|
|
|
|
/// the final class in the path would have access in that class.
|
|
|
|
bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) {
|
2010-08-28 15:56:00 +08:00
|
|
|
// If we ever reach the naming class, check the current path for
|
|
|
|
// friendship. We can also stop recursing because we obviously
|
|
|
|
// won't find the naming class there again.
|
2010-08-28 16:47:21 +08:00
|
|
|
if (Cur == NamingClass)
|
|
|
|
return checkFriendshipAlongPath(PrivateDepth);
|
2010-08-28 15:56:00 +08:00
|
|
|
|
|
|
|
if (CheckDependent && MightInstantiateTo(Cur, NamingClass))
|
|
|
|
EverDependent = true;
|
|
|
|
|
|
|
|
// Recurse into the base classes.
|
2014-03-13 23:41:46 +08:00
|
|
|
for (const auto &I : Cur->bases()) {
|
2010-08-28 16:47:21 +08:00
|
|
|
// If this is private inheritance, then a public member of the
|
|
|
|
// base will not have any access in classes derived from Cur.
|
|
|
|
unsigned BasePrivateDepth = PrivateDepth;
|
2014-03-13 23:41:46 +08:00
|
|
|
if (I.getAccessSpecifier() == AS_private)
|
2010-08-28 16:47:21 +08:00
|
|
|
BasePrivateDepth = CurPath.size() - 1;
|
2010-08-28 15:56:00 +08:00
|
|
|
|
|
|
|
const CXXRecordDecl *RD;
|
|
|
|
|
2014-03-13 23:41:46 +08:00
|
|
|
QualType T = I.getType();
|
2010-08-28 15:56:00 +08:00
|
|
|
if (const RecordType *RT = T->getAs<RecordType>()) {
|
|
|
|
RD = cast<CXXRecordDecl>(RT->getDecl());
|
|
|
|
} else if (const InjectedClassNameType *IT
|
|
|
|
= T->getAs<InjectedClassNameType>()) {
|
|
|
|
RD = IT->getDecl();
|
|
|
|
} else {
|
|
|
|
assert(T->isDependentType() && "non-dependent base wasn't a record?");
|
|
|
|
EverDependent = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recurse. We don't need to clean up if this returns true.
|
2010-08-28 16:47:21 +08:00
|
|
|
CurPath.push_back(RD);
|
|
|
|
if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth))
|
|
|
|
return true;
|
|
|
|
CurPath.pop_back();
|
2010-08-28 15:56:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2010-08-28 16:47:21 +08:00
|
|
|
|
|
|
|
bool findFriendship(const CXXRecordDecl *Cur) {
|
|
|
|
assert(CurPath.empty());
|
|
|
|
CurPath.push_back(Cur);
|
|
|
|
return findFriendship(Cur, 0);
|
|
|
|
}
|
2010-08-28 15:56:00 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Search for a class P that EC is a friend of, under the constraint
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
/// InstanceContext <= P
|
|
|
|
/// if InstanceContext exists, or else
|
|
|
|
/// NamingClass <= P
|
2010-08-28 15:56:00 +08:00
|
|
|
/// and with the additional restriction that a protected member of
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
/// NamingClass would have some natural access in P, which implicitly
|
|
|
|
/// imposes the constraint that P <= NamingClass.
|
2010-08-28 15:56:00 +08:00
|
|
|
///
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
/// This isn't quite the condition laid out in the standard.
|
|
|
|
/// Instead of saying that a notional protected member of NamingClass
|
|
|
|
/// would have to have some natural access in P, it says the actual
|
|
|
|
/// target has to have some natural access in P, which opens up the
|
|
|
|
/// possibility that the target (which is not necessarily a member
|
|
|
|
/// of NamingClass) might be more accessible along some path not
|
|
|
|
/// passing through it. That's really a bad idea, though, because it
|
2010-08-28 15:56:00 +08:00
|
|
|
/// introduces two problems:
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
/// - Most importantly, it breaks encapsulation because you can
|
|
|
|
/// access a forbidden base class's members by directly subclassing
|
|
|
|
/// it elsewhere.
|
|
|
|
/// - It also makes access substantially harder to compute because it
|
2010-08-28 15:56:00 +08:00
|
|
|
/// breaks the hill-climbing algorithm: knowing that the target is
|
|
|
|
/// accessible in some base class would no longer let you change
|
|
|
|
/// the question solely to whether the base class is accessible,
|
|
|
|
/// because the original target might have been more accessible
|
|
|
|
/// because of crazy subclassing.
|
|
|
|
/// So we don't implement that.
|
|
|
|
static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC,
|
|
|
|
const CXXRecordDecl *InstanceContext,
|
|
|
|
const CXXRecordDecl *NamingClass) {
|
2014-05-26 14:22:03 +08:00
|
|
|
assert(InstanceContext == nullptr ||
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
InstanceContext->getCanonicalDecl() == InstanceContext);
|
2010-08-28 15:56:00 +08:00
|
|
|
assert(NamingClass->getCanonicalDecl() == NamingClass);
|
|
|
|
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
// If we don't have an instance context, our constraints give us
|
|
|
|
// that NamingClass <= P <= NamingClass, i.e. P == NamingClass.
|
|
|
|
// This is just the usual friendship check.
|
|
|
|
if (!InstanceContext) return GetFriendKind(S, EC, NamingClass);
|
|
|
|
|
2010-08-28 15:56:00 +08:00
|
|
|
ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass);
|
|
|
|
if (PRC.findFriendship(InstanceContext)) return AR_accessible;
|
|
|
|
if (PRC.EverDependent) return AR_dependent;
|
|
|
|
return AR_inaccessible;
|
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
static AccessResult HasAccess(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
const CXXRecordDecl *NamingClass,
|
|
|
|
AccessSpecifier Access,
|
|
|
|
const AccessTarget &Target) {
|
2010-04-02 08:03:43 +08:00
|
|
|
assert(NamingClass->getCanonicalDecl() == NamingClass &&
|
|
|
|
"declaration should be canonicalized before being passed here");
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
if (Access == AS_public) return AR_accessible;
|
2010-04-02 08:03:43 +08:00
|
|
|
assert(Access == AS_private || Access == AS_protected);
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessResult OnFailure = AR_inaccessible;
|
|
|
|
|
2010-04-02 08:03:43 +08:00
|
|
|
for (EffectiveContext::record_iterator
|
|
|
|
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
|
|
|
|
// All the declarations in EC have been canonicalized, so pointer
|
|
|
|
// equality from this point on will work fine.
|
|
|
|
const CXXRecordDecl *ECRecord = *I;
|
|
|
|
|
|
|
|
// [B2] and [M2]
|
2010-04-07 05:38:20 +08:00
|
|
|
if (Access == AS_private) {
|
|
|
|
if (ECRecord == NamingClass)
|
|
|
|
return AR_accessible;
|
2010-04-02 08:03:43 +08:00
|
|
|
|
2010-05-04 13:11:27 +08:00
|
|
|
if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass))
|
|
|
|
OnFailure = AR_dependent;
|
|
|
|
|
2010-04-02 08:03:43 +08:00
|
|
|
// [B3] and [M3]
|
2010-04-07 05:38:20 +08:00
|
|
|
} else {
|
|
|
|
assert(Access == AS_protected);
|
|
|
|
switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
|
|
|
|
case AR_accessible: break;
|
|
|
|
case AR_inaccessible: continue;
|
|
|
|
case AR_dependent: OnFailure = AR_dependent; continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++ [class.protected]p1:
|
|
|
|
// An additional access check beyond those described earlier in
|
|
|
|
// [class.access] is applied when a non-static data member or
|
|
|
|
// non-static member function is a protected member of its naming
|
|
|
|
// class. As described earlier, access to a protected member is
|
|
|
|
// granted because the reference occurs in a friend or member of
|
|
|
|
// some class C. If the access is to form a pointer to member,
|
|
|
|
// the nested-name-specifier shall name C or a class derived from
|
|
|
|
// C. All other accesses involve a (possibly implicit) object
|
|
|
|
// expression. In this case, the class of the object expression
|
|
|
|
// shall be C or a class derived from C.
|
|
|
|
//
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
// We interpret this as a restriction on [M3].
|
|
|
|
|
|
|
|
// In this part of the code, 'C' is just our context class ECRecord.
|
|
|
|
|
|
|
|
// These rules are different if we don't have an instance context.
|
|
|
|
if (!Target.hasInstanceContext()) {
|
|
|
|
// If it's not an instance member, these restrictions don't apply.
|
|
|
|
if (!Target.isInstanceMember()) return AR_accessible;
|
|
|
|
|
|
|
|
// If it's an instance member, use the pointer-to-member rule
|
|
|
|
// that the naming class has to be derived from the effective
|
|
|
|
// context.
|
|
|
|
|
2012-04-17 20:35:05 +08:00
|
|
|
// Emulate a MSVC bug where the creation of pointer-to-member
|
|
|
|
// to protected member of base class is allowed but only from
|
2012-04-19 15:48:57 +08:00
|
|
|
// static member functions.
|
2014-01-14 20:51:41 +08:00
|
|
|
if (S.getLangOpts().MSVCCompat && !EC.Functions.empty())
|
2012-04-18 11:24:38 +08:00
|
|
|
if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front()))
|
|
|
|
if (MD->isStatic()) return AR_accessible;
|
2012-04-17 20:35:05 +08:00
|
|
|
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
// Despite the standard's confident wording, there is a case
|
|
|
|
// where you can have an instance member that's neither in a
|
|
|
|
// pointer-to-member expression nor in a member access: when
|
|
|
|
// it names a field in an unevaluated context that can't be an
|
|
|
|
// implicit member. Pending clarification, we just apply the
|
|
|
|
// same naming-class restriction here.
|
|
|
|
// FIXME: we're probably not correctly adding the
|
|
|
|
// protected-member restriction when we retroactively convert
|
|
|
|
// an expression to being evaluated.
|
|
|
|
|
|
|
|
// We know that ECRecord derives from NamingClass. The
|
|
|
|
// restriction says to check whether NamingClass derives from
|
|
|
|
// ECRecord, but that's not really necessary: two distinct
|
|
|
|
// classes can't be recursively derived from each other. So
|
|
|
|
// along this path, we just need to check whether the classes
|
|
|
|
// are equal.
|
|
|
|
if (NamingClass == ECRecord) return AR_accessible;
|
|
|
|
|
|
|
|
// Otherwise, this context class tells us nothing; on to the next.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(Target.isInstanceMember());
|
|
|
|
|
|
|
|
const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
|
|
|
|
if (!InstanceContext) {
|
|
|
|
OnFailure = AR_dependent;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
|
|
|
|
case AR_accessible: return AR_accessible;
|
|
|
|
case AR_inaccessible: continue;
|
|
|
|
case AR_dependent: OnFailure = AR_dependent; continue;
|
|
|
|
}
|
|
|
|
}
|
2010-04-02 08:03:43 +08:00
|
|
|
}
|
|
|
|
|
2010-08-28 15:56:00 +08:00
|
|
|
// [M3] and [B3] say that, if the target is protected in N, we grant
|
|
|
|
// access if the access occurs in a friend or member of some class P
|
|
|
|
// that's a subclass of N and where the target has some natural
|
|
|
|
// access in P. The 'member' aspect is easy to handle because P
|
|
|
|
// would necessarily be one of the effective-context records, and we
|
|
|
|
// address that above. The 'friend' aspect is completely ridiculous
|
|
|
|
// to implement because there are no restrictions at all on P
|
|
|
|
// *unless* the [class.protected] restriction applies. If it does,
|
|
|
|
// however, we should ignore whether the naming class is a friend,
|
|
|
|
// and instead rely on whether any potential P is a friend.
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
if (Access == AS_protected && Target.isInstanceMember()) {
|
|
|
|
// Compute the instance context if possible.
|
2014-05-26 14:22:03 +08:00
|
|
|
const CXXRecordDecl *InstanceContext = nullptr;
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
if (Target.hasInstanceContext()) {
|
|
|
|
InstanceContext = Target.resolveInstanceContext(S);
|
|
|
|
if (!InstanceContext) return AR_dependent;
|
|
|
|
}
|
|
|
|
|
2010-08-28 15:56:00 +08:00
|
|
|
switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) {
|
|
|
|
case AR_accessible: return AR_accessible;
|
2010-04-07 05:38:20 +08:00
|
|
|
case AR_inaccessible: return OnFailure;
|
|
|
|
case AR_dependent: return AR_dependent;
|
|
|
|
}
|
2010-08-28 16:10:32 +08:00
|
|
|
llvm_unreachable("impossible friendship kind");
|
2010-04-07 05:38:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (GetFriendKind(S, EC, NamingClass)) {
|
|
|
|
case AR_accessible: return AR_accessible;
|
|
|
|
case AR_inaccessible: return OnFailure;
|
|
|
|
case AR_dependent: return AR_dependent;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Silence bogus warnings
|
|
|
|
llvm_unreachable("impossible friendship kind");
|
2010-04-02 08:03:43 +08:00
|
|
|
}
|
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
/// Finds the best path from the naming class to the declaring class,
|
|
|
|
/// taking friend declarations into account.
|
|
|
|
///
|
2010-04-02 08:03:43 +08:00
|
|
|
/// C++0x [class.access.base]p5:
|
|
|
|
/// A member m is accessible at the point R when named in class N if
|
|
|
|
/// [M1] m as a member of N is public, or
|
|
|
|
/// [M2] m as a member of N is private, and R occurs in a member or
|
|
|
|
/// friend of class N, or
|
|
|
|
/// [M3] m as a member of N is protected, and R occurs in a member or
|
|
|
|
/// friend of class N, or in a member or friend of a class P
|
|
|
|
/// derived from N, where m as a member of P is public, private,
|
|
|
|
/// or protected, or
|
|
|
|
/// [M4] there exists a base class B of N that is accessible at R, and
|
|
|
|
/// m is accessible at R when named in class B.
|
|
|
|
///
|
|
|
|
/// C++0x [class.access.base]p4:
|
|
|
|
/// A base class B of N is accessible at R, if
|
|
|
|
/// [B1] an invented public member of B would be a public member of N, or
|
|
|
|
/// [B2] R occurs in a member or friend of class N, and an invented public
|
|
|
|
/// member of B would be a private or protected member of N, or
|
|
|
|
/// [B3] R occurs in a member or friend of a class P derived from N, and an
|
|
|
|
/// invented public member of B would be a private or protected member
|
|
|
|
/// of P, or
|
|
|
|
/// [B4] there exists a class S such that B is a base class of S accessible
|
|
|
|
/// at R and S is a base class of N accessible at R.
|
|
|
|
///
|
|
|
|
/// Along a single inheritance path we can restate both of these
|
|
|
|
/// iteratively:
|
|
|
|
///
|
|
|
|
/// First, we note that M1-4 are equivalent to B1-4 if the member is
|
|
|
|
/// treated as a notional base of its declaring class with inheritance
|
|
|
|
/// access equivalent to the member's access. Therefore we need only
|
|
|
|
/// ask whether a class B is accessible from a class N in context R.
|
|
|
|
///
|
|
|
|
/// Let B_1 .. B_n be the inheritance path in question (i.e. where
|
|
|
|
/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of
|
|
|
|
/// B_i). For i in 1..n, we will calculate ACAB(i), the access to the
|
|
|
|
/// closest accessible base in the path:
|
|
|
|
/// Access(a, b) = (* access on the base specifier from a to b *)
|
|
|
|
/// Merge(a, forbidden) = forbidden
|
|
|
|
/// Merge(a, private) = forbidden
|
|
|
|
/// Merge(a, b) = min(a,b)
|
|
|
|
/// Accessible(c, forbidden) = false
|
|
|
|
/// Accessible(c, private) = (R is c) || IsFriend(c, R)
|
|
|
|
/// Accessible(c, protected) = (R derived from c) || IsFriend(c, R)
|
|
|
|
/// Accessible(c, public) = true
|
|
|
|
/// ACAB(n) = public
|
|
|
|
/// ACAB(i) =
|
|
|
|
/// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in
|
|
|
|
/// if Accessible(B_i, AccessToBase) then public else AccessToBase
|
|
|
|
///
|
2012-09-27 18:16:10 +08:00
|
|
|
/// B is an accessible base of N at R iff ACAB(1) = public.
|
2010-04-02 08:03:43 +08:00
|
|
|
///
|
2010-04-07 05:38:20 +08:00
|
|
|
/// \param FinalAccess the access of the "final step", or AS_public if
|
2010-03-19 07:49:19 +08:00
|
|
|
/// there is no final step.
|
2010-02-10 17:31:12 +08:00
|
|
|
/// \return null if friendship is dependent
|
|
|
|
static CXXBasePath *FindBestPath(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget &Target,
|
2010-03-19 07:49:19 +08:00
|
|
|
AccessSpecifier FinalAccess,
|
2010-02-10 17:31:12 +08:00
|
|
|
CXXBasePaths &Paths) {
|
|
|
|
// Derive the paths to the desired base.
|
2010-04-07 05:38:20 +08:00
|
|
|
const CXXRecordDecl *Derived = Target.getNamingClass();
|
|
|
|
const CXXRecordDecl *Base = Target.getDeclaringClass();
|
|
|
|
|
|
|
|
// FIXME: fail correctly when there are dependent paths.
|
|
|
|
bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base),
|
|
|
|
Paths);
|
2010-02-10 17:31:12 +08:00
|
|
|
assert(isDerived && "derived class not actually derived from base");
|
|
|
|
(void) isDerived;
|
|
|
|
|
2014-05-26 14:22:03 +08:00
|
|
|
CXXBasePath *BestPath = nullptr;
|
2010-02-10 17:31:12 +08:00
|
|
|
|
2010-03-19 07:49:19 +08:00
|
|
|
assert(FinalAccess != AS_none && "forbidden access after declaring class");
|
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
bool AnyDependent = false;
|
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
// Derive the friend-modified access along each path.
|
|
|
|
for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
|
|
|
|
PI != PE; ++PI) {
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext();
|
2010-02-10 17:31:12 +08:00
|
|
|
|
|
|
|
// Walk through the path backwards.
|
2010-03-19 07:49:19 +08:00
|
|
|
AccessSpecifier PathAccess = FinalAccess;
|
2010-02-10 17:31:12 +08:00
|
|
|
CXXBasePath::iterator I = PI->end(), E = PI->begin();
|
|
|
|
while (I != E) {
|
|
|
|
--I;
|
|
|
|
|
2010-03-19 07:49:19 +08:00
|
|
|
assert(PathAccess != AS_none);
|
|
|
|
|
|
|
|
// If the declaration is a private member of a base class, there
|
|
|
|
// is no level of friendship in derived classes that can make it
|
|
|
|
// accessible.
|
|
|
|
if (PathAccess == AS_private) {
|
|
|
|
PathAccess = AS_none;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
const CXXRecordDecl *NC = I->Class->getCanonicalDecl();
|
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
|
2010-04-02 08:03:43 +08:00
|
|
|
PathAccess = std::max(PathAccess, BaseAccess);
|
2010-04-07 05:38:20 +08:00
|
|
|
|
|
|
|
switch (HasAccess(S, EC, NC, PathAccess, Target)) {
|
|
|
|
case AR_inaccessible: break;
|
|
|
|
case AR_accessible:
|
|
|
|
PathAccess = AS_public;
|
|
|
|
|
|
|
|
// Future tests are not against members and so do not have
|
|
|
|
// instance context.
|
|
|
|
Target.suppressInstanceContext();
|
|
|
|
break;
|
|
|
|
case AR_dependent:
|
2010-04-02 08:03:43 +08:00
|
|
|
AnyDependent = true;
|
|
|
|
goto Next;
|
2009-03-27 14:03:27 +08:00
|
|
|
}
|
|
|
|
}
|
2009-07-18 22:32:15 +08:00
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
// Note that we modify the path's Access field to the
|
|
|
|
// friend-modified access.
|
2014-05-26 14:22:03 +08:00
|
|
|
if (BestPath == nullptr || PathAccess < BestPath->Access) {
|
2010-02-10 17:31:12 +08:00
|
|
|
BestPath = &*PI;
|
|
|
|
BestPath->Access = PathAccess;
|
2010-03-24 13:22:00 +08:00
|
|
|
|
|
|
|
// Short-circuit if we found a public path.
|
|
|
|
if (BestPath->Access == AS_public)
|
|
|
|
return BestPath;
|
2009-03-27 14:03:27 +08:00
|
|
|
}
|
2010-03-24 13:22:00 +08:00
|
|
|
|
|
|
|
Next: ;
|
2009-03-27 14:03:27 +08:00
|
|
|
}
|
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
assert((!BestPath || BestPath->Access != AS_public) &&
|
|
|
|
"fell out of loop with public path");
|
|
|
|
|
|
|
|
// We didn't find a public path, but at least one path was subject
|
|
|
|
// to dependent friendship, so delay the check.
|
|
|
|
if (AnyDependent)
|
2014-05-26 14:22:03 +08:00
|
|
|
return nullptr;
|
2010-03-24 13:22:00 +08:00
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
return BestPath;
|
2009-07-18 22:32:15 +08:00
|
|
|
}
|
|
|
|
|
2010-09-03 12:56:05 +08:00
|
|
|
/// Given that an entity has protected natural access, check whether
|
|
|
|
/// access might be denied because of the protected member access
|
|
|
|
/// restriction.
|
|
|
|
///
|
|
|
|
/// \return true if a note was emitted
|
|
|
|
static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
|
|
|
|
AccessTarget &Target) {
|
|
|
|
// Only applies to instance accesses.
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
if (!Target.isInstanceMember())
|
2010-09-03 12:56:05 +08:00
|
|
|
return false;
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
|
2010-09-03 12:56:05 +08:00
|
|
|
assert(Target.isMemberAccess());
|
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass();
|
2010-09-03 12:56:05 +08:00
|
|
|
|
|
|
|
for (EffectiveContext::record_iterator
|
|
|
|
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
|
|
|
|
const CXXRecordDecl *ECRecord = *I;
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
|
2010-09-03 12:56:05 +08:00
|
|
|
case AR_accessible: break;
|
|
|
|
case AR_inaccessible: continue;
|
|
|
|
case AR_dependent: continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The effective context is a subclass of the declaring class.
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
// Check whether the [class.protected] restriction is limiting
|
|
|
|
// access.
|
2010-09-03 12:56:05 +08:00
|
|
|
|
|
|
|
// To get this exactly right, this might need to be checked more
|
|
|
|
// holistically; it's not necessarily the case that gaining
|
|
|
|
// access here would grant us access overall.
|
|
|
|
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
NamedDecl *D = Target.getTargetDecl();
|
|
|
|
|
|
|
|
// If we don't have an instance context, [class.protected] says the
|
|
|
|
// naming class has to equal the context class.
|
|
|
|
if (!Target.hasInstanceContext()) {
|
|
|
|
// If it does, the restriction doesn't apply.
|
|
|
|
if (NamingClass == ECRecord) continue;
|
|
|
|
|
|
|
|
// TODO: it would be great to have a fixit here, since this is
|
|
|
|
// such an obvious error.
|
|
|
|
S.Diag(D->getLocation(), diag::note_access_protected_restricted_noobject)
|
|
|
|
<< S.Context.getTypeDeclType(ECRecord);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-09-03 12:56:05 +08:00
|
|
|
const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
|
|
|
|
assert(InstanceContext && "diagnosing dependent access");
|
|
|
|
|
|
|
|
switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
|
|
|
|
case AR_accessible: continue;
|
|
|
|
case AR_dependent: continue;
|
|
|
|
case AR_inaccessible:
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Okay, the restriction seems to be what's limiting us.
|
|
|
|
|
|
|
|
// Use a special diagnostic for constructors and destructors.
|
|
|
|
if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D) ||
|
|
|
|
(isa<FunctionTemplateDecl>(D) &&
|
|
|
|
isa<CXXConstructorDecl>(
|
|
|
|
cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) {
|
2014-01-22 15:29:52 +08:00
|
|
|
return S.Diag(D->getLocation(),
|
|
|
|
diag::note_access_protected_restricted_ctordtor)
|
|
|
|
<< isa<CXXDestructorDecl>(D->getAsFunction());
|
2010-09-03 12:56:05 +08:00
|
|
|
}
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
|
|
|
|
// Otherwise, use the generic diagnostic.
|
2014-01-22 15:29:52 +08:00
|
|
|
return S.Diag(D->getLocation(),
|
|
|
|
diag::note_access_protected_restricted_object)
|
|
|
|
<< S.Context.getTypeDeclType(ECRecord);
|
2010-09-03 12:56:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
/// We are unable to access a given declaration due to its direct
|
|
|
|
/// access control; diagnose that.
|
|
|
|
static void diagnoseBadDirectAccess(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
AccessTarget &entity) {
|
|
|
|
assert(entity.isMemberAccess());
|
|
|
|
NamedDecl *D = entity.getTargetDecl();
|
|
|
|
|
|
|
|
if (D->getAccess() == AS_protected &&
|
|
|
|
TryDiagnoseProtectedAccess(S, EC, entity))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Find an original declaration.
|
|
|
|
while (D->isOutOfLine()) {
|
2014-05-26 14:22:03 +08:00
|
|
|
NamedDecl *PrevDecl = nullptr;
|
2013-02-27 08:08:19 +08:00
|
|
|
if (VarDecl *VD = dyn_cast<VarDecl>(D))
|
|
|
|
PrevDecl = VD->getPreviousDecl();
|
|
|
|
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
|
|
|
|
PrevDecl = FD->getPreviousDecl();
|
|
|
|
else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))
|
|
|
|
PrevDecl = TND->getPreviousDecl();
|
|
|
|
else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
|
|
|
if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
|
|
|
|
break;
|
|
|
|
PrevDecl = TD->getPreviousDecl();
|
|
|
|
}
|
|
|
|
if (!PrevDecl) break;
|
|
|
|
D = PrevDecl;
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
|
|
|
|
Decl *ImmediateChild;
|
|
|
|
if (D->getDeclContext() == DeclaringClass)
|
|
|
|
ImmediateChild = D;
|
|
|
|
else {
|
|
|
|
DeclContext *DC = D->getDeclContext();
|
|
|
|
while (DC->getParent() != DeclaringClass)
|
|
|
|
DC = DC->getParent();
|
|
|
|
ImmediateChild = cast<Decl>(DC);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether there's an AccessSpecDecl preceding this in the
|
|
|
|
// chain of the DeclContext.
|
|
|
|
bool isImplicit = true;
|
2014-03-08 03:56:05 +08:00
|
|
|
for (const auto *I : DeclaringClass->decls()) {
|
|
|
|
if (I == ImmediateChild) break;
|
|
|
|
if (isa<AccessSpecDecl>(I)) {
|
2013-02-27 08:08:19 +08:00
|
|
|
isImplicit = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
S.Diag(D->getLocation(), diag::note_access_natural)
|
|
|
|
<< (unsigned) (D->getAccess() == AS_protected)
|
|
|
|
<< isImplicit;
|
|
|
|
}
|
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
/// Diagnose the path which caused the given declaration or base class
|
|
|
|
/// to become inaccessible.
|
|
|
|
static void DiagnoseAccessPath(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
2013-02-27 08:08:19 +08:00
|
|
|
AccessTarget &entity) {
|
|
|
|
// Save the instance context to preserve invariants.
|
|
|
|
AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext();
|
2010-04-02 08:03:43 +08:00
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
// This basically repeats the main algorithm but keeps some more
|
|
|
|
// information.
|
2010-04-02 08:03:43 +08:00
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
// The natural access so far.
|
|
|
|
AccessSpecifier accessSoFar = AS_public;
|
2010-10-20 16:15:06 +08:00
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
// Check whether we have special rights to the declaring class.
|
|
|
|
if (entity.isMemberAccess()) {
|
|
|
|
NamedDecl *D = entity.getTargetDecl();
|
|
|
|
accessSoFar = D->getAccess();
|
|
|
|
const CXXRecordDecl *declaringClass = entity.getDeclaringClass();
|
2010-10-20 16:15:06 +08:00
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) {
|
|
|
|
// If the declaration is accessible when named in its declaring
|
|
|
|
// class, then we must be constrained by the path.
|
|
|
|
case AR_accessible:
|
|
|
|
accessSoFar = AS_public;
|
|
|
|
entity.suppressInstanceContext();
|
|
|
|
break;
|
2009-07-18 22:32:15 +08:00
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
case AR_inaccessible:
|
|
|
|
if (accessSoFar == AS_private ||
|
|
|
|
declaringClass == entity.getEffectiveNamingClass())
|
|
|
|
return diagnoseBadDirectAccess(S, EC, entity);
|
|
|
|
break;
|
2009-07-18 22:32:15 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
case AR_dependent:
|
2013-02-27 08:08:19 +08:00
|
|
|
llvm_unreachable("cannot diagnose dependent access");
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
|
|
|
}
|
2009-03-27 14:03:27 +08:00
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
CXXBasePaths paths;
|
|
|
|
CXXBasePath &path = *FindBestPath(S, EC, entity, accessSoFar, paths);
|
|
|
|
assert(path.Access != AS_public);
|
2009-07-18 22:32:15 +08:00
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
CXXBasePath::iterator i = path.end(), e = path.begin();
|
|
|
|
CXXBasePath::iterator constrainingBase = i;
|
|
|
|
while (i != e) {
|
|
|
|
--i;
|
2009-03-27 14:03:27 +08:00
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
assert(accessSoFar != AS_none && accessSoFar != AS_private);
|
2010-02-10 17:31:12 +08:00
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
// Is the entity accessible when named in the deriving class, as
|
|
|
|
// modified by the base specifier?
|
|
|
|
const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl();
|
|
|
|
const CXXBaseSpecifier *base = i->Base;
|
2010-02-10 17:31:12 +08:00
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
// If the access to this base is worse than the access we have to
|
|
|
|
// the declaration, remember it.
|
|
|
|
AccessSpecifier baseAccess = base->getAccessSpecifier();
|
|
|
|
if (baseAccess > accessSoFar) {
|
|
|
|
constrainingBase = i;
|
|
|
|
accessSoFar = baseAccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) {
|
2010-04-07 05:38:20 +08:00
|
|
|
case AR_inaccessible: break;
|
2013-02-27 08:08:19 +08:00
|
|
|
case AR_accessible:
|
|
|
|
accessSoFar = AS_public;
|
|
|
|
entity.suppressInstanceContext();
|
2014-05-26 14:22:03 +08:00
|
|
|
constrainingBase = nullptr;
|
2013-02-27 08:08:19 +08:00
|
|
|
break;
|
2010-04-07 05:38:20 +08:00
|
|
|
case AR_dependent:
|
2013-02-27 08:08:19 +08:00
|
|
|
llvm_unreachable("cannot diagnose dependent access");
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
// If this was private inheritance, but we don't have access to
|
|
|
|
// the deriving class, we're done.
|
|
|
|
if (accessSoFar == AS_private) {
|
|
|
|
assert(baseAccess == AS_private);
|
|
|
|
assert(constrainingBase == i);
|
|
|
|
break;
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
2009-03-27 14:03:27 +08:00
|
|
|
}
|
2009-07-18 22:32:15 +08:00
|
|
|
|
2013-02-27 08:08:19 +08:00
|
|
|
// If we don't have a constraining base, the access failure must be
|
|
|
|
// due to the original declaration.
|
|
|
|
if (constrainingBase == path.end())
|
|
|
|
return diagnoseBadDirectAccess(S, EC, entity);
|
|
|
|
|
|
|
|
// We're constrained by inheritance, but we want to say
|
|
|
|
// "declared private here" if we're diagnosing a hierarchy
|
|
|
|
// conversion and this is the final step.
|
|
|
|
unsigned diagnostic;
|
|
|
|
if (entity.isMemberAccess() ||
|
|
|
|
constrainingBase + 1 != path.end()) {
|
|
|
|
diagnostic = diag::note_access_constrained_by_path;
|
|
|
|
} else {
|
|
|
|
diagnostic = diag::note_access_natural;
|
|
|
|
}
|
|
|
|
|
|
|
|
const CXXBaseSpecifier *base = constrainingBase->Base;
|
|
|
|
|
|
|
|
S.Diag(base->getSourceRange().getBegin(), diagnostic)
|
|
|
|
<< base->getSourceRange()
|
|
|
|
<< (base->getAccessSpecifier() == AS_protected)
|
|
|
|
<< (base->getAccessSpecifierAsWritten() == AS_none);
|
|
|
|
|
|
|
|
if (entity.isMemberAccess())
|
2014-05-28 20:20:14 +08:00
|
|
|
S.Diag(entity.getTargetDecl()->getLocation(),
|
|
|
|
diag::note_member_declared_at);
|
2009-03-27 13:05:05 +08:00
|
|
|
}
|
2010-01-23 08:46:32 +08:00
|
|
|
|
2010-04-02 08:03:43 +08:00
|
|
|
static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
|
|
|
|
const EffectiveContext &EC,
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget &Entity) {
|
2010-04-02 08:03:43 +08:00
|
|
|
const CXXRecordDecl *NamingClass = Entity.getNamingClass();
|
2010-04-07 05:38:20 +08:00
|
|
|
const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
|
2014-05-26 14:22:03 +08:00
|
|
|
NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : nullptr);
|
2010-02-10 17:31:12 +08:00
|
|
|
|
2010-03-16 13:22:47 +08:00
|
|
|
S.Diag(Loc, Entity.getDiag())
|
2010-04-02 08:03:43 +08:00
|
|
|
<< (Entity.getAccess() == AS_protected)
|
|
|
|
<< (D ? D->getDeclName() : DeclarationName())
|
2010-03-16 13:22:47 +08:00
|
|
|
<< S.Context.getTypeDeclType(NamingClass)
|
|
|
|
<< S.Context.getTypeDeclType(DeclaringClass);
|
2010-04-02 08:03:43 +08:00
|
|
|
DiagnoseAccessPath(S, EC, Entity);
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
2010-01-23 08:46:32 +08:00
|
|
|
|
2011-05-23 11:43:44 +08:00
|
|
|
/// MSVC has a bug where if during an using declaration name lookup,
|
|
|
|
/// the declaration found is unaccessible (private) and that declaration
|
|
|
|
/// was bring into scope via another using declaration whose target
|
|
|
|
/// declaration is accessible (public) then no error is generated.
|
|
|
|
/// Example:
|
|
|
|
/// class A {
|
|
|
|
/// public:
|
|
|
|
/// int f();
|
|
|
|
/// };
|
|
|
|
/// class B : public A {
|
|
|
|
/// private:
|
|
|
|
/// using A::f;
|
|
|
|
/// };
|
|
|
|
/// class C : public B {
|
|
|
|
/// private:
|
|
|
|
/// using B::f;
|
|
|
|
/// };
|
|
|
|
///
|
|
|
|
/// Here, B::f is private so this should fail in Standard C++, but
|
|
|
|
/// because B::f refers to A::f which is public MSVC accepts it.
|
|
|
|
static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
|
|
|
|
SourceLocation AccessLoc,
|
|
|
|
AccessTarget &Entity) {
|
|
|
|
if (UsingShadowDecl *Shadow =
|
|
|
|
dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) {
|
|
|
|
const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl();
|
|
|
|
if (Entity.getTargetDecl()->getAccess() == AS_private &&
|
|
|
|
(OrigDecl->getAccess() == AS_public ||
|
|
|
|
OrigDecl->getAccess() == AS_protected)) {
|
2011-12-30 05:57:33 +08:00
|
|
|
S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible)
|
2011-05-23 11:43:44 +08:00
|
|
|
<< Shadow->getUsingDecl()->getQualifiedNameAsString()
|
|
|
|
<< OrigDecl->getQualifiedNameAsString();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-04-02 08:03:43 +08:00
|
|
|
/// Determines whether the accessed entity is accessible. Public members
|
|
|
|
/// have been weeded out by this point.
|
2010-04-07 05:38:20 +08:00
|
|
|
static AccessResult IsAccessible(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
AccessTarget &Entity) {
|
2010-04-02 08:03:43 +08:00
|
|
|
// Determine the actual naming class.
|
2013-02-27 08:08:19 +08:00
|
|
|
const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass();
|
2010-01-23 08:46:32 +08:00
|
|
|
|
2010-04-02 08:03:43 +08:00
|
|
|
AccessSpecifier UnprivilegedAccess = Entity.getAccess();
|
|
|
|
assert(UnprivilegedAccess != AS_public && "public access not weeded out");
|
2010-01-23 08:46:32 +08:00
|
|
|
|
2010-04-02 08:03:43 +08:00
|
|
|
// Before we try to recalculate access paths, try to white-list
|
|
|
|
// accesses which just trade in on the final step, i.e. accesses
|
|
|
|
// which don't require [M4] or [B4]. These are by far the most
|
2010-04-07 05:38:20 +08:00
|
|
|
// common forms of privileged access.
|
2010-04-02 08:03:43 +08:00
|
|
|
if (UnprivilegedAccess != AS_none) {
|
2010-04-07 05:38:20 +08:00
|
|
|
switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) {
|
|
|
|
case AR_dependent:
|
2010-04-02 08:03:43 +08:00
|
|
|
// This is actually an interesting policy decision. We don't
|
|
|
|
// *have* to delay immediately here: we can do the full access
|
|
|
|
// calculation in the hope that friendship on some intermediate
|
|
|
|
// class will make the declaration accessible non-dependently.
|
|
|
|
// But that's not cheap, and odds are very good (note: assertion
|
|
|
|
// made without data) that the friend declaration will determine
|
|
|
|
// access.
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_dependent;
|
2010-04-02 08:03:43 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
case AR_accessible: return AR_accessible;
|
|
|
|
case AR_inaccessible: break;
|
2010-04-02 08:03:43 +08:00
|
|
|
}
|
|
|
|
}
|
2010-01-23 08:46:32 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext();
|
2010-04-02 08:03:43 +08:00
|
|
|
|
|
|
|
// We lower member accesses to base accesses by pretending that the
|
|
|
|
// member is a base class of its declaring class.
|
|
|
|
AccessSpecifier FinalAccess;
|
2010-02-10 17:31:12 +08:00
|
|
|
|
|
|
|
if (Entity.isMemberAccess()) {
|
2010-04-02 08:03:43 +08:00
|
|
|
// Determine if the declaration is accessible from EC when named
|
|
|
|
// in its declaring class.
|
2010-02-10 17:31:12 +08:00
|
|
|
NamedDecl *Target = Entity.getTargetDecl();
|
2010-04-07 05:38:20 +08:00
|
|
|
const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
|
2010-02-10 17:31:12 +08:00
|
|
|
|
2010-04-02 08:03:43 +08:00
|
|
|
FinalAccess = Target->getAccess();
|
2010-04-07 05:38:20 +08:00
|
|
|
switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) {
|
|
|
|
case AR_accessible:
|
2013-02-22 11:52:55 +08:00
|
|
|
// Target is accessible at EC when named in its declaring class.
|
|
|
|
// We can now hill-climb and simply check whether the declaring
|
|
|
|
// class is accessible as a base of the naming class. This is
|
|
|
|
// equivalent to checking the access of a notional public
|
|
|
|
// member with no instance context.
|
2010-04-07 05:38:20 +08:00
|
|
|
FinalAccess = AS_public;
|
2013-02-22 11:52:55 +08:00
|
|
|
Entity.suppressInstanceContext();
|
2010-04-07 05:38:20 +08:00
|
|
|
break;
|
|
|
|
case AR_inaccessible: break;
|
|
|
|
case AR_dependent: return AR_dependent; // see above
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
2010-01-27 11:50:35 +08:00
|
|
|
|
2010-04-02 08:03:43 +08:00
|
|
|
if (DeclaringClass == NamingClass)
|
2010-04-07 05:38:20 +08:00
|
|
|
return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);
|
2010-04-02 08:03:43 +08:00
|
|
|
} else {
|
|
|
|
FinalAccess = AS_public;
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
2010-01-27 11:50:35 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
assert(Entity.getDeclaringClass() != NamingClass);
|
2010-02-10 17:31:12 +08:00
|
|
|
|
|
|
|
// Append the declaration's access if applicable.
|
|
|
|
CXXBasePaths Paths;
|
2010-04-07 05:38:20 +08:00
|
|
|
CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths);
|
2010-03-24 13:22:00 +08:00
|
|
|
if (!Path)
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_dependent;
|
2010-01-23 08:46:32 +08:00
|
|
|
|
2010-04-02 08:03:43 +08:00
|
|
|
assert(Path->Access <= UnprivilegedAccess &&
|
|
|
|
"access along best path worse than direct?");
|
|
|
|
if (Path->Access == AS_public)
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_accessible;
|
|
|
|
return AR_inaccessible;
|
2010-03-24 13:22:00 +08:00
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
static void DelayDependentAccess(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
SourceLocation Loc,
|
|
|
|
const AccessTarget &Entity) {
|
2010-03-24 13:22:00 +08:00
|
|
|
assert(EC.isDependent() && "delaying non-dependent access");
|
2010-03-24 15:46:06 +08:00
|
|
|
DeclContext *DC = EC.getInnerContext();
|
2010-03-24 13:22:00 +08:00
|
|
|
assert(DC->isDependentContext() && "delaying non-dependent access");
|
|
|
|
DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
|
|
|
|
Loc,
|
|
|
|
Entity.isMemberAccess(),
|
|
|
|
Entity.getAccess(),
|
|
|
|
Entity.getTargetDecl(),
|
|
|
|
Entity.getNamingClass(),
|
2010-04-07 05:38:20 +08:00
|
|
|
Entity.getBaseObjectType(),
|
2010-03-24 13:22:00 +08:00
|
|
|
Entity.getDiag());
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks access to an entity from the given effective context.
|
2010-04-07 05:38:20 +08:00
|
|
|
static AccessResult CheckEffectiveAccess(Sema &S,
|
|
|
|
const EffectiveContext &EC,
|
|
|
|
SourceLocation Loc,
|
|
|
|
AccessTarget &Entity) {
|
2010-04-02 08:03:43 +08:00
|
|
|
assert(Entity.getAccess() != AS_public && "called for public access!");
|
2010-01-23 08:46:32 +08:00
|
|
|
|
2010-04-02 08:03:43 +08:00
|
|
|
switch (IsAccessible(S, EC, Entity)) {
|
2010-04-07 05:38:20 +08:00
|
|
|
case AR_dependent:
|
|
|
|
DelayDependentAccess(S, EC, Loc, Entity);
|
|
|
|
return AR_dependent;
|
2010-03-24 13:22:00 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
case AR_inaccessible:
|
2014-02-08 10:40:20 +08:00
|
|
|
if (S.getLangOpts().MSVCCompat &&
|
|
|
|
IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))
|
|
|
|
return AR_accessible;
|
2010-04-02 08:03:43 +08:00
|
|
|
if (!Entity.isQuiet())
|
|
|
|
DiagnoseBadAccess(S, Loc, EC, Entity);
|
2010-04-07 05:38:20 +08:00
|
|
|
return AR_inaccessible;
|
2010-01-23 08:46:32 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
case AR_accessible:
|
|
|
|
return AR_accessible;
|
2010-04-02 08:03:43 +08:00
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
// silence unnecessary warning
|
|
|
|
llvm_unreachable("invalid access result");
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
2010-01-23 08:46:32 +08:00
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget &Entity) {
|
2010-02-10 17:31:12 +08:00
|
|
|
// If the access path is public, it's accessible everywhere.
|
|
|
|
if (Entity.getAccess() == AS_public)
|
|
|
|
return Sema::AR_accessible;
|
2010-01-23 08:46:32 +08:00
|
|
|
|
2011-02-14 15:13:47 +08:00
|
|
|
// If we're currently parsing a declaration, we may need to delay
|
|
|
|
// access control checking, because our effective context might be
|
|
|
|
// different based on what the declaration comes out as.
|
|
|
|
//
|
|
|
|
// For example, we might be parsing a declaration with a scope
|
|
|
|
// specifier, like this:
|
|
|
|
// A::private_type A::foo() { ... }
|
|
|
|
//
|
|
|
|
// Or we might be parsing something that will turn out to be a friend:
|
|
|
|
// void foo(A::private_type);
|
|
|
|
// void B::foo(A::private_type);
|
|
|
|
if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
|
|
|
|
S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity));
|
2010-02-10 17:31:12 +08:00
|
|
|
return Sema::AR_delayed;
|
2010-01-23 08:46:32 +08:00
|
|
|
}
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
EffectiveContext EC(S.CurContext);
|
|
|
|
switch (CheckEffectiveAccess(S, EC, Loc, Entity)) {
|
|
|
|
case AR_accessible: return Sema::AR_accessible;
|
|
|
|
case AR_inaccessible: return Sema::AR_inaccessible;
|
|
|
|
case AR_dependent: return Sema::AR_dependent;
|
|
|
|
}
|
|
|
|
llvm_unreachable("falling off end");
|
2010-01-23 08:46:32 +08:00
|
|
|
}
|
|
|
|
|
2013-04-29 18:13:55 +08:00
|
|
|
void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {
|
2011-02-16 06:51:53 +08:00
|
|
|
// Access control for names used in the declarations of functions
|
|
|
|
// and function templates should normally be evaluated in the context
|
|
|
|
// of the declaration, just in case it's a friend of something.
|
|
|
|
// However, this does not apply to local extern declarations.
|
|
|
|
|
2013-04-29 18:13:55 +08:00
|
|
|
DeclContext *DC = D->getDeclContext();
|
2013-12-11 11:35:27 +08:00
|
|
|
if (D->isLocalExternDecl()) {
|
|
|
|
DC = D->getLexicalDeclContext();
|
|
|
|
} else if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) {
|
|
|
|
DC = FN;
|
2013-04-29 18:13:55 +08:00
|
|
|
} else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
|
|
|
|
DC = cast<DeclContext>(TD->getTemplatedDecl());
|
2011-02-16 06:51:53 +08:00
|
|
|
}
|
|
|
|
|
2010-04-18 16:23:21 +08:00
|
|
|
EffectiveContext EC(DC);
|
2010-01-27 11:50:35 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget Target(DD.getAccessData());
|
|
|
|
|
|
|
|
if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible)
|
2010-01-27 11:50:35 +08:00
|
|
|
DD.Triggered = true;
|
|
|
|
}
|
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
|
|
|
|
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
|
|
|
SourceLocation Loc = DD.getAccessLoc();
|
|
|
|
AccessSpecifier Access = DD.getAccess();
|
|
|
|
|
|
|
|
Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(),
|
|
|
|
TemplateArgs);
|
|
|
|
if (!NamingD) return;
|
|
|
|
Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(),
|
|
|
|
TemplateArgs);
|
|
|
|
if (!TargetD) return;
|
|
|
|
|
|
|
|
if (DD.isAccessToMember()) {
|
2010-04-07 05:38:20 +08:00
|
|
|
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD);
|
|
|
|
NamedDecl *TargetDecl = cast<NamedDecl>(TargetD);
|
|
|
|
QualType BaseObjectType = DD.getAccessBaseObjectType();
|
|
|
|
if (!BaseObjectType.isNull()) {
|
|
|
|
BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc,
|
|
|
|
DeclarationName());
|
|
|
|
if (BaseObjectType.isNull()) return;
|
|
|
|
}
|
|
|
|
|
|
|
|
AccessTarget Entity(Context,
|
|
|
|
AccessTarget::Member,
|
|
|
|
NamingClass,
|
|
|
|
DeclAccessPair::make(TargetDecl, Access),
|
|
|
|
BaseObjectType);
|
2010-03-24 13:22:00 +08:00
|
|
|
Entity.setDiag(DD.getDiagnostic());
|
|
|
|
CheckAccess(*this, Loc, Entity);
|
|
|
|
} else {
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget Entity(Context,
|
|
|
|
AccessTarget::Base,
|
|
|
|
cast<CXXRecordDecl>(TargetD),
|
|
|
|
cast<CXXRecordDecl>(NamingD),
|
|
|
|
Access);
|
2010-03-24 13:22:00 +08:00
|
|
|
Entity.setDiag(DD.getDiagnostic());
|
|
|
|
CheckAccess(*this, Loc, Entity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
|
2010-03-19 15:35:19 +08:00
|
|
|
DeclAccessPair Found) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().AccessControl ||
|
2010-03-16 13:22:47 +08:00
|
|
|
!E->getNamingClass() ||
|
2010-03-19 15:35:19 +08:00
|
|
|
Found.getAccess() == AS_public)
|
2010-02-10 17:31:12 +08:00
|
|
|
return AR_accessible;
|
2010-01-27 09:50:18 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
|
|
|
|
Found, QualType());
|
2010-03-16 13:22:47 +08:00
|
|
|
Entity.setDiag(diag::err_access) << E->getSourceRange();
|
|
|
|
|
|
|
|
return CheckAccess(*this, E->getNameLoc(), Entity);
|
2010-01-27 09:50:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Perform access-control checking on a previously-unresolved member
|
|
|
|
/// access which has now been resolved to a member.
|
2010-02-10 17:31:12 +08:00
|
|
|
Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
|
2010-03-19 15:35:19 +08:00
|
|
|
DeclAccessPair Found) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().AccessControl ||
|
2010-03-19 15:35:19 +08:00
|
|
|
Found.getAccess() == AS_public)
|
2010-02-10 17:31:12 +08:00
|
|
|
return AR_accessible;
|
2010-01-27 09:50:18 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
QualType BaseType = E->getBaseType();
|
|
|
|
if (E->isArrow())
|
|
|
|
BaseType = BaseType->getAs<PointerType>()->getPointeeType();
|
|
|
|
|
|
|
|
AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
|
|
|
|
Found, BaseType);
|
2010-03-16 13:22:47 +08:00
|
|
|
Entity.setDiag(diag::err_access) << E->getSourceRange();
|
|
|
|
|
|
|
|
return CheckAccess(*this, E->getMemberLoc(), Entity);
|
2010-01-27 09:50:18 +08:00
|
|
|
}
|
|
|
|
|
2012-04-10 04:53:23 +08:00
|
|
|
/// Is the given special member function accessible for the purposes of
|
|
|
|
/// deciding whether to define a special member function as deleted?
|
|
|
|
bool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl,
|
|
|
|
AccessSpecifier access,
|
|
|
|
QualType objectType) {
|
|
|
|
// Fast path.
|
|
|
|
if (access == AS_public || !getLangOpts().AccessControl) return true;
|
|
|
|
|
|
|
|
AccessTarget entity(Context, AccessTarget::Member, decl->getParent(),
|
|
|
|
DeclAccessPair::make(decl, access), objectType);
|
|
|
|
|
|
|
|
// Suppress diagnostics.
|
|
|
|
entity.setDiag(PDiag());
|
|
|
|
|
|
|
|
switch (CheckAccess(*this, SourceLocation(), entity)) {
|
|
|
|
case AR_accessible: return true;
|
|
|
|
case AR_inaccessible: return false;
|
|
|
|
case AR_dependent: llvm_unreachable("dependent for =delete computation");
|
|
|
|
case AR_delayed: llvm_unreachable("cannot delay =delete computation");
|
|
|
|
}
|
|
|
|
llvm_unreachable("bad access result");
|
|
|
|
}
|
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
|
2010-03-16 13:22:47 +08:00
|
|
|
CXXDestructorDecl *Dtor,
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
const PartialDiagnostic &PDiag,
|
|
|
|
QualType ObjectTy) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().AccessControl)
|
2010-02-10 17:31:12 +08:00
|
|
|
return AR_accessible;
|
2010-02-02 16:45:54 +08:00
|
|
|
|
2010-03-16 13:22:47 +08:00
|
|
|
// There's never a path involved when checking implicit destructor access.
|
2010-02-02 16:45:54 +08:00
|
|
|
AccessSpecifier Access = Dtor->getAccess();
|
|
|
|
if (Access == AS_public)
|
2010-02-10 17:31:12 +08:00
|
|
|
return AR_accessible;
|
2010-02-02 16:45:54 +08:00
|
|
|
|
2010-03-16 13:22:47 +08:00
|
|
|
CXXRecordDecl *NamingClass = Dtor->getParent();
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass);
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
|
|
|
|
DeclAccessPair::make(Dtor, Access),
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
ObjectTy);
|
2010-03-16 13:22:47 +08:00
|
|
|
Entity.setDiag(PDiag); // TODO: avoid copy
|
|
|
|
|
|
|
|
return CheckAccess(*this, Loc, Entity);
|
2010-02-02 16:45:54 +08:00
|
|
|
}
|
|
|
|
|
2010-02-01 11:16:54 +08:00
|
|
|
/// Checks access to a constructor.
|
2010-02-10 17:31:12 +08:00
|
|
|
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
|
2010-06-07 23:58:05 +08:00
|
|
|
CXXConstructorDecl *Constructor,
|
|
|
|
const InitializedEntity &Entity,
|
|
|
|
AccessSpecifier Access,
|
|
|
|
bool IsCopyBindingRefToTemp) {
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
if (!getLangOpts().AccessControl || Access == AS_public)
|
2010-02-10 17:31:12 +08:00
|
|
|
return AR_accessible;
|
2010-02-01 11:16:54 +08:00
|
|
|
|
2011-06-10 11:50:41 +08:00
|
|
|
PartialDiagnostic PD(PDiag());
|
2010-04-22 02:47:17 +08:00
|
|
|
switch (Entity.getKind()) {
|
|
|
|
default:
|
2011-06-10 11:50:41 +08:00
|
|
|
PD = PDiag(IsCopyBindingRefToTemp
|
|
|
|
? diag::ext_rvalue_to_reference_access_ctor
|
|
|
|
: diag::err_access_ctor);
|
|
|
|
|
2010-04-22 02:47:17 +08:00
|
|
|
break;
|
|
|
|
|
2010-04-22 13:40:53 +08:00
|
|
|
case InitializedEntity::EK_Base:
|
2011-06-10 11:50:41 +08:00
|
|
|
PD = PDiag(diag::err_access_base_ctor);
|
|
|
|
PD << Entity.isInheritedVirtualBase()
|
|
|
|
<< Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor);
|
2010-04-22 02:47:17 +08:00
|
|
|
break;
|
2010-04-22 13:40:53 +08:00
|
|
|
|
2010-04-22 04:28:29 +08:00
|
|
|
case InitializedEntity::EK_Member: {
|
|
|
|
const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());
|
2011-06-10 11:50:41 +08:00
|
|
|
PD = PDiag(diag::err_access_field_ctor);
|
|
|
|
PD << Field->getType() << getSpecialMember(Constructor);
|
2010-04-22 04:28:29 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-03-16 13:22:47 +08:00
|
|
|
|
2012-02-16 00:57:26 +08:00
|
|
|
case InitializedEntity::EK_LambdaCapture: {
|
2013-12-05 09:40:41 +08:00
|
|
|
StringRef VarName = Entity.getCapturedVarName();
|
2012-02-16 00:57:26 +08:00
|
|
|
PD = PDiag(diag::err_access_lambda_capture);
|
2013-12-05 09:40:41 +08:00
|
|
|
PD << VarName << Entity.getType() << getSpecialMember(Constructor);
|
2012-02-16 00:57:26 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-04-22 03:52:01 +08:00
|
|
|
}
|
|
|
|
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
return CheckConstructorAccess(UseLoc, Constructor, Entity, Access, PD);
|
2011-06-10 11:50:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks access to a constructor.
|
|
|
|
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
|
|
|
|
CXXConstructorDecl *Constructor,
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
const InitializedEntity &Entity,
|
2011-06-10 11:50:41 +08:00
|
|
|
AccessSpecifier Access,
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
const PartialDiagnostic &PD) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().AccessControl ||
|
2011-06-10 11:50:41 +08:00
|
|
|
Access == AS_public)
|
|
|
|
return AR_accessible;
|
|
|
|
|
|
|
|
CXXRecordDecl *NamingClass = Constructor->getParent();
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
|
|
|
|
// Initializing a base sub-object is an instance method call on an
|
|
|
|
// object of the derived class. Otherwise, we have an instance method
|
|
|
|
// call on an object of the constructed type.
|
|
|
|
CXXRecordDecl *ObjectClass;
|
|
|
|
if (Entity.getKind() == InitializedEntity::EK_Base) {
|
|
|
|
ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent();
|
|
|
|
} else {
|
|
|
|
ObjectClass = NamingClass;
|
|
|
|
}
|
|
|
|
|
2011-06-10 11:50:41 +08:00
|
|
|
AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
|
|
|
|
DeclAccessPair::make(Constructor, Access),
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
Context.getTypeDeclType(ObjectClass));
|
2011-06-10 11:50:41 +08:00
|
|
|
AccessEntity.setDiag(PD);
|
|
|
|
|
2010-04-22 02:47:17 +08:00
|
|
|
return CheckAccess(*this, UseLoc, AccessEntity);
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
}
|
2010-02-01 11:16:54 +08:00
|
|
|
|
2010-03-18 16:19:33 +08:00
|
|
|
/// Checks access to an overloaded operator new or delete.
|
|
|
|
Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
|
|
|
|
SourceRange PlacementRange,
|
|
|
|
CXXRecordDecl *NamingClass,
|
2011-05-13 06:46:25 +08:00
|
|
|
DeclAccessPair Found,
|
|
|
|
bool Diagnose) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().AccessControl ||
|
2010-03-18 16:19:33 +08:00
|
|
|
!NamingClass ||
|
2010-03-19 15:35:19 +08:00
|
|
|
Found.getAccess() == AS_public)
|
2010-03-18 16:19:33 +08:00
|
|
|
return AR_accessible;
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
|
|
|
|
QualType());
|
2011-05-13 06:46:25 +08:00
|
|
|
if (Diagnose)
|
|
|
|
Entity.setDiag(diag::err_access)
|
|
|
|
<< PlacementRange;
|
2010-03-18 16:19:33 +08:00
|
|
|
|
|
|
|
return CheckAccess(*this, OpLoc, Entity);
|
|
|
|
}
|
|
|
|
|
2013-07-19 11:13:43 +08:00
|
|
|
/// \brief Checks access to a member.
|
|
|
|
Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc,
|
|
|
|
CXXRecordDecl *NamingClass,
|
2013-10-01 10:44:48 +08:00
|
|
|
DeclAccessPair Found) {
|
2013-07-19 11:13:43 +08:00
|
|
|
if (!getLangOpts().AccessControl ||
|
|
|
|
!NamingClass ||
|
2013-10-01 10:44:48 +08:00
|
|
|
Found.getAccess() == AS_public)
|
2013-07-19 11:13:43 +08:00
|
|
|
return AR_accessible;
|
|
|
|
|
|
|
|
AccessTarget Entity(Context, AccessTarget::Member, NamingClass,
|
2013-10-01 10:44:48 +08:00
|
|
|
Found, QualType());
|
2013-07-19 11:13:43 +08:00
|
|
|
|
|
|
|
return CheckAccess(*this, UseLoc, Entity);
|
|
|
|
}
|
|
|
|
|
2010-02-01 11:16:54 +08:00
|
|
|
/// Checks access to an overloaded member operator, including
|
|
|
|
/// conversion operators.
|
2010-02-10 17:31:12 +08:00
|
|
|
Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
|
|
|
|
Expr *ObjectExpr,
|
2010-03-16 13:22:47 +08:00
|
|
|
Expr *ArgExpr,
|
2010-03-19 15:35:19 +08:00
|
|
|
DeclAccessPair Found) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().AccessControl ||
|
2010-03-19 15:35:19 +08:00
|
|
|
Found.getAccess() == AS_public)
|
2010-02-10 17:31:12 +08:00
|
|
|
return AR_accessible;
|
2010-01-28 09:42:12 +08:00
|
|
|
|
2011-09-21 16:36:56 +08:00
|
|
|
const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>();
|
2010-01-28 09:42:12 +08:00
|
|
|
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
|
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
|
|
|
|
ObjectExpr->getType());
|
2010-03-16 13:22:47 +08:00
|
|
|
Entity.setDiag(diag::err_access)
|
|
|
|
<< ObjectExpr->getSourceRange()
|
|
|
|
<< (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
|
|
|
|
|
|
|
|
return CheckAccess(*this, OpLoc, Entity);
|
2010-02-10 17:31:12 +08:00
|
|
|
}
|
2010-01-28 09:42:12 +08:00
|
|
|
|
2012-08-10 11:15:35 +08:00
|
|
|
/// Checks access to the target of a friend declaration.
|
|
|
|
Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
|
2014-01-22 15:29:52 +08:00
|
|
|
assert(isa<CXXMethodDecl>(target->getAsFunction()));
|
2012-08-10 11:15:35 +08:00
|
|
|
|
|
|
|
// Friendship lookup is a redeclaration lookup, so there's never an
|
|
|
|
// inheritance path modifying access.
|
|
|
|
AccessSpecifier access = target->getAccess();
|
|
|
|
|
|
|
|
if (!getLangOpts().AccessControl || access == AS_public)
|
|
|
|
return AR_accessible;
|
|
|
|
|
2014-01-22 15:53:08 +08:00
|
|
|
CXXMethodDecl *method = cast<CXXMethodDecl>(target->getAsFunction());
|
2012-08-10 11:15:35 +08:00
|
|
|
assert(method->getQualifier());
|
|
|
|
|
|
|
|
AccessTarget entity(Context, AccessTarget::Member,
|
|
|
|
cast<CXXRecordDecl>(target->getDeclContext()),
|
|
|
|
DeclAccessPair::make(target, access),
|
|
|
|
/*no instance context*/ QualType());
|
|
|
|
entity.setDiag(diag::err_access_friend_function)
|
|
|
|
<< method->getQualifierLoc().getSourceRange();
|
|
|
|
|
|
|
|
// We need to bypass delayed-diagnostics because we might be called
|
|
|
|
// while the ParsingDeclarator is active.
|
|
|
|
EffectiveContext EC(CurContext);
|
|
|
|
switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) {
|
|
|
|
case AR_accessible: return Sema::AR_accessible;
|
|
|
|
case AR_inaccessible: return Sema::AR_inaccessible;
|
|
|
|
case AR_dependent: return Sema::AR_dependent;
|
|
|
|
}
|
|
|
|
llvm_unreachable("falling off end");
|
|
|
|
}
|
|
|
|
|
2010-03-31 05:47:33 +08:00
|
|
|
Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
|
|
|
|
DeclAccessPair Found) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().AccessControl ||
|
2010-03-31 06:20:00 +08:00
|
|
|
Found.getAccess() == AS_none ||
|
2010-03-31 05:47:33 +08:00
|
|
|
Found.getAccess() == AS_public)
|
|
|
|
return AR_accessible;
|
|
|
|
|
2010-08-27 17:08:28 +08:00
|
|
|
OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression;
|
2010-04-23 02:44:12 +08:00
|
|
|
CXXRecordDecl *NamingClass = Ovl->getNamingClass();
|
2010-03-31 05:47:33 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
|
Fix several problems with protected access control:
- The [class.protected] restriction is non-trivial for any instance
member, even if the access lacks an object (for example, if it's
a pointer-to-member constant). In this case, it is equivalent to
requiring the naming class to equal the context class.
- The [class.protected] restriction applies to accesses to constructors
and destructors. A protected constructor or destructor can only be
used to create or destroy a base subobject, as a direct result.
- Several places were dropping or misapplying object information.
The standard could really be much clearer about what the object type is
supposed to be in some of these accesses. Usually it's easy enough to
find a reasonable answer, but still, the standard makes a very confident
statement about accesses to instance members only being possible in
either pointer-to-member literals or member access expressions, which
just completely ignores concepts like constructor and destructor
calls, using declarations, unevaluated field references, etc.
llvm-svn: 154248
2012-04-07 11:04:20 +08:00
|
|
|
/*no instance context*/ QualType());
|
2010-03-31 05:47:33 +08:00
|
|
|
Entity.setDiag(diag::err_access)
|
|
|
|
<< Ovl->getSourceRange();
|
|
|
|
|
|
|
|
return CheckAccess(*this, Ovl->getNameLoc(), Entity);
|
|
|
|
}
|
|
|
|
|
2010-02-10 17:31:12 +08:00
|
|
|
/// Checks access for a hierarchy conversion.
|
|
|
|
///
|
|
|
|
/// \param ForceCheck true if this check should be performed even if access
|
|
|
|
/// control is disabled; some things rely on this for semantics
|
|
|
|
/// \param ForceUnprivileged true if this check should proceed as if the
|
|
|
|
/// context had no special privileges
|
|
|
|
Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
|
|
|
|
QualType Base,
|
|
|
|
QualType Derived,
|
|
|
|
const CXXBasePath &Path,
|
2010-03-16 13:22:47 +08:00
|
|
|
unsigned DiagID,
|
2010-02-10 17:31:12 +08:00
|
|
|
bool ForceCheck,
|
2010-03-16 13:22:47 +08:00
|
|
|
bool ForceUnprivileged) {
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!ForceCheck && !getLangOpts().AccessControl)
|
2010-02-10 17:31:12 +08:00
|
|
|
return AR_accessible;
|
|
|
|
|
|
|
|
if (Path.Access == AS_public)
|
|
|
|
return AR_accessible;
|
|
|
|
|
|
|
|
CXXRecordDecl *BaseD, *DerivedD;
|
|
|
|
BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
|
|
|
|
DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
|
2010-03-16 13:22:47 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD,
|
|
|
|
Path.Access);
|
2010-03-16 13:22:47 +08:00
|
|
|
if (DiagID)
|
|
|
|
Entity.setDiag(DiagID) << Derived << Base;
|
2010-02-10 17:31:12 +08:00
|
|
|
|
2010-04-07 05:38:20 +08:00
|
|
|
if (ForceUnprivileged) {
|
|
|
|
switch (CheckEffectiveAccess(*this, EffectiveContext(),
|
|
|
|
AccessLoc, Entity)) {
|
|
|
|
case ::AR_accessible: return Sema::AR_accessible;
|
|
|
|
case ::AR_inaccessible: return Sema::AR_inaccessible;
|
|
|
|
case ::AR_dependent: return Sema::AR_dependent;
|
|
|
|
}
|
|
|
|
llvm_unreachable("unexpected result from CheckEffectiveAccess");
|
|
|
|
}
|
2010-03-16 13:22:47 +08:00
|
|
|
return CheckAccess(*this, AccessLoc, Entity);
|
2010-01-28 09:42:12 +08:00
|
|
|
}
|
|
|
|
|
2010-01-23 08:46:32 +08:00
|
|
|
/// Checks access to all the declarations in the given result set.
|
2010-02-10 17:31:12 +08:00
|
|
|
void Sema::CheckLookupAccess(const LookupResult &R) {
|
2012-03-11 15:00:24 +08:00
|
|
|
assert(getLangOpts().AccessControl
|
2010-02-10 17:31:12 +08:00
|
|
|
&& "performing access check without access control");
|
|
|
|
assert(R.getNamingClass() && "performing access check without naming class");
|
|
|
|
|
2010-03-16 13:22:47 +08:00
|
|
|
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
|
|
|
|
if (I.getAccess() != AS_public) {
|
2010-04-07 05:38:20 +08:00
|
|
|
AccessTarget Entity(Context, AccessedEntity::Member,
|
|
|
|
R.getNamingClass(), I.getPair(),
|
2011-09-19 23:10:40 +08:00
|
|
|
R.getBaseObjectType());
|
2010-03-16 13:22:47 +08:00
|
|
|
Entity.setDiag(diag::err_access);
|
|
|
|
CheckAccess(*this, R.getNameLoc(), Entity);
|
|
|
|
}
|
|
|
|
}
|
2010-01-23 08:46:32 +08:00
|
|
|
}
|
2010-06-28 16:39:25 +08:00
|
|
|
|
2011-10-06 15:27:49 +08:00
|
|
|
/// Checks access to Decl from the given class. The check will take access
|
|
|
|
/// specifiers into account, but no member access expressions and such.
|
|
|
|
///
|
|
|
|
/// \param Decl the declaration to check if it can be accessed
|
2012-08-24 08:01:24 +08:00
|
|
|
/// \param Ctx the class/context from which to start the search
|
2011-10-06 15:27:49 +08:00
|
|
|
/// \return true if the Decl is accessible from the Class, false otherwise.
|
2011-11-04 00:51:37 +08:00
|
|
|
bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) {
|
|
|
|
if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) {
|
2011-11-04 01:41:55 +08:00
|
|
|
if (!Decl->isCXXClassMember())
|
2011-11-04 00:51:37 +08:00
|
|
|
return true;
|
2011-10-06 15:27:49 +08:00
|
|
|
|
2011-11-04 00:51:37 +08:00
|
|
|
QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal();
|
|
|
|
AccessTarget Entity(Context, AccessedEntity::Member, Class,
|
|
|
|
DeclAccessPair::make(Decl, Decl->getAccess()),
|
|
|
|
qType);
|
|
|
|
if (Entity.getAccess() == AS_public)
|
|
|
|
return true;
|
2011-10-06 15:27:49 +08:00
|
|
|
|
2011-11-04 00:51:37 +08:00
|
|
|
EffectiveContext EC(CurContext);
|
|
|
|
return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;
|
|
|
|
}
|
|
|
|
|
2011-11-04 03:00:24 +08:00
|
|
|
if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Decl)) {
|
|
|
|
// @public and @package ivars are always accessible.
|
|
|
|
if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public ||
|
|
|
|
Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package)
|
|
|
|
return true;
|
2013-05-08 00:56:03 +08:00
|
|
|
|
2011-11-04 03:00:24 +08:00
|
|
|
// If we are inside a class or category implementation, determine the
|
|
|
|
// interface we're in.
|
2014-05-26 14:22:03 +08:00
|
|
|
ObjCInterfaceDecl *ClassOfMethodDecl = nullptr;
|
2011-11-04 03:00:24 +08:00
|
|
|
if (ObjCMethodDecl *MD = getCurMethodDecl())
|
|
|
|
ClassOfMethodDecl = MD->getClassInterface();
|
|
|
|
else if (FunctionDecl *FD = getCurFunctionDecl()) {
|
|
|
|
if (ObjCImplDecl *Impl
|
|
|
|
= dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) {
|
|
|
|
if (ObjCImplementationDecl *IMPD
|
|
|
|
= dyn_cast<ObjCImplementationDecl>(Impl))
|
|
|
|
ClassOfMethodDecl = IMPD->getClassInterface();
|
|
|
|
else if (ObjCCategoryImplDecl* CatImplClass
|
|
|
|
= dyn_cast<ObjCCategoryImplDecl>(Impl))
|
|
|
|
ClassOfMethodDecl = CatImplClass->getClassInterface();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're not in an interface, this ivar is inaccessible.
|
|
|
|
if (!ClassOfMethodDecl)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If we're inside the same interface that owns the ivar, we're fine.
|
2011-12-15 08:29:59 +08:00
|
|
|
if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface()))
|
2011-11-04 03:00:24 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// If the ivar is private, it's inaccessible.
|
|
|
|
if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return Ivar->getContainingInterface()->isSuperClassOf(ClassOfMethodDecl);
|
|
|
|
}
|
|
|
|
|
2011-11-04 00:51:37 +08:00
|
|
|
return true;
|
2011-10-06 15:27:49 +08:00
|
|
|
}
|