c++: base-clause parsing and implicit 'this' [PR100362]

Message ID 20210503164808.155944-1-ppalka@redhat.com
State New
Headers show
Series
  • c++: base-clause parsing and implicit 'this' [PR100362]
Related show

Commit Message

H.J. Lu via Gcc-patches May 3, 2021, 4:48 p.m.
My r11-6815 change to defer access checking when processing a
base-clause removed a pair of pushclass / popclass calls that seemed to
be unnecessary now that we'd also defer access checking while parsing
the base-clause.

But it turns out this makes a difference in the below testcase, where we
have a local class whose base clause implicitly uses the 'this' of the
enclosing class.  Before r11-6815, while parsing the base-clause of the
local class, maybe_resolve_dummy would fail to resolve the dummy 'this'
object because the current scope would be the local class.  Now, since
the current scope is the lambda, maybe_resolve_dummy succeeds and
returns the 'this' for the enclosing class Qux.  Later, during deferred
instantiation of the local class, we get confused trying to resolve the
access of 'a_' through this non-dummy 'this'.

So this patch just reinstates the calls to pushclass / popclass that
were removed in r11-6815.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?

gcc/cp/ChangeLog:

	PR c++/100362
	* parser.c (cp_parser_class_head): Reinstate calls to pushclass
	and popclass during parsing of the base-clause that were
	removed in r11-6815.

gcc/testsuite/ChangeLog:

	PR c++/100362
	* g++.dg/cpp1y/lambda-generic-100362.C: New test.
---
 gcc/cp/parser.c                               |  8 +++++-
 .../g++.dg/cpp1y/lambda-generic-100362.C      | 25 +++++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-100362.C

-- 
2.31.1.442.g7e39198978

Comments

H.J. Lu via Gcc-patches May 3, 2021, 4:55 p.m. | #1
On 5/3/21 12:48 PM, Patrick Palka wrote:
> My r11-6815 change to defer access checking when processing a

> base-clause removed a pair of pushclass / popclass calls that seemed to

> be unnecessary now that we'd also defer access checking while parsing

> the base-clause.

> 

> But it turns out this makes a difference in the below testcase, where we

> have a local class whose base clause implicitly uses the 'this' of the

> enclosing class.  Before r11-6815, while parsing the base-clause of the

> local class, maybe_resolve_dummy would fail to resolve the dummy 'this'

> object because the current scope would be the local class.  Now, since

> the current scope is the lambda, maybe_resolve_dummy succeeds and

> returns the 'this' for the enclosing class Qux.  Later, during deferred

> instantiation of the local class, we get confused trying to resolve the

> access of 'a_' through this non-dummy 'this'.

> 

> So this patch just reinstates the calls to pushclass / popclass that

> were removed in r11-6815.

> 

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK

> for trunk?


OK for trunk and 11.2.

> gcc/cp/ChangeLog:

> 

> 	PR c++/100362

> 	* parser.c (cp_parser_class_head): Reinstate calls to pushclass

> 	and popclass during parsing of the base-clause that were

> 	removed in r11-6815.

> 

> gcc/testsuite/ChangeLog:

> 

> 	PR c++/100362

> 	* g++.dg/cpp1y/lambda-generic-100362.C: New test.

> ---

>   gcc/cp/parser.c                               |  8 +++++-

>   .../g++.dg/cpp1y/lambda-generic-100362.C      | 25 +++++++++++++++++++

>   2 files changed, 32 insertions(+), 1 deletion(-)

>   create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-100362.C

> 

> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c

> index e1b1617da68..28752611b34 100644

> --- a/gcc/cp/parser.c

> +++ b/gcc/cp/parser.c

> @@ -25683,7 +25683,13 @@ cp_parser_class_head (cp_parser* parser,

>        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))

> -    bases = cp_parser_base_clause (parser);

> +    {

> +      if (type)

> +	pushclass (type);

> +      bases = cp_parser_base_clause (parser);

> +      if (type)

> +	popclass ();

> +    }

>     else

>       bases = NULL_TREE;

>   

> diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-100362.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-100362.C

> new file mode 100644

> index 00000000000..283c2c9477e

> --- /dev/null

> +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-100362.C

> @@ -0,0 +1,25 @@

> +// PR c++/100362

> +// { dg-do compile { target c++14 } }

> +

> +template <class>

> +struct Qux {

> +  struct A { } a_;

> +  A f();

> +

> +  void AsyncOp() {

> +    [](auto) {

> +      struct local : decltype(a_) {};

> +      local ptr;

> +    }(0);

> +

> +    [](auto) {

> +      struct local : decltype(f()) {};

> +      local ptr;

> +    }(0);

> +  }

> +};

> +

> +void corge() {

> +  Qux<int> qux;

> +  qux.AsyncOp();

> +}

>

Patch

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e1b1617da68..28752611b34 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -25683,7 +25683,13 @@  cp_parser_class_head (cp_parser* parser,
      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))
-    bases = cp_parser_base_clause (parser);
+    {
+      if (type)
+	pushclass (type);
+      bases = cp_parser_base_clause (parser);
+      if (type)
+	popclass ();
+    }
   else
     bases = NULL_TREE;
 
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-100362.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-100362.C
new file mode 100644
index 00000000000..283c2c9477e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-100362.C
@@ -0,0 +1,25 @@ 
+// PR c++/100362
+// { dg-do compile { target c++14 } }
+
+template <class>
+struct Qux {
+  struct A { } a_;
+  A f();
+
+  void AsyncOp() {
+    [](auto) {
+      struct local : decltype(a_) {};
+      local ptr;
+    }(0);
+
+    [](auto) {
+      struct local : decltype(f()) {};
+      local ptr;
+    }(0);
+  }
+};
+
+void corge() {
+  Qux<int> qux;
+  qux.AsyncOp();
+}