aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Decl.h4
-rw-r--r--include/clang/AST/DeclAccessPair.h72
-rw-r--r--include/clang/AST/DeclCXX.h5
-rw-r--r--include/clang/AST/DependentDiagnostic.h9
-rw-r--r--include/clang/AST/Expr.h10
-rw-r--r--include/clang/AST/UnresolvedSet.h51
-rw-r--r--lib/AST/Decl.cpp18
-rw-r--r--lib/AST/Expr.cpp6
-rw-r--r--lib/Sema/Lookup.h13
-rw-r--r--lib/Sema/Sema.h24
-rw-r--r--lib/Sema/SemaAccess.cpp631
-rw-r--r--lib/Sema/SemaExpr.cpp33
-rw-r--r--lib/Sema/SemaOverload.cpp6
-rw-r--r--lib/Sema/SemaType.cpp10
-rw-r--r--test/CXX/class.access/class.protected/p1.cpp387
15 files changed, 969 insertions, 310 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 2cdb983513..569a94e8a1 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -196,6 +196,10 @@ public:
return DC->isRecord();
}
+ /// \brief Given that this declaration is a C++ class member,
+ /// determine whether it's an instance member of its class.
+ bool isCXXInstanceMember() const;
+
/// \brief Determine what kind of linkage this entity has.
Linkage getLinkage() const;
diff --git a/include/clang/AST/DeclAccessPair.h b/include/clang/AST/DeclAccessPair.h
new file mode 100644
index 0000000000..7ecd8f8bcd
--- /dev/null
+++ b/include/clang/AST/DeclAccessPair.h
@@ -0,0 +1,72 @@
+//===--- DeclAccessPair.h - A decl bundled with its path access -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the DeclAccessPair class, which provides an
+// efficient representation of a pair of a NamedDecl* and an
+// AccessSpecifier. Generally the access specifier gives the
+// natural access of a declaration when named in a class, as
+// defined in C++ [class.access.base]p1.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_DECLACCESSPAIR_H
+#define LLVM_CLANG_AST_DECLACCESSPAIR_H
+
+#include "clang/Basic/Specifiers.h"
+
+namespace clang {
+
+class NamedDecl;
+
+/// A POD class for pairing a NamedDecl* with an access specifier.
+/// Can be put into unions.
+class DeclAccessPair {
+ NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
+
+ enum { Mask = 0x3 };
+
+public:
+ static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) {
+ DeclAccessPair p;
+ p.set(D, AS);
+ return p;
+ }
+
+ NamedDecl *getDecl() const {
+ return (NamedDecl*) (~Mask & (uintptr_t) Ptr);
+ }
+ AccessSpecifier getAccess() const {
+ return AccessSpecifier(Mask & (uintptr_t) Ptr);
+ }
+
+ void setDecl(NamedDecl *D) {
+ set(D, getAccess());
+ }
+ void setAccess(AccessSpecifier AS) {
+ set(getDecl(), AS);
+ }
+ void set(NamedDecl *D, AccessSpecifier AS) {
+ Ptr = reinterpret_cast<NamedDecl*>(uintptr_t(AS) |
+ reinterpret_cast<uintptr_t>(D));
+ }
+
+ operator NamedDecl*() const { return getDecl(); }
+ NamedDecl *operator->() const { return getDecl(); }
+};
+}
+
+// Take a moment to tell SmallVector that DeclAccessPair is POD.
+namespace llvm {
+template<typename> struct isPodLike;
+template<> struct isPodLike<clang::DeclAccessPair> {
+ static const bool value = true;
+};
+}
+
+#endif
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 23769af46b..9f110748d5 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -471,6 +471,11 @@ public:
friend_iterator friend_end() const;
void pushFriendDecl(FriendDecl *FD);
+ /// Determines whether this record has any friends.
+ bool hasFriends() const {
+ return data().FirstFriend != 0;
+ }
+
/// hasConstCopyConstructor - Determines whether this class has a
/// copy constructor that accepts a const-qualified argument.
bool hasConstCopyConstructor(ASTContext &Context) const;
diff --git a/include/clang/AST/DependentDiagnostic.h b/include/clang/AST/DependentDiagnostic.h
index 1954a282e8..2bbe5020cb 100644
--- a/include/clang/AST/DependentDiagnostic.h
+++ b/include/clang/AST/DependentDiagnostic.h
@@ -22,6 +22,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclContextInternals.h"
+#include "clang/AST/Type.h"
namespace clang {
@@ -42,6 +43,7 @@ public:
AccessSpecifier AS,
NamedDecl *TargetDecl,
CXXRecordDecl *NamingClass,
+ QualType BaseObjectType,
const PartialDiagnostic &PDiag) {
DependentDiagnostic *DD = Create(Context, Parent, PDiag);
DD->AccessData.Loc = Loc.getRawEncoding();
@@ -49,6 +51,7 @@ public:
DD->AccessData.Access = AS;
DD->AccessData.TargetDecl = TargetDecl;
DD->AccessData.NamingClass = NamingClass;
+ DD->AccessData.BaseObjectType = BaseObjectType.getAsOpaquePtr();
return DD;
}
@@ -81,6 +84,11 @@ public:
return AccessData.NamingClass;
}
+ QualType getAccessBaseObjectType() const {
+ assert(getKind() == Access);
+ return QualType::getFromOpaquePtr(AccessData.BaseObjectType);
+ }
+
const PartialDiagnostic &getDiagnostic() const {
return Diag;
}
@@ -107,6 +115,7 @@ private:
unsigned IsMember : 1;
NamedDecl *TargetDecl;
CXXRecordDecl *NamingClass;
+ void *BaseObjectType;
} AccessData;
};
};
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index a687ee5f01..2b172a726f 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -17,6 +17,7 @@
#include "clang/AST/APValue.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
+#include "clang/AST/DeclAccessPair.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallVector.h"
@@ -1274,7 +1275,7 @@ public:
class MemberExpr : public Expr {
/// Extra data stored in some member expressions.
struct MemberNameQualifier : public NameQualifier {
- NamedDecl *FoundDecl;
+ DeclAccessPair FoundDecl;
};
/// Base - the expression for the base pointer or structure references. In
@@ -1349,7 +1350,7 @@ public:
static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual, SourceRange qualrange,
- ValueDecl *memberdecl, NamedDecl *founddecl,
+ ValueDecl *memberdecl, DeclAccessPair founddecl,
SourceLocation l,
const TemplateArgumentListInfo *targs,
QualType ty);
@@ -1365,9 +1366,10 @@ public:
void setMemberDecl(ValueDecl *D) { MemberDecl = D; }
/// \brief Retrieves the declaration found by lookup.
- NamedDecl *getFoundDecl() const {
+ DeclAccessPair getFoundDecl() const {
if (!HasQualifierOrFoundDecl)
- return getMemberDecl();
+ return DeclAccessPair::make(getMemberDecl(),
+ getMemberDecl()->getAccess());
return getMemberQualifier()->FoundDecl;
}
diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h
index 553f04d76a..cad7e61d55 100644
--- a/include/clang/AST/UnresolvedSet.h
+++ b/include/clang/AST/UnresolvedSet.h
@@ -17,56 +17,7 @@
#include <iterator>
#include "llvm/ADT/SmallVector.h"
-#include "clang/Basic/Specifiers.h"
-
-namespace clang {
-
-class NamedDecl;
-
-/// A POD class for pairing a NamedDecl* with an access specifier.
-/// Can be put into unions.
-class DeclAccessPair {
- NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
-
- enum { Mask = 0x3 };
-
-public:
- static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) {
- DeclAccessPair p;
- p.set(D, AS);
- return p;
- }
-
- NamedDecl *getDecl() const {
- return (NamedDecl*) (~Mask & (uintptr_t) Ptr);
- }
- AccessSpecifier getAccess() const {
- return AccessSpecifier(Mask & (uintptr_t) Ptr);
- }
-
- void setDecl(NamedDecl *D) {
- set(D, getAccess());
- }
- void setAccess(AccessSpecifier AS) {
- set(getDecl(), AS);
- }
- void set(NamedDecl *D, AccessSpecifier AS) {
- Ptr = reinterpret_cast<NamedDecl*>(uintptr_t(AS) |
- reinterpret_cast<uintptr_t>(D));
- }
-
- operator NamedDecl*() const { return getDecl(); }
- NamedDecl *operator->() const { return getDecl(); }
-};
-}
-
-// Take a moment to tell SmallVector that this is POD.
-namespace llvm {
-template<typename> struct isPodLike;
-template<> struct isPodLike<clang::DeclAccessPair> {
- static const bool value = true;
-};
-}
+#include "clang/AST/DeclAccessPair.h"
namespace clang {
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index dc9fb59e30..3f2baf7c9c 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -494,6 +494,24 @@ NamedDecl *NamedDecl::getUnderlyingDecl() {
}
}
+bool NamedDecl::isCXXInstanceMember() const {
+ assert(isCXXClassMember() &&
+ "checking whether non-member is instance member");
+
+ const NamedDecl *D = this;
+ if (isa<UsingShadowDecl>(D))
+ D = cast<UsingShadowDecl>(D)->getTargetDecl();
+
+ if (isa<FieldDecl>(D))
+ return true;
+ if (isa<CXXMethodDecl>(D))
+ return cast<CXXMethodDecl>(D)->isInstance();
+ if (isa<FunctionTemplateDecl>(D))
+ return cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D)
+ ->getTemplatedDecl())->isInstance();
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// DeclaratorDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index ae4bc8c801..132245e671 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -496,13 +496,15 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifier *qual,
SourceRange qualrange,
ValueDecl *memberdecl,
- NamedDecl *founddecl,
+ DeclAccessPair founddecl,
SourceLocation l,
const TemplateArgumentListInfo *targs,
QualType ty) {
std::size_t Size = sizeof(MemberExpr);
- bool hasQualOrFound = (qual != 0 || founddecl != memberdecl);
+ bool hasQualOrFound = (qual != 0 ||
+ founddecl.getDecl() != memberdecl ||
+ founddecl.getAccess() != memberdecl->getAccess());
if (hasQualOrFound)
Size += sizeof(MemberNameQualifier);
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index f310c253ab..73559a246d 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -282,6 +282,18 @@ public:
NamingClass = Record;
}
+ /// \brief Returns the base object type associated with this lookup;
+ /// important for [class.protected]. Most lookups do not have an
+ /// associated base object.
+ QualType getBaseObjectType() const {
+ return BaseObjectType;
+ }
+
+ /// \brief Sets the base object type for this lookup.
+ void setBaseObjectType(QualType T) {
+ BaseObjectType = T;
+ }
+
/// \brief Add a declaration to these results with its natural access.
/// Does not test the acceptance criteria.
void addDecl(NamedDecl *D) {
@@ -550,6 +562,7 @@ private:
UnresolvedSet<8> Decls;
CXXBasePaths *Paths;
CXXRecordDecl *NamingClass;
+ QualType BaseObjectType;
// Parameters.
Sema &SemaRef;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 0766b1e83d..3f5113ed55 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -315,20 +315,11 @@ public:
AccessedEntity(ASTContext &Context,
MemberNonce _,
CXXRecordDecl *NamingClass,
- AccessSpecifier Access,
- NamedDecl *Target)
- : Access(Access), IsMember(true),
- Target(Target), NamingClass(NamingClass),
- Diag(0, Context.getDiagAllocator()) {
- }
-
- AccessedEntity(ASTContext &Context,
- MemberNonce _,
- CXXRecordDecl *NamingClass,
- DeclAccessPair FoundDecl)
+ DeclAccessPair FoundDecl,
+ QualType BaseObjectType)
: Access(FoundDecl.getAccess()), IsMember(true),
Target(FoundDecl.getDecl()), NamingClass(NamingClass),
- Diag(0, Context.getDiagAllocator()) {
+ BaseObjectType(BaseObjectType), Diag(0, Context.getDiagAllocator()) {
}
AccessedEntity(ASTContext &Context,
@@ -353,6 +344,10 @@ public:
CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); }
CXXRecordDecl *getDerivedClass() const { return NamingClass; }
+ /// Retrieves the base object type, important when accessing
+ /// an instance member.
+ QualType getBaseObjectType() const { return BaseObjectType; }
+
/// Sets a diagnostic to be performed. The diagnostic is given
/// four (additional) arguments:
/// %0 - 0 if the entity was private, 1 if protected
@@ -378,6 +373,7 @@ public:
bool IsMember;
NamedDecl *Target;
CXXRecordDecl *NamingClass;
+ QualType BaseObjectType;
PartialDiagnostic Diag;
};
@@ -1254,10 +1250,10 @@ public:
FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From);
Expr *FixOverloadedFunctionReference(Expr *E,
- NamedDecl *FoundDecl,
+ DeclAccessPair FoundDecl,
FunctionDecl *Fn);
OwningExprResult FixOverloadedFunctionReference(OwningExprResult,
- NamedDecl *FoundDecl,
+ DeclAccessPair FoundDecl,
FunctionDecl *Fn);
void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index f628884aab..99a8f9f5bd 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -22,6 +22,13 @@
using namespace clang;
+/// A copy of Sema's enum without AR_delayed.
+enum AccessResult {
+ AR_accessible,
+ AR_inaccessible,
+ AR_dependent
+};
+
/// 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).
@@ -51,6 +58,20 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
return false;
}
+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;
+}
+
namespace {
struct EffectiveContext {
EffectiveContext() : Inner(0), Dependent(false) {}
@@ -109,22 +130,145 @@ struct EffectiveContext {
llvm::SmallVector<CXXRecordDecl*, 4> Records;
bool Dependent;
};
+
+/// Like Sema's AccessedEntity, but kindly lets us scribble all over
+/// it.
+struct AccessTarget : public Sema::AccessedEntity {
+ AccessTarget(const Sema::AccessedEntity &Entity)
+ : AccessedEntity(Entity) {
+ initialize();
+ }
+
+ AccessTarget(ASTContext &Context,
+ MemberNonce _,
+ CXXRecordDecl *NamingClass,
+ DeclAccessPair FoundDecl,
+ QualType BaseObjectType)
+ : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) {
+ initialize();
+ }
+
+ AccessTarget(ASTContext &Context,
+ BaseNonce _,
+ CXXRecordDecl *BaseClass,
+ CXXRecordDecl *DerivedClass,
+ AccessSpecifier Access)
+ : AccessedEntity(Context, Base, BaseClass, DerivedClass, Access) {
+ initialize();
+ }
+
+ bool hasInstanceContext() const {
+ return HasInstanceContext;
+ }
+
+ class SavedInstanceContext {
+ public:
+ ~SavedInstanceContext() {
+ Target.HasInstanceContext = Has;
+ }
+
+ private:
+ friend class AccessTarget;
+ 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());
+ InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() : 0);
+ return InstanceContext;
+ }
+
+ const CXXRecordDecl *getDeclaringClass() const {
+ return DeclaringClass;
+ }
+
+private:
+ void initialize() {
+ HasInstanceContext = (isMemberAccess() &&
+ !getBaseObjectType().isNull() &&
+ getTargetDecl()->isCXXInstanceMember());
+ CalculatedInstanceContext = false;
+ InstanceContext = 0;
+
+ 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;
+};
+
}
-static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
- DeclContext *DC = D->getDeclContext();
+/// 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);
- // This can only happen at top: enum decls only "publish" their
- // immediate members.
- if (isa<EnumDecl>(DC))
- DC = cast<EnumDecl>(DC)->getDeclContext();
+ if (Derived == Target) return AR_accessible;
- CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
- while (DeclaringClass->isAnonymousStructOrUnion())
- DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
- return DeclaringClass;
+ AccessResult OnFailure = AR_inaccessible;
+ llvm::SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
+
+ while (true) {
+ for (CXXRecordDecl::base_class_const_iterator
+ I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) {
+
+ const CXXRecordDecl *RD;
+
+ QualType T = I->getType();
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RD = cast<CXXRecordDecl>(RT->getDecl());
+ } else {
+ // It's possible for a base class to be the current
+ // instantiation of some enclosing template, but I'm guessing
+ // nobody will ever care that we just dependently delay here.
+ assert(T->isDependentType() && "non-dependent base wasn't a record?");
+ OnFailure = AR_dependent;
+ continue;
+ }
+
+ RD = RD->getCanonicalDecl();
+ if (RD == Target) return AR_accessible;
+ Queue.push_back(RD);
+ }
+
+ if (Queue.empty()) break;
+
+ Derived = Queue.back();
+ Queue.pop_back();
+ }
+
+ return OnFailure;
}
+
static bool MightInstantiateTo(Sema &S, DeclContext *Context,
DeclContext *Friend) {
if (Friend == Context)
@@ -204,11 +348,11 @@ static bool MightInstantiateTo(Sema &S,
Friend->getTemplatedDecl());
}
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- const CXXRecordDecl *Friend) {
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Friend) {
if (EC.includesClass(Friend))
- return Sema::AR_accessible;
+ return AR_accessible;
if (EC.isDependent()) {
CanQualType FriendTy
@@ -219,32 +363,32 @@ static Sema::AccessResult MatchesFriend(Sema &S,
CanQualType ContextTy
= S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
if (MightInstantiateTo(S, ContextTy, FriendTy))
- return Sema::AR_dependent;
+ return AR_dependent;
}
}
- return Sema::AR_inaccessible;
+ return AR_inaccessible;
}
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- CanQualType Friend) {
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ CanQualType Friend) {
if (const RecordType *RT = Friend->getAs<RecordType>())
return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
// TODO: we can do better than this
if (Friend->isDependentType())
- return Sema::AR_dependent;
+ return AR_dependent;
- return Sema::AR_inaccessible;
+ return AR_inaccessible;
}
/// Determines whether the given friend class template matches
/// anything in the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- ClassTemplateDecl *Friend) {
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ ClassTemplateDecl *Friend) {
+ AccessResult OnFailure = AR_inaccessible;
// Check whether the friend is the template of a class in the
// context chain.
@@ -268,7 +412,7 @@ static Sema::AccessResult MatchesFriend(Sema &S,
// It's a match.
if (Friend == CTD->getCanonicalDecl())
- return Sema::AR_accessible;
+ return AR_accessible;
// If the context isn't dependent, it can't be a dependent match.
if (!EC.isDependent())
@@ -286,7 +430,7 @@ static Sema::AccessResult MatchesFriend(Sema &S,
continue;
// Otherwise, it's a dependent match.
- OnFailure = Sema::AR_dependent;
+ OnFailure = AR_dependent;
}
return OnFailure;
@@ -294,18 +438,18 @@ static Sema::AccessResult MatchesFriend(Sema &S,
/// Determines whether the given friend function matches anything in
/// the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- FunctionDecl *Friend) {
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FunctionDecl *Friend) {
+ AccessResult OnFailure = AR_inaccessible;
for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
if (Friend == *I)
- return Sema::AR_accessible;
+ return AR_accessible;
if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
- OnFailure = Sema::AR_dependent;
+ OnFailure = AR_dependent;
}
return OnFailure;
@@ -313,12 +457,12 @@ static Sema::AccessResult MatchesFriend(Sema &S,
/// Determines whether the given friend function template matches
/// anything in the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- FunctionTemplateDecl *Friend) {
- if (EC.Functions.empty()) return Sema::AR_inaccessible;
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FunctionTemplateDecl *Friend) {
+ if (EC.Functions.empty()) return AR_inaccessible;
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+ AccessResult OnFailure = AR_inaccessible;
for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
@@ -332,10 +476,10 @@ static Sema::AccessResult MatchesFriend(Sema &S,
FTD = FTD->getCanonicalDecl();
if (Friend == FTD)
- return Sema::AR_accessible;
+ return AR_accessible;
if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
- OnFailure = Sema::AR_dependent;
+ OnFailure = AR_dependent;
}
return OnFailure;
@@ -343,9 +487,9 @@ static Sema::AccessResult MatchesFriend(Sema &S,
/// Determines whether the given friend declaration matches anything
/// in the effective context.
-static Sema::AccessResult MatchesFriend(Sema &S,
- const EffectiveContext &EC,
- FriendDecl *FriendD) {
+static AccessResult MatchesFriend(Sema &S,
+ const EffectiveContext &EC,
+ FriendDecl *FriendD) {
if (TypeSourceInfo *T = FriendD->getFriendType())
return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
@@ -367,10 +511,10 @@ static Sema::AccessResult MatchesFriend(Sema &S,
return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
}
-static Sema::AccessResult GetFriendKind(Sema &S,
- const EffectiveContext &EC,
- const CXXRecordDecl *Class) {
- Sema::AccessResult OnFailure = Sema::AR_inaccessible;
+static AccessResult GetFriendKind(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *Class) {
+ AccessResult OnFailure = AR_inaccessible;
// Okay, check friends.
for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
@@ -378,18 +522,15 @@ static Sema::AccessResult GetFriendKind(Sema &S,
FriendDecl *Friend = *I;
switch (MatchesFriend(S, EC, Friend)) {
- case Sema::AR_accessible:
- return Sema::AR_accessible;
+ case AR_accessible:
+ return AR_accessible;
- case Sema::AR_inaccessible:
- break;
+ case AR_inaccessible:
+ continue;
- case Sema::AR_dependent:
- OnFailure = Sema::AR_dependent;
+ case AR_dependent:
+ OnFailure = AR_dependent;
break;
-
- case Sema::AR_delayed:
- llvm_unreachable("cannot get delayed answer from MatchesFriend");
}
}
@@ -397,16 +538,19 @@ static Sema::AccessResult GetFriendKind(Sema &S,
return OnFailure;
}
-static Sema::AccessResult HasAccess(Sema &S,
- const EffectiveContext &EC,
- const CXXRecordDecl *NamingClass,
- AccessSpecifier Access) {
+static AccessResult HasAccess(Sema &S,
+ const EffectiveContext &EC,
+ const CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ const AccessTarget &Target) {
assert(NamingClass->getCanonicalDecl() == NamingClass &&
"declaration should be canonicalized before being passed here");
- if (Access == AS_public) return Sema::AR_accessible;
+ if (Access == AS_public) return AR_accessible;
assert(Access == AS_private || Access == AS_protected);
+ AccessResult OnFailure = AR_inaccessible;
+
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
@@ -414,16 +558,75 @@ static Sema::AccessResult HasAccess(Sema &S,
const CXXRecordDecl *ECRecord = *I;
// [B2] and [M2]
- if (ECRecord == NamingClass)
- return Sema::AR_accessible;
+ if (Access == AS_private) {
+ if (ECRecord == NamingClass)
+ return AR_accessible;
// [B3] and [M3]
- if (Access == AS_protected &&
- ECRecord->isDerivedFrom(const_cast<CXXRecordDecl*>(NamingClass)))
- return Sema::AR_accessible;
+ } else {
+ assert(Access == AS_protected);
+ switch (IsDerivedFromInclusive(ECRecord, NamingClass)) {
+ case AR_accessible: break;
+ case AR_inaccessible: continue;
+ case AR_dependent: OnFailure = AR_dependent; continue;
+ }
+
+ if (!Target.hasInstanceContext())
+ return AR_accessible;
+
+ const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
+ if (!InstanceContext) {
+ 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.
+ //
+ // We interpret this as a restriction on [M3]. Most of the
+ // conditions are encoded by not having any instance context.
+ switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) {
+ case AR_accessible: return AR_accessible;
+ case AR_inaccessible: continue;
+ case AR_dependent: OnFailure = AR_dependent; continue;
+ }
+ }
}
- return GetFriendKind(S, EC, NamingClass);
+ if (!NamingClass->hasFriends())
+ return OnFailure;
+
+ // Don't consider friends if we're under the [class.protected]
+ // restriction, above.
+ if (Access == AS_protected && Target.hasInstanceContext()) {
+ const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S);
+ if (!InstanceContext) return AR_dependent;
+
+ switch (IsDerivedFromInclusive(InstanceContext, NamingClass)) {
+ case AR_accessible: break;
+ case AR_inaccessible: return OnFailure;
+ case AR_dependent: return AR_dependent;
+ }
+ }
+
+ 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");
+ return OnFailure;
}
/// Finds the best path from the naming class to the declaring class,
@@ -479,17 +682,21 @@ static Sema::AccessResult HasAccess(Sema &S,
///
/// B is an accessible base of N at R iff ACAB(1) = public.
///
-/// \param FinalAccess the access of the "final step", or AS_none if
+/// \param FinalAccess the access of the "final step", or AS_public if
/// there is no final step.
/// \return null if friendship is dependent
static CXXBasePath *FindBestPath(Sema &S,
const EffectiveContext &EC,
- CXXRecordDecl *Derived,
- CXXRecordDecl *Base,
+ AccessTarget &Target,
AccessSpecifier FinalAccess,
CXXBasePaths &Paths) {
// Derive the paths to the desired base.
- bool isDerived = Derived->isDerivedFrom(Base, Paths);
+ 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),
+ P