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

Jason Merrill jason@redhat.com
Sun Feb 9 11:26:00 GMT 2020


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
> 



More information about the Gcc-patches mailing list