diff options
author | Paolo Carlini <paolo.carlini@oracle.com> | 2013-09-04 23:52:48 +0000 |
---|---|---|
committer | Paolo Carlini <paolo@gcc.gnu.org> | 2013-09-04 23:52:48 +0000 |
commit | 096a48656c7734c99f029b3c0e26c545b8644ec7 (patch) | |
tree | 570076f0b7a08c8f4adb498a312cf967f8a21b35 /gcc/cp/class.c | |
parent | c167bc5b7d51a6d582324040201106fab36723da (diff) | |
download | gcc-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.c | 132 |
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); } } |