diff mbox series

c++: Fix ICE during constexpr virtual call evaluation [PR93633]

Message ID 20200209072735.GG17695@tucnak
State New
Headers show
Series c++: Fix ICE during constexpr virtual call evaluation [PR93633] | expand

Commit Message

Jakub Jelinek Feb. 9, 2020, 7:27 a.m. UTC
Hi!

The first (valid) testcase ICEs because for
  A *a = new B ();
  a->foo (); // virtual method call
we actually see &heap  and the "heap " objects don't have the class or
whatever else type was used in new expression, but an array type containing
one (or more of those for array new) and so when using TYPE_BINFO (objtype)
on it we ICE.
This patch handles this special case, and otherwise punts (as shown e.g. in
the second testcase, where because the heap object is already deleted,
we don't really want to allow it to be used.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2020-02-08  Jakub Jelinek  <jakub@redhat.com>

	PR c++/93633
	* constexpr.c (cxx_eval_constant_expression): If obj is heap var with
	ARRAY_TYPE, use the element type.  Punt if objtype after that is not
	a class type.

	* g++.dg/cpp2a/constexpr-new11.C: New test.
	* g++.dg/cpp2a/constexpr-new12.C: New test.
	* g++.dg/cpp2a/constexpr-new13.C: New test.


	Jakub

Comments

Jason Merrill Feb. 9, 2020, 11:26 a.m. UTC | #1
On 2/9/20 2:27 AM, Jakub Jelinek wrote:
> Hi!
> 
> The first (valid) testcase ICEs because for
>    A *a = new B ();
>    a->foo (); // virtual method call
> we actually see &heap  and the "heap " objects don't have the class or
> whatever else type was used in new expression, but an array type containing
> one (or more of those for array new) and so when using TYPE_BINFO (objtype)
> on it we ICE.
> This patch handles this special case, and otherwise punts (as shown e.g. in
> the second testcase, where because the heap object is already deleted,
> we don't really want to allow it to be used.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

> 2020-02-08  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/93633
> 	* constexpr.c (cxx_eval_constant_expression): If obj is heap var with
> 	ARRAY_TYPE, use the element type.  Punt if objtype after that is not
> 	a class type.
> 
> 	* g++.dg/cpp2a/constexpr-new11.C: New test.
> 	* g++.dg/cpp2a/constexpr-new12.C: New test.
> 	* g++.dg/cpp2a/constexpr-new13.C: New test.
> 
> --- gcc/cp/constexpr.c.jj	2020-02-08 10:58:15.434064005 +0100
> +++ gcc/cp/constexpr.c	2020-02-08 14:15:55.356768622 +0100
> @@ -6027,6 +6027,17 @@ cxx_eval_constant_expression (const cons
>   	       && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1)))
>   	  obj = TREE_OPERAND (obj, 0);
>   	tree objtype = TREE_TYPE (obj);
> +	if (VAR_P (obj)
> +	    && DECL_NAME (obj) == heap_identifier
> +	    && TREE_CODE (objtype) == ARRAY_TYPE)
> +	  objtype = TREE_TYPE (objtype);
> +	if (!CLASS_TYPE_P (objtype))
> +	  {
> +	    if (!ctx->quiet)
> +	      error_at (loc, "expression %qE is not a constant expression", t);
> +	    *non_constant_p = true;
> +	    return t;
> +	  }
>   	/* Find the function decl in the virtual functions list.  TOKEN is
>   	   the DECL_VINDEX that says which function we're looking for.  */
>   	tree virtuals = BINFO_VIRTUALS (TYPE_BINFO (objtype));
> --- gcc/testsuite/g++.dg/cpp2a/constexpr-new11.C.jj	2020-02-08 14:22:34.740789172 +0100
> +++ gcc/testsuite/g++.dg/cpp2a/constexpr-new11.C	2020-02-08 14:21:50.689448695 +0100
> @@ -0,0 +1,31 @@
> +// PR c++/93633
> +// { dg-do compile { target c++2a } }
> +
> +struct A {
> +  constexpr A () : a (0) {}
> +  constexpr virtual int foo () { return 1 + a * 4; }
> +  int a;
> +};
> +
> +struct B : A {
> +  constexpr B () : b (0) {}
> +  constexpr virtual int foo () { return 0 + b * 4; }
> +  int b;
> +};
> +
> +constexpr int
> +foo ()
> +{
> +  A *a = new B ();
> +  a->a = 4;
> +  int r = a->foo ();
> +  delete a;
> +  return r;
> +}
> +
> +int
> +main ()
> +{
> +  constexpr auto a = foo ();
> +  static_assert (a == 0);
> +}
> --- gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C.jj	2020-02-08 14:22:38.043739717 +0100
> +++ gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C	2020-02-08 14:24:04.119451025 +0100
> @@ -0,0 +1,26 @@
> +// PR c++/93633
> +// { dg-do compile { target c++2a } }
> +
> +struct A {
> +  constexpr A () : a (0) {}
> +  constexpr virtual int foo () { return 1 + a * 4; }
> +  int a;
> +};
> +
> +struct B : A {
> +  constexpr B () : b (0) {}
> +  constexpr virtual int foo () { return 0 + b * 4; }
> +  int b;
> +};
> +
> +constexpr int
> +foo ()
> +{
> +  A *a = new B ();
> +  a->a = 4;
> +  delete a;
> +  int r = a->foo ();
> +  return r;
> +}
> +
> +constexpr auto a = foo ();	// { dg-error "is not a constant expression" }
> --- gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C.jj	2020-02-08 14:22:41.060694553 +0100
> +++ gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C	2020-02-08 14:25:38.783033750 +0100
> @@ -0,0 +1,26 @@
> +// PR c++/93633
> +// { dg-do compile { target c++2a } }
> +
> +struct A {
> +  constexpr A () : a (0) {}
> +  virtual int foo () { return 1 + a * 4; }
> +  int a;
> +};
> +
> +struct B : A {
> +  constexpr B () : b (0) {}
> +  virtual int foo () { return 0 + b * 4; }	// { dg-message "declared here" }
> +  int b;
> +};
> +
> +constexpr int
> +foo ()
> +{
> +  A *a = new B ();
> +  a->a = 4;
> +  int r = a->foo ();	// { dg-error "call to non-.constexpr. function" }
> +  delete a;
> +  return r;
> +}
> +
> +constexpr auto a = foo ();
> 
> 	Jakub
>
diff mbox series

