aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/class.c
diff options
context:
space:
mode:
authorPaolo Carlini <paolo.carlini@oracle.com>2013-09-04 23:52:48 +0000
committerPaolo Carlini <paolo@gcc.gnu.org>2013-09-04 23:52:48 +0000
commit096a48656c7734c99f029b3c0e26c545b8644ec7 (patch)
tree570076f0b7a08c8f4adb498a312cf967f8a21b35 /gcc/cp/class.c
parentc167bc5b7d51a6d582324040201106fab36723da (diff)
downloadgcc-096a48656c7734c99f029b3c0e26c545b8644ec7.zip
gcc-096a48656c7734c99f029b3c0e26c545b8644ec7.tar.gz
gcc-096a48656c7734c99f029b3c0e26c545b8644ec7.tar.bz2
re PR c++/24926 (gcc ignores access level violation for anonymous structs)
/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
Diffstat (limited to 'gcc/cp/class.c')
-rw-r--r--gcc/cp/class.c132
1 files changed, 82 insertions, 50 deletions
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index bcd8076..3d34b92 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -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);
}
}