aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaAccess.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaAccess.cpp')
-rw-r--r--lib/Sema/SemaAccess.cpp55
1 files changed, 55 insertions, 0 deletions
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 4625cb15ea..e629f0fd35 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -930,6 +930,57 @@ static CXXBasePath *FindBestPath(Sema &S,
return BestPath;
}
+/// 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.
+ if (!Target.hasInstanceContext())
+ return false;
+ assert(Target.isMemberAccess());
+ NamedDecl *D = Target.getTargetDecl();
+
+ const CXXRecordDecl *DeclaringClass = Target.getDeclaringClass();
+ DeclaringClass = DeclaringClass->getCanonicalDecl();
+
+ for (EffectiveContext::record_iterator
+ I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
+ const CXXRecordDecl *ECRecord = *I;
+ switch (IsDerivedFromInclusive(ECRecord, DeclaringClass)) {
+ case AR_accessible: break;
+ case AR_inaccessible: continue;
+ case AR_dependent: continue;
+ }
+
+ // The effective context is a subclass of the declaring class.
+ // If that class isn't a superclass of the instance context,
+ // then the [class.protected] restriction applies.
+
+ // 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.
+
+ 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:
+ S.Diag(D->getLocation(), diag::note_access_protected_restricted)
+ << (InstanceContext != Target.getNamingClass()->getCanonicalDecl())
+ << S.Context.getTypeDeclType(InstanceContext)
+ << S.Context.getTypeDeclType(ECRecord);
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// Diagnose the path which caused the given declaration or base class
/// to become inaccessible.
static void DiagnoseAccessPath(Sema &S,
@@ -948,6 +999,10 @@ static void DiagnoseAccessPath(Sema &S,
if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
switch (HasAccess(S, EC, DeclaringClass, D->getAccess(), Entity)) {
case AR_inaccessible: {
+ if (Access == AS_protected &&
+ TryDiagnoseProtectedAccess(S, EC, Entity))
+ return;
+
S.Diag(D->getLocation(), diag::note_access_natural)
<< (unsigned) (Access == AS_protected)
<< /*FIXME: not implicitly*/ 0;