re PR c++/24926 (gcc ignores access level violation for anonymous structs)
authorPaolo Carlini <paolo.carlini@oracle.com>
Wed, 4 Sep 2013 23:52:48 +0000 (23:52 +0000)
committerPaolo Carlini <paolo@gcc.gnu.org>
Wed, 4 Sep 2013 23:52:48 +0000 (23:52 +0000)
/cp
2013-09-04  Paolo Carlini  <paolo.carlini@oracle.com>

PR c++/24926
* class.c (finish_struct_anon_r): New.
(finish_struct_anon): Use it.

/testsuite
2013-09-04  Paolo Carlini  <paolo.carlini@oracle.com>

PR c++/24926
* g++.dg/parse/access11.C: New.

From-SVN: r202266

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/parse/access11.C [new file with mode: 0644]

index db4cd660af3752ef8680a0b29d188d8bc62e1268..be8258dcf3ec1fe685663d369601d99148bd11bf 100644 (file)
@@ -1,3 +1,9 @@
+2013-09-04  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       PR c++/24926
+       * class.c (finish_struct_anon_r): New.
+       (finish_struct_anon): Use it.
+
 2013-09-04  Gabriel Dos Reis  <gdr@integrable-solutions.net>
 
        * cxx-pretty-print.h (cxx_pretty_printer::simple_type_specifier):
index bcd8076b09d75c1457cbf36c8100e0b28f2f9865..3d34b92cfb1b22ecc5cc4da5e34f775bd54a3fce 100644 (file)
@@ -2773,15 +2773,93 @@ warn_hidden (tree t)
     }
 }
 
