aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--include/clang/Sema/Lookup.h16
-rw-r--r--lib/Sema/SemaAccess.cpp52
-rw-r--r--lib/Sema/SemaDeclCXX.cpp1
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp19
5 files changed, 88 insertions, 4 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 00cd81f7e3..e5354b6424 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -596,6 +596,10 @@ def err_class_redeclared_with_different_access : Error<
"%0 redeclared with '%1' access">;
def err_access : Error<
"%1 is a %select{private|protected}0 member of %3">, AccessControl;
+def war_ms_using_declaration_inaccessible : ExtWarn<
+ "using declaration refers to inaccessible member '%0', which refers "
+ "to accessible member '%1', accepted for Microsoft compatibility">,
+ AccessControl, InGroup<Microsoft>;
def err_access_ctor : Error<
"calling a %select{private|protected}0 constructor of class %2">,
AccessControl;
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index 400a7cc919..dceed4efc9 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -282,6 +282,18 @@ public:
return NamingClass != 0;
}
+ /// \brief Set whether the name lookup is triggered by a
+ /// using declaration.
+ void setUsingDeclaration(bool U) {
+ UsingDeclaration = U;
+ }
+
+ /// \brief Returns whether the name lookup is triggered by a
+ /// using declaration.
+ bool isUsingDeclaration() const {
+ return UsingDeclaration;
+ }
+
/// \brief Returns the 'naming class' for this lookup, i.e. the
/// class which was looked into to find these results.
///
@@ -603,6 +615,10 @@ private:
bool HideTags;
bool Diagnose;
+
+ /// \brief True if the lookup is triggered by a using declaration.
+ /// Necessary to handle a MSVC bug.
+ bool UsingDeclaration;
};
/// \brief Consumes visible declarations found when searching for
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);
}
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 4fc9bf1fdd..8bf7cb67b8 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -5345,6 +5345,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// Otherwise, look up the target name.
LookupResult R(*this, NameInfo, LookupOrdinaryName);
+ R.setUsingDeclaration(true);
// Unlike most lookups, we don't always want to hide tag
// declarations: tag names are visible through the using declaration
diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp
index 88e3922670..3391e7afb0 100644
--- a/test/SemaCXX/MicrosoftExtensions.cpp
+++ b/test/SemaCXX/MicrosoftExtensions.cpp
@@ -197,3 +197,22 @@ void pointer_to_integral_type_conv(char* ptr) {
ch = (char)ptr;
sh = (short)ptr;
}
+
+namespace ms_using_declaration_bug {
+
+class A {
+public:
+ int f();
+};
+
+class B : public A {
+private:
+ using A::f;
+};
+
+class C : public B {
+private:
+ using B::f; // expected-warning {{using declaration refers to inaccessible member 'ms_using_declaration_bug::B::f', which refers to accessible member 'ms_using_declaration_bug::A::f', accepted for Microsoft compatibility}}
+};
+
+} \ No newline at end of file