]> granicus.if.org Git - clang/commitdiff
Emulate a MSVC bug where if during an using declaration name lookup, the declaration...
authorFrancois Pichet <pichet2000@gmail.com>
Mon, 23 May 2011 03:43:44 +0000 (03:43 +0000)
committerFrancois Pichet <pichet2000@gmail.com>
Mon, 23 May 2011 03:43:44 +0000 (03:43 +0000)
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.

This fixes 1 error when parsing MFC code with clang.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131896 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Lookup.h
lib/Sema/SemaAccess.cpp
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/MicrosoftExtensions.cpp

index 00cd81f7e350a6f114f4cdc4112254b5e4f9d8fd..e5354b64248bd07c17c14d24065c0175fa95cd6b 100644 (file)
@@ -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;
index 400a7cc9194deacea2b0fd0832b3bb09d304643e..dceed4efc9797ba27c182630e54b2ea8f6b0a16c 100644 (file)
@@ -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
index e92d19d13d36750ce3cfd7a7588162207e81a35f..0eb98545627071ba306f3029917202cebe9a5845 100644 (file)
@@ -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);
     }
   }
index 4fc9bf1fdd5d4592ec20cb944fa895bbcf443312..8bf7cb67b88a409a352294453081d14ecf4fe4d3 100644 (file)
@@ -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
index 88e39226708c98cb7944bac6cc5fde5b4d1a1ec0..3391e7afb00928781c95425c29648f5525dc2823 100644 (file)
@@ -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