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  <ja...@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

Reply via email to