diff mbox

[C++] Fix ICE with constexpr store to pointer to method (PR c++/79639)

Message ID 20170221164446.GU1849@tucnak
State New
Headers show

Commit Message

Jakub Jelinek Feb. 21, 2017, 4:44 p.m. UTC
Hi!

Apparently we can end up trying to store into a pointer-to-member
that has a PTRMEM_CST as its current value.  Later code in
cxx_eval_store_expression is upset that it isn't a CONSTRUCTOR when
the type is actually aggregate.

The following patch fixes that, bootstrapped/regtested on x86_64-linux
and i686-linux, though I admit I'm not really sure if this is the best fix.

2017-02-21  Jakub Jelinek  <jakub@redhat.com>

	PR c++/79639
	* constexpr.c (cxx_eval_store_expression): If *valp is a PTRMEM_CST,
	call cplus_expand_constant on it first.

	* g++.dg/cpp1y/constexpr-79639.C: New test. 


	Jakub

Comments

Jason Merrill Feb. 21, 2017, 5:52 p.m. UTC | #1
OK.

On Tue, Feb 21, 2017 at 8:44 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> Apparently we can end up trying to store into a pointer-to-member
> that has a PTRMEM_CST as its current value.  Later code in
> cxx_eval_store_expression is upset that it isn't a CONSTRUCTOR when
> the type is actually aggregate.
>
> The following patch fixes that, bootstrapped/regtested on x86_64-linux
> and i686-linux, though I admit I'm not really sure if this is the best fix.
>
> 2017-02-21  Jakub Jelinek  <jakub@redhat.com>
>
>         PR c++/79639
>         * constexpr.c (cxx_eval_store_expression): If *valp is a PTRMEM_CST,
>         call cplus_expand_constant on it first.
>
>         * g++.dg/cpp1y/constexpr-79639.C: New test.
>
> --- gcc/cp/constexpr.c.jj       2017-02-21 13:49:06.000000000 +0100
> +++ gcc/cp/constexpr.c  2017-02-21 14:57:30.290440638 +0100
> @@ -3518,11 +3518,12 @@ cxx_eval_store_expression (const constex
>          wants to modify it.  */
>        if (*valp == NULL_TREE)
>         {
> -         *valp = new_ctx.ctor = build_constructor (type, NULL);
> -         CONSTRUCTOR_NO_IMPLICIT_ZERO (new_ctx.ctor) = no_zero_init;
> +         *valp = build_constructor (type, NULL);
> +         CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp) = no_zero_init;
>         }
> -      else
> -       new_ctx.ctor = *valp;
> +      else if (TREE_CODE (*valp) == PTRMEM_CST)
> +       *valp = cplus_expand_constant (*valp);
> +      new_ctx.ctor = *valp;
>        new_ctx.object = target;
>      }
>
> --- gcc/testsuite/g++.dg/cpp1y/constexpr-79639.C.jj     2017-02-21 15:06:42.625475572 +0100
> +++ gcc/testsuite/g++.dg/cpp1y/constexpr-79639.C        2017-02-21 15:06:07.000000000 +0100
> @@ -0,0 +1,27 @@
> +// PR c++/79639
> +// { dg-do compile { target c++14 } }
> +
> +struct A
> +{
> +  void foo () {}
> +  void bar () {}
> +};
> +typedef void (A::*T) ();
> +
> +constexpr T
> +foo (T f)
> +{
> +  f = 0;
> +  return f;
> +}
> +
> +constexpr T
> +bar (T f)
> +{
> +  f = &A::bar;
> +  return f;
> +}
> +
> +constexpr T a = foo (&A::foo);
> +constexpr T b = foo (&A::foo);
> +static_assert (a == nullptr, "");
>
>         Jakub
diff mbox

Patch

--- gcc/cp/constexpr.c.jj	2017-02-21 13:49:06.000000000 +0100
+++ gcc/cp/constexpr.c	2017-02-21 14:57:30.290440638 +0100
@@ -3518,11 +3518,12 @@  cxx_eval_store_expression (const constex
 	 wants to modify it.  */
       if (*valp == NULL_TREE)
 	{
-	  *valp = new_ctx.ctor = build_constructor (type, NULL);
-	  CONSTRUCTOR_NO_IMPLICIT_ZERO (new_ctx.ctor) = no_zero_init;
+	  *valp = build_constructor (type, NULL);
+	  CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp) = no_zero_init;
 	}
-      else
-	new_ctx.ctor = *valp;
+      else if (TREE_CODE (*valp) == PTRMEM_CST)
+	*valp = cplus_expand_constant (*valp);
+      new_ctx.ctor = *valp;
       new_ctx.object = target;
     }
 
--- gcc/testsuite/g++.dg/cpp1y/constexpr-79639.C.jj	2017-02-21 15:06:42.625475572 +0100
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-79639.C	2017-02-21 15:06:07.000000000 +0100
@@ -0,0 +1,27 @@ 
+// PR c++/79639
+// { dg-do compile { target c++14 } }
+
+struct A
+{
+  void foo () {}
+  void bar () {}
+};
+typedef void (A::*T) ();
+
+constexpr T
+foo (T f)
+{
+  f = 0;
+  return f;
+}
+
+constexpr T
+bar (T f)
+{
+  f = &A::bar;
+  return f;
+}
+
+constexpr T a = foo (&A::foo);
+constexpr T b = foo (&A::foo);
+static_assert (a == nullptr, "");