Patch

--- gcc/cp/constexpr.c.jj	2020-02-08 10:58:15.434064005 +0100
+++ gcc/cp/constexpr.c	2020-02-08 14:15:55.356768622 +0100
@@ -6027,6 +6027,17 @@  cxx_eval_constant_expression (const cons
 	       && DECL_FIELD_IS_BASE (TREE_OPERAND (obj, 1)))
 	  obj = TREE_OPERAND (obj, 0);
 	tree objtype = TREE_TYPE (obj);
+	if (VAR_P (obj)
+	    && DECL_NAME (obj) == heap_identifier
+	    && TREE_CODE (objtype) == ARRAY_TYPE)
+	  objtype = TREE_TYPE (objtype);
+	if (!CLASS_TYPE_P (objtype))
+	  {
+	    if (!ctx->quiet)
+	      error_at (loc, "expression %qE is not a constant expression", t);
+	    *non_constant_p = true;
+	    return t;
+	  }
 	/* Find the function decl in the virtual functions list.  TOKEN is
 	   the DECL_VINDEX that says which function we're looking for.  */
 	tree virtuals = BINFO_VIRTUALS (TYPE_BINFO (objtype));
--- gcc/testsuite/g++.dg/cpp2a/constexpr-new11.C.jj	2020-02-08 14:22:34.740789172 +0100
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-new11.C	2020-02-08 14:21:50.689448695 +0100
@@ -0,0 +1,31 @@ 
+// PR c++/93633
+// { dg-do compile { target c++2a } }
+
+struct A {
+  constexpr A () : a (0) {}
+  constexpr virtual int foo () { return 1 + a * 4; }
+  int a;
+};
+
+struct B : A {
+  constexpr B () : b (0) {}
+  constexpr virtual int foo () { return 0 + b * 4; }
+  int b;
+};
+
+constexpr int
+foo ()
+{
+  A *a = new B ();
+  a->a = 4;
+  int r = a->foo ();
+  delete a;
+  return r;
+}
+
+int
+main ()
+{
+  constexpr auto a = foo ();
+  static_assert (a == 0);
+}
--- gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C.jj	2020-02-08 14:22:38.043739717 +0100
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C	2020-02-08 14:24:04.119451025 +0100
@@ -0,0 +1,26 @@ 
+// PR c++/93633
+// { dg-do compile { target c++2a } }
+
+struct A {
+  constexpr A () : a (0) {}
+  constexpr virtual int foo () { return 1 + a * 4; }
+  int a;
+};
+
+struct B : A {
+  constexpr B () : b (0) {}
+  constexpr virtual int foo () { return 0 + b * 4; }
+  int b;
+};
+
+constexpr int
+foo ()
+{
+  A *a = new B ();
+  a->a = 4;
+  delete a;
+  int r = a->foo ();
+  return r;
+}
+
+constexpr auto a = foo ();	// { dg-error "is not a constant expression" }
--- gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C.jj	2020-02-08 14:22:41.060694553 +0100
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C	2020-02-08 14:25:38.783033750 +0100
@@ -0,0 +1,26 @@ 
+// PR c++/93633
+// { dg-do compile { target c++2a } }
+
+struct A {
+  constexpr A () : a (0) {}
+  virtual int foo () { return 1 + a * 4; }
+  int a;
+};
+
+struct B : A {
+  constexpr B () : b (0) {}
+  virtual int foo () { return 0 + b * 4; }	// { dg-message "declared here" }
+  int b;
+};
+
+constexpr int
+foo ()
+{
+  A *a = new B ();
+  a->a = 4;
+  int r = a->foo ();	// { dg-error "call to non-.constexpr. function" }
+  delete a;
+  return r;
+}
+
+constexpr auto a = foo ();