diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index bfd8aeae39f..8b1658decba 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -26559,7 +26559,23 @@ cp_parser_class_head (cp_parser* parser, if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false)) qualified_p = true; - push_deferring_access_checks (dk_no_check); + /* It is OK to define an inaccessible class; for example: + + class A { class B; }; + class A::B {}; + + So we want to ignore access when parsing the class name. + However, we might be tentatively parsing what is really an + elaborated-type-specifier naming a template-id, e.g. + + struct C<&D::m> c; + + In this case the tentative parse as a class-head will fail, but not + before cp_parser_template_id splices in a CPP_TEMPLATE_ID token. + Since dk_no_check is sticky, we must instead use dk_deferred so that + any such CPP_TEMPLATE_ID token created during this tentative parse + will correctly capture the access checks imposed by the template-id . */ + push_deferring_access_checks (dk_deferred); /* Determine the name of the class. Begin by looking for an optional nested-name-specifier. */ @@ -26586,11 +26602,6 @@ cp_parser_class_head (cp_parser* parser, The proposed resolution for Core Issue 180 says that wherever you see `class T::X' you should treat `X' as a type-name. - It is OK to define an inaccessible class; for example: - - class A { class B; }; - class A::B {}; - We do not know if we will see a class-name, or a template-name. We look for a class-name first, in case the class-name is a template-id; if we looked for the diff --git a/gcc/testsuite/g++.dg/parse/access14.C b/gcc/testsuite/g++.dg/parse/access14.C new file mode 100644 index 00000000000..bdbc7f6ee2b --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/access14.C @@ -0,0 +1,18 @@ +// PR c++/108275 + +struct A { + int i; +private: + int j; +}; + +template +struct B { + struct C { }; +private: + template struct D { }; +}; + +struct B<&A::j> b; // { dg-error "private" } +struct B<&A::j>::C c; // { dg-error "private" } +struct B<&A::i>::D<0> d; // { dg-error "private" }