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;
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. */
|| 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++)
/* 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. */
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))
--- /dev/null
+// 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 { };
--- /dev/null
+// 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;