Check that the access specifier of a member redeclaration is the same as the original declaration.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67722 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 88c08b0..d974301 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3083,6 +3083,21 @@
   return NewTD;
 }
 
+static const char *getAccessName(AccessSpecifier AS) {
+  switch (AS) {
+    default:
+    case AS_none:
+      assert("Invalid access specifier!");
+      return 0;
+    case AS_public:
+      return "public";
+    case AS_private:
+      return "private";
+    case AS_protected:
+      return "protected";
+  }
+}
+
 /// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'.  In the
 /// former case, Name will be non-null.  In the later case, Name will be null.
 /// TagSpec indicates what kind of tag this is. TK indicates whether this is a
@@ -3384,9 +3399,17 @@
   // lexical context will be different from the semantic context.
   New->setLexicalDeclContext(CurContext);
 
-  if (PrevDecl)
-    New->setAccess(PrevDecl->getAccess());
-  else
+  if (PrevDecl) {
+    // C++ [class.access.spec]p3: When a member is redeclared its access
+    // specifier must be same as its initial declaration.
+    if (AS != AS_none && AS != PrevDecl->getAccess()) {
+      Diag(Loc, diag::err_class_redeclared_with_different_access) 
+        << New << getAccessName(AS);
+      Diag(PrevDecl->getLocation(), diag::note_previous_access_declaration)
+        << PrevDecl << getAccessName(PrevDecl->getAccess());
+    } else 
+      New->setAccess(PrevDecl->getAccess());
+  } else
     New->setAccess(AS);
 
   if (TK == TK_Definition)