We used to preserve deferred access check along with resolved template ids, but a tentative parsing firewall introduced additional layers of deferred access checks, so that we don't preserve the checks we want to any more.
This patch collapses the access check levels introduced by the firewall with those we wanted to preserve to begin with, saves them, pushes them one more layer up so that the firewall doesn't drop them, and then pushes new empty levels so balance out with the upcoming popping. We may want to avoid the pop_to_parent and one push after the save, and instead leave the firewall's scope before the final pop_to_parent. However, this patch is what I regression-tested successfully with check-g++ on x86_64-linux-gnu. Regstrapping on i686- and x86_64-linux-gnu now. Ok to install? for gcc/cp/ChangeLog PR c++/86823 * parser.c (cp_parser_template_id): Merge access checks from outside the tentative parsing firewall with those from inside, and save them all with the template id token. for gcc/testsuite/ChangeLog PR c++/86823 * g++.dg/pr86823.C: New. --- gcc/cp/parser.c | 12 ++++++++++++ gcc/testsuite/g++.dg/pr86823.C | 15 +++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 gcc/testsuite/g++.dg/pr86823.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index db0f0338179e..6a08b09715a7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16185,7 +16185,19 @@ cp_parser_template_id (cp_parser *parser, so the memory will not be reclaimed during token replacing below. */ token->u.tree_check_value = ggc_cleared_alloc<struct tree_check> (); token->u.tree_check_value->value = template_id; + /* Collapse the access check levels introduced by + tentative_firewall with the one we introduced ourselves. */ + pop_to_parent_deferring_access_checks (); + pop_to_parent_deferring_access_checks (); token->u.tree_check_value->checks = get_deferred_access_checks (); + /* Push the checks up one more level, so that the firewall + doesn't drop them on the floor when we return. Then, push + empty levels back in place so that they are popped + properly. */ + pop_to_parent_deferring_access_checks (); + push_deferring_access_checks (dk_deferred); + push_deferring_access_checks (dk_deferred); + push_deferring_access_checks (dk_deferred); token->keyword = RID_MAX; /* Purge all subsequent tokens. */ diff --git a/gcc/testsuite/g++.dg/pr86823.C b/gcc/testsuite/g++.dg/pr86823.C new file mode 100644 index 000000000000..18914b00aa8d --- /dev/null +++ b/gcc/testsuite/g++.dg/pr86823.C @@ -0,0 +1,15 @@ +// { dg-do compile } + +struct X { +private: + template<typename T> + struct Y { + int data; + }; +public: + int value; +}; + +int main() { + typename X::Y<int> a; // { dg-error "private" } +} -- Alexandre Oliva, freedom fighter https://FSFLA.org/blogs/lxo Be the change, be Free! FSF Latin America board member GNU Toolchain Engineer Free Software Evangelist Hay que enGNUrecerse, pero sin perder la terGNUra jamás-GNUChe