c++: Fix ICE during constexpr virtual call evaluation [PR93633]
authorJakub Jelinek <jakub@redhat.com>
Sun, 9 Feb 2020 11:32:22 +0000 (12:32 +0100)
committerJakub Jelinek <jakub@redhat.com>
Sun, 9 Feb 2020 11:32:22 +0000 (12:32 +0100)
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.

2020-02-09  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/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp2a/constexpr-new11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C [new file with mode: 0644]

index dff6a170580d30dfb50b2d734e4064c8485bdfa0..90f26c90918df78684a57042bdb73add685c37c7 100644 (file)
@@ -1,3 +1,10 @@
+2020-02-09  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.
+
 2020-02-08  Jason Merrill  <jason@redhat.com>
 
        PR c++/90691
index 192ba566427df22dababf95b4616b40b61d701f8..6495cf88e6916add1a73f71b3ed536c73a552ce6 100644 (file)
@@ -6063,6 +6063,17 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
               && 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));
index c47f3fb98dd80e29fd88a48609dfd2b1a0a4f52e..66806752bb60852e440ad4d9bbbd0d8790710469 100644 (file)
@@ -1,3 +1,10 @@
+2020-02-09  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/93633
+       * g++.dg/cpp2a/constexpr-new11.C: New test.
+       * g++.dg/cpp2a/constexpr-new12.C: New test.
+       * g++.dg/cpp2a/constexpr-new13.C: New test.
+
 2020-02-08  Andrew Pinski  <apinski@marvel.com>
 
        PR target/91927
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new11.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new11.C
new file mode 100644 (file)
index 0000000..26658d0
--- /dev/null
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new12.C
new file mode 100644 (file)
index 0000000..2dedcd2
--- /dev/null
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new13.C
new file mode 100644 (file)
index 0000000..2121903
--- /dev/null
@@ -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 ();