From: Paolo Carlini Date: Wed, 4 Sep 2013 23:52:48 +0000 (+0000) Subject: re PR c++/24926 (gcc ignores access level violation for anonymous structs) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=096a48656c7734c99f029b3c0e26c545b8644ec7;p=gcc.git re PR c++/24926 (gcc ignores access level violation for anonymous structs) /cp 2013-09-04 Paolo Carlini PR c++/24926 * class.c (finish_struct_anon_r): New. (finish_struct_anon): Use it. /testsuite 2013-09-04 Paolo Carlini PR c++/24926 * g++.dg/parse/access11.C: New. From-SVN: r202266 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index db4cd660af3..be8258dcf3e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2013-09-04 Paolo Carlini + + PR c++/24926 + * class.c (finish_struct_anon_r): New. + (finish_struct_anon): Use it. + 2013-09-04 Gabriel Dos Reis * cxx-pretty-print.h (cxx_pretty_printer::simple_type_specifier): diff --git a/gcc/cp/class.c b/gcc/cp/class.c index bcd8076b09d..3d34b92cfb1 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); } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8faee5a0a97..176d9973f6c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-09-04 Paolo Carlini + + PR c++/24926 + * g++.dg/parse/access11.C: New. + 2013-09-04 David Edelsohn * g++.dg/warn/weak1.C: Skip on AIX. diff --git a/gcc/testsuite/g++.dg/parse/access11.C b/gcc/testsuite/g++.dg/parse/access11.C new file mode 100644 index 00000000000..7004fa76401 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/access11.C @@ -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" }