+/* Recursive helper for finish_struct_anon.  */
+
+static void
+finish_struct_anon_r (tree field, bool complain)
+{
+  bool is_union = TREE_CODE (TREE_TYPE (field)) == UNION_TYPE;
+  tree elt = TYPE_FIELDS (TREE_TYPE (field));
+  for (; elt; elt = DECL_CHAIN (elt))
+    {
+      /* We're generally only interested in entities the user
+        declared, but we also find nested classes by noticing
+        the TYPE_DECL that we create implicitly.  You're
+        allowed to put one anonymous union inside another,
+        though, so we explicitly tolerate that.  We use
+        TYPE_ANONYMOUS_P rather than ANON_AGGR_TYPE_P so that
+        we also allow unnamed types used for defining fields.  */
+      if (DECL_ARTIFICIAL (elt)
+         && (!DECL_IMPLICIT_TYPEDEF_P (elt)
+             || TYPE_ANONYMOUS_P (TREE_TYPE (elt))))
+       continue;
+
+      if (TREE_CODE (elt) != FIELD_DECL)
+       {
+         if (complain)
+           {
+             if (is_union)
+               permerror (input_location,
+                          "%q+#D invalid; an anonymous union can "
+                          "only have non-static data members", elt);
+             else
+               permerror (input_location,
+                          "%q+#D invalid; an anonymous struct can "
+                          "only have non-static data members", elt);
+           }
+         continue;
+       }
+
+      if (complain)
+       {
+         if (TREE_PRIVATE (elt))
+           {
+             if (is_union)
+               permerror (input_location,
+                          "private member %q+#D in anonymous union", elt);
+             else
+               permerror (input_location,
+                          "private member %q+#D in anonymous struct", elt);
+           }
+         else if (TREE_PROTECTED (elt))
+           {
+             if (is_union)
+               permerror (input_location,
+                          "protected member %q+#D in anonymous union", elt);
+             else
+               permerror (input_location,
+                          "protected member %q+#D in anonymous struct", elt);
+           }
+       }
+
+      TREE_PRIVATE (elt) = TREE_PRIVATE (field);
+      TREE_PROTECTED (elt) = TREE_PROTECTED (field);
+
+      /* Recurse into the anonymous aggregates to handle correctly
+        access control (c++/24926):
+
+        class A {
+          union {
+            union {
+              int i;
+            };
+          };
+        };
+
+        int j=A().i;  */
+      if (DECL_NAME (elt) == NULL_TREE
+         && ANON_AGGR_TYPE_P (TREE_TYPE (elt)))
+       finish_struct_anon_r (elt, /*complain=*/false);
+    }
+}
+
 /* Check for things that are invalid.  There are probably plenty of other
    things we should check for also.  */
 
 static void
 finish_struct_anon (tree t)
 {
-  tree field;
-
-  for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+  for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
     {
       if (TREE_STATIC (field))
        continue;
@@ -2790,53 +2868,7 @@ finish_struct_anon (tree t)
 
       if (DECL_NAME (field) == NULL_TREE
          && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
-       {
-         bool is_union = TREE_CODE (TREE_TYPE (field)) == UNION_TYPE;
-         tree elt = TYPE_FIELDS (TREE_TYPE (field));
-         for (; elt; elt = DECL_CHAIN (elt))
-           {
-             /* We're generally only interested in entities the user
-                declared, but we also find nested classes by noticing
-                the TYPE_DECL that we create implicitly.  You're
-                allowed to put one anonymous union inside another,
-                though, so we explicitly tolerate that.  We use
-                TYPE_ANONYMOUS_P rather than ANON_AGGR_TYPE_P so that
-                we also allow unnamed types used for defining fields.  */
-             if (DECL_ARTIFICIAL (elt)
-                 && (!DECL_IMPLICIT_TYPEDEF_P (elt)
-                     || TYPE_ANONYMOUS_P (TREE_TYPE (elt))))
-               continue;
-
-             if (TREE_CODE (elt) != FIELD_DECL)
-               {
-                 if (is_union)
-                   permerror (input_location, "%q+#D invalid; an anonymous union can "
-                              "only have non-static data members", elt);
-                 else
-                   permerror (input_location, "%q+#D invalid; an anonymous struct can "
-                              "only have non-static data members", elt);
-                 continue;
-               }
-
-             if (TREE_PRIVATE (elt))
-               {
-                 if (is_union)
-                   permerror (input_location, "private member %q+#D in anonymous union", elt);
-                 else
-                   permerror (input_location, "private member %q+#D in anonymous struct", elt);
-               }
-             else if (TREE_PROTECTED (elt))
-               {
-                 if (is_union)
-                   permerror (input_location, "protected member %q+#D in anonymous union", elt);
-                 else
-                   permerror (input_location, "protected member %q+#D in anonymous struct", elt);
-               }
-
-             TREE_PRIVATE (elt) = TREE_PRIVATE (field);
-             TREE_PROTECTED (elt) = TREE_PROTECTED (field);
-           }
-       }
+       finish_struct_anon_r (field, /*complain=*/true);
     }
 }
 
index 8faee5a0a97e90ebcf4c7b0d4738950e21a7e638..176d9973f6ce8f8da68bcf1c74dede3ce15f9b6f 100644 (file)
@@ -1,3 +1,8 @@
+2013-09-04  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       PR c++/24926
+       * g++.dg/parse/access11.C: New.
+
 2013-09-04  David Edelsohn  <dje.gcc@gmail.com>
 
        * g++.dg/warn/weak1.C: Skip on AIX.
diff --git a/gcc/testsuite/g++.dg/parse/access11.C b/gcc/testsuite/g++.dg/parse/access11.C
new file mode 100644 (file)
index 0000000..7004fa7
--- /dev/null
@@ -0,0 +1,35 @@
+// PR c++/24926
+
+class A {
+  union {
+    int i;       // { dg-error "private" }
+  };
+  union {
+    int j;       // { dg-error "private" }
+  }; 
+  union {
+    union {
+      int k;     // { dg-error "private" }
+    };
+    union {
+      union {
+       int l;   // { dg-error "private" }
+      };
+      union {
+       int m;   // { dg-error "private" }
+       union {
+         int n; // { dg-error "private" }
+         int o; // { dg-error "private" }
+       };
+      };
+    };
+  };
+};
+
+int a1 = A().i;  // { dg-error "context" }
+int a2 = A().j;  // { dg-error "context" }
+int a3 = A().k;  // { dg-error "context" }
+int a4 = A().l;  // { dg-error "context" }
+int a5 = A().m;  // { dg-error "context" }
+int a6 = A().n;  // { dg-error "context" }
+int a7 = A().o;  // { dg-error "context" }