aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/parser.c30
-rw-r--r--gcc/cp/pt.c16
-rw-r--r--gcc/testsuite/g++.dg/parse/access12.C24
-rw-r--r--gcc/testsuite/g++.dg/template/access35.C19
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;