diff options
Diffstat (limited to 'lib/Sema/SemaAccess.cpp')
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 52 |
1 files changed, 48 insertions, 4 deletions
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index e92d19d13d..0eb9854562 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -146,8 +146,10 @@ struct AccessTarget : public AccessedEntity { MemberNonce _, CXXRecordDecl *NamingClass, DeclAccessPair FoundDecl, - QualType BaseObjectType) - : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) { + QualType BaseObjectType, + bool IsUsingDecl = false) + : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType), + IsUsingDeclaration(IsUsingDecl) { initialize(); } @@ -216,6 +218,7 @@ private: DeclaringClass = DeclaringClass->getCanonicalDecl(); } + bool IsUsingDeclaration : 1; bool HasInstanceContext : 1; mutable bool CalculatedInstanceContext : 1; mutable const CXXRecordDecl *InstanceContext; @@ -1129,6 +1132,44 @@ static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, DiagnoseAccessPath(S, EC, Entity); } +/// 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)) { + S.Diag(AccessLoc, diag::war_ms_using_declaration_inaccessible) + << Shadow->getUsingDecl()->getQualifiedNameAsString() + << OrigDecl->getQualifiedNameAsString(); + return true; + } + } + return false; +} + /// Determines whether the accessed entity is accessible. Public members /// have been weeded out by this point. static AccessResult IsAccessible(Sema &S, @@ -1232,6 +1273,10 @@ static AccessResult CheckEffectiveAccess(Sema &S, AccessTarget &Entity) { assert(Entity.getAccess() != AS_public && "called for public access!"); + if (S.getLangOptions().Microsoft && + IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity)) + return AR_accessible; + switch (IsAccessible(S, EC, Entity)) { case AR_dependent: DelayDependentAccess(S, EC, Loc, Entity); @@ -1577,9 +1622,8 @@ void Sema::CheckLookupAccess(const LookupResult &R) { if (I.getAccess() != AS_public) { AccessTarget Entity(Context, AccessedEntity::Member, R.getNamingClass(), I.getPair(), - R.getBaseObjectType()); + R.getBaseObjectType(), R.isUsingDeclaration()); Entity.setDiag(diag::err_access); - CheckAccess(*this, R.getNameLoc(), Entity); } } |