diff mbox

[C++] PR 24926

Message ID 5226949A.5050706@oracle.com
State New
Headers show

Commit Message

Paolo Carlini Sept. 4, 2013, 2:02 a.m. UTC
Hi,

of the various access control issues we have got, this one seems rather 
manageable.

It seems to me that in case of nested anonymous aggregates what is 
needed to get the access control right is just a bit of recursion, to 
completely propagate the access from the outer to the inner aggregates. 
The patch seems large but in fact just moves to a recursive helper the 
code that currently handles anonymous aggregates in finish_struct_anon.

Patch appears to work well, no regressions etc, I'm not 100% sure we 
couldn't simplify a bit the new finish_struct_anon_r.

Thanks!
Paolo.

////////////////////////
/cp
2013-09-04

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

/testsuite
2013-09-04

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

Patch

Index: cp/class.c
===================================================================
--- cp/class.c	(revision 202231)
+++ cp/class.c	(working copy)
@@ -2773,73 +2773,112 @@  warn_hidden (tree t)
     }
 }
 
-/* Check for things that are invalid.  There are probably plenty of other
-   things we should check for also.  */
+/* Recursive helper for finish_struct_anon.  */
 
 static void
-finish_struct_anon (tree t)
+finish_struct_anon_r (tree field, bool complain)
 {
-  tree field;
-
-  for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+  if (DECL_NAME (field) == NULL_TREE
+      && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
     {
-      if (TREE_STATIC (field))
-	continue;
-      if (TREE_CODE (field) != FIELD_DECL)
-	continue;
+      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 (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))
+	  if (!complain && TREE_STATIC (elt))
+	    continue;
+
+	  if (TREE_CODE (elt) != FIELD_DECL)
 	    {
-	      /* 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 "
+		    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 "
+		    permerror (input_location,
+			       "%q+#D invalid; an anonymous struct can "
 			       "only have non-static data members", elt);
-		  continue;
 		}
+	      continue;
+	    }
 
+	  if (complain)
+	    {
 	      if (TREE_PRIVATE (elt))
 		{
 		  if (is_union)
-		    permerror (input_location, "private member %q+#D in anonymous union", elt);
+		    permerror (input_location,
+			       "private member %q+#D in anonymous union",
+			       elt);
 		  else
-		    permerror (input_location, "private member %q+#D in anonymous struct", elt);
+		    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);
+		    permerror (input_location,
+			       "protected member %q+#D in anonymous union",
+			       elt);
 		  else
-		    permerror (input_location, "protected member %q+#D in anonymous struct", elt);
+		    permerror (input_location,
+			       "protected member %q+#D in anonymous struct",
+			       elt);
 		}
+	    }
 
-	      TREE_PRIVATE (elt) = TREE_PRIVATE (field);
-	      TREE_PROTECTED (elt) = TREE_PROTECTED (field);
-	    }
+	  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;  */
+	  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)
+{
+  for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+    {
+      if (TREE_STATIC (field))
+	continue;
+      if (TREE_CODE (field) != FIELD_DECL)
+	continue;
+
+      finish_struct_anon_r (field, /*complain=*/true);
+    }
+}
+
 /* Add T to CLASSTYPE_DECL_LIST of current_class_type which
    will be used later during class template instantiation.
    When FRIEND_P is zero, T can be a static member data (VAR_DECL),
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" }