... assuming the general idea makes sense, this version may be better because, at the cost of 3 lines of code duplication, it cuts the unnecessary function calls, eg exactly zero if the struct doesn't have anonymous aggregates at all. The patch is also easier to read ;)

Booted and tested x86_64-linux.

Paolo.

/////////////
Index: cp/class.c
===================================================================
--- cp/class.c  (revision 202241)
+++ cp/class.c  (working copy)
@@ -2773,15 +2773,96 @@ 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 (!complain && TREE_STATIC (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);
+
+      /* Recur inside 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 +2871,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: testsuite/g++.dg/parse/access11.C
===================================================================
--- testsuite/g++.dg/parse/access11.C   (revision 0)
+++ testsuite/g++.dg/parse/access11.C   (working copy)
@@ -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" }

Reply via email to