diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/parser.c | 30 | ||||
-rw-r--r-- | gcc/cp/pt.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/parse/access12.C | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/access35.C | 19 |
4 files changed, 68 insertions, 21 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index eeffc2e..4b2bca3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -25576,19 +25576,11 @@ cp_parser_class_head (cp_parser* parser, is valid. */ - /* Get the list of base-classes, if there is one. */ + /* Get the list of base-classes, if there is one. Defer access checking + until the entire list has been seen, as per [class.access.general]. */ + push_deferring_access_checks (dk_deferred); if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) - { - /* PR59482: enter the class scope so that base-specifiers are looked - up correctly. */ - if (type) - pushclass (type); - bases = cp_parser_base_clause (parser); - /* PR59482: get out of the previously pushed class scope so that the - subsequent pops pop the right thing. */ - if (type) - popclass (); - } + bases = cp_parser_base_clause (parser); else bases = NULL_TREE; @@ -25597,6 +25589,20 @@ cp_parser_class_head (cp_parser* parser, if (type && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) xref_basetypes (type, bases); + /* Now that all bases have been seen and attached to the class, check + accessibility of the types named in the base-clause. This must be + done relative to the class scope, so that we accept e.g. + + struct A { protected: struct B {}; }; + struct C : A::B, A {}; // OK: A::B is accessible via base A + + as per [class.access.general]. */ + if (type) + pushclass (type); + pop_to_parent_deferring_access_checks (); + if (type) + popclass (); + done: /* Leave the scope given by the nested-name-specifier. We will enter the class scope itself while processing the members. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index c9f5811..bcf4c6e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -11825,17 +11825,14 @@ instantiate_class_template_1 (tree type) || COMPLETE_OR_OPEN_TYPE_P (TYPE_CONTEXT (type))); base_list = NULL_TREE; + /* Defer access checking while we substitute into the types named in + the base-clause. */ + push_deferring_access_checks (dk_deferred); if (BINFO_N_BASE_BINFOS (pbinfo)) { tree pbase_binfo; - tree pushed_scope; int i; - /* We must enter the scope containing the type, as that is where - the accessibility of types named in dependent bases are - looked up from. */ - pushed_scope = push_scope (CP_TYPE_CONTEXT (type)); - /* Substitute into each of the bases to determine the actual basetypes. */ for (i = 0; BINFO_BASE_ITERATE (pbinfo, i, pbase_binfo); i++) @@ -11877,9 +11874,6 @@ instantiate_class_template_1 (tree type) /* The list is now in reverse order; correct that. */ base_list = nreverse (base_list); - - if (pushed_scope) - pop_scope (pushed_scope); } /* Now call xref_basetypes to set up all the base-class information. */ @@ -11897,6 +11891,10 @@ instantiate_class_template_1 (tree type) class, except we also need to push the enclosing classes. */ push_nested_class (type); + /* Now check accessibility of the types named in its base-clause, + relative to the scope of the class. */ + pop_to_parent_deferring_access_checks (); + /* Now members are processed in the order of declaration. */ for (member = CLASSTYPE_DECL_LIST (pattern); member; member = TREE_CHAIN (member)) diff --git a/gcc/testsuite/g++.dg/parse/access12.C b/gcc/testsuite/g++.dg/parse/access12.C new file mode 100644 index 0000000..6963e0e --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/access12.C @@ -0,0 +1,24 @@ +// Example 2 of [class.access.general] +// { dg-do compile } + +class A { + typedef int I; // private member + I f(); + friend I g(I); + static I x; + template<int> struct Q; + template<int> friend struct R; +protected: + struct B { }; +}; + +A::I A::f() { return 0; } +A::I g(A::I p = A::x); +A::I g(A::I p) { return 0; } +A::I A::x = 0; +// FIXME: We reject these two declarations because access checking of A::I +// is not performed in the scope of the class being declared. +// template<A::I> struct A::Q { }; +// template<A::I> struct R { }; + +struct D: A::B, A { }; diff --git a/gcc/testsuite/g++.dg/template/access35.C b/gcc/testsuite/g++.dg/template/access35.C new file mode 100644 index 0000000..70197eb --- /dev/null +++ b/gcc/testsuite/g++.dg/template/access35.C @@ -0,0 +1,19 @@ +// PR c++/82613 +// { dg-do compile } + +template <typename T> class B; + +class A { + friend class B<A>; + class Type {}; +}; + +template <typename T> +class B : T::Type { protected: class Type {}; }; + +B<A> b; + +template <typename T> +class C : B<T>::Type, B<T> {}; + +C<A> c; |