... 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" }