On 1/17/25 1:31 PM, Marek Polacek wrote:
On Fri, Jan 17, 2025 at 08:10:24AM -0500, Jason Merrill wrote:
On 1/16/25 8:04 PM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
The recent r15-6369 unfortunately caused a bad wrong-code issue.
Here we have

    TARGET_EXPR <D.2996, (void) (D.2996 = {.status=0, .data={._vptr.Foo=&_ZTV3Foo 
+ 16}})>

and call cp_fold_r -> maybe_constant_init with object=D.2996.  In
cxx_eval_outermost_constant_expr we now take the type of the object
if present.  An object can't have type 'void' and so we continue to
evaluate the initializer.  That evaluates into a VOID_CST, meaning
we disregard the whole initializer, and terrible things ensue.

In that case, I'd think we want to use the value of 'object' (which should
be in ctx.ctor?) instead of the return value of
cxx_eval_constant_expression.

Ah, I'm sorry I didn't choose that approach.  Maybe like this, then?

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

OK.  Maybe also add an assert that TREE_TYPE (r) is close enough to type?

-- >8 --
The recent r15-6369 unfortunately caused a bad wrong-code issue.
Here we have

   TARGET_EXPR <D.2996, (void) (D.2996 = {.status=0, .data={._vptr.Foo=&_ZTV3Foo + 
16}})>

and call cp_fold_r -> maybe_constant_init with object=D.2996.  In
cxx_eval_outermost_constant_expr we now take the type of the object
if present.  An object can't have type 'void' and so we continue to
evaluate the initializer.  That evaluates into a VOID_CST, meaning
we disregard the whole initializer, and terrible things ensue.

For non-simple TARGET_EXPRs, we should return ctx.ctor rather than
the result of cxx_eval_constant_expression.

        PR c++/118396
        PR c++/118523

gcc/cp/ChangeLog:

        * constexpr.cc (cxx_eval_outermost_constant_expr): For non-simple
        TARGET_EXPRs, return ctx.ctor rather than the result of
        cxx_eval_constant_expression.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/constexpr-prvalue4.C: New test.
        * g++.dg/cpp1y/constexpr-prvalue3.C: New test.
---
  gcc/cp/constexpr.cc                           |  5 +++
  .../g++.dg/cpp0x/constexpr-prvalue4.C         | 33 ++++++++++++++
  .../g++.dg/cpp1y/constexpr-prvalue3.C         | 45 +++++++++++++++++++
  3 files changed, 83 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue4.C
  create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-prvalue3.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index c898e3bfa6e..078f7b19f24 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8978,6 +8978,11 @@ cxx_eval_outermost_constant_expr (tree t, bool 
allow_non_constant,
    r = cxx_eval_constant_expression (&ctx, r, vc_prvalue,
                                    &non_constant_p, &overflow_p);
+ /* If we got a non-simple TARGET_EXPR, the initializer was a sequence
+     of statements, and the result ought to be stored in ctx.ctor.  */
+  if (r == void_node && !constexpr_dtor && ctx.ctor)
+    r = ctx.ctor;
+
    if (!constexpr_dtor)
      verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
    else
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue4.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue4.C
new file mode 100644
index 00000000000..afcee65f880
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue4.C
@@ -0,0 +1,33 @@
+// PR c++/118396
+// { dg-do run { target c++11 } }
+// { dg-options "-O" }
+
+void *operator new(__SIZE_TYPE__, void *__p) { return __p; }
+
+struct Foo {
+  virtual ~Foo() = default;
+};
+struct Data {
+  int status;
+  Foo data{};
+};
+
+Data *P, *Q;
+
+struct vector {
+  vector (const Data &__value) {
+    P = static_cast<Data *>(__builtin_operator_new(0));
+    new (P) Data (__value);
+    Q = P + 1;
+  }
+  Data *begin() { return P; }
+  Data *end() { return Q; }
+};
+
+int
+main ()
+{
+  vector items_(Data{});
+  for (auto item : items_)
+    item.status == 0 ? void() : __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-prvalue3.C 
b/gcc/testsuite/g++.dg/cpp1y/constexpr-prvalue3.C
new file mode 100644
index 00000000000..8ea86c60be5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-prvalue3.C
@@ -0,0 +1,45 @@
+// PR c++/118523
+// { dg-do compile { target c++14 } }
+// { dg-options "-O2 -Wall" }
+
+struct __new_allocator {
+  constexpr __new_allocator() {}
+  __new_allocator(__new_allocator &) {}
+};
+template <typename> using __allocator_base = __new_allocator;
+template <typename> struct allocator_traits;
+template <typename> struct allocator : __allocator_base<int> {};
+template <typename _Tp> struct allocator_traits<allocator<_Tp>> {
+  using pointer = _Tp *;
+  template <typename _Up> using rebind_alloc = allocator<_Up>;
+  static void deallocate(allocator<_Tp>, pointer, long);
+};
+struct __alloc_traits : allocator_traits<allocator<int>> {};
+struct _Vector_impl_data {
+  __alloc_traits::pointer _M_start;
+  __alloc_traits::pointer _M_end_of_storage;
+  constexpr _Vector_impl_data() : _M_start(), _M_end_of_storage() {}
+};
+struct _Vector_impl : __alloc_traits::rebind_alloc<int>, _Vector_impl_data {};
+struct _Vector_base {
+  ~_Vector_base() {
+    _M_deallocate(_M_impl._M_start,
+                  _M_impl._M_end_of_storage - _M_impl._M_start);
+  }
+  _Vector_impl _M_impl;
+  void _M_deallocate(__alloc_traits::pointer __p, long __n) {
+    if (__p)
+      __alloc_traits::deallocate(_M_impl, __p, __n);
+  }
+};
+struct vector : protected _Vector_base {};
+struct S {
+  vector a{};
+};
+struct B2 {
+  B2(S);
+};
+struct E : B2 {
+  E(S opts = {}) : B2{opts} {}
+};
+void fun() { E{}; }

base-commit: 71280df05f28fd568f8b863dd700c0be2f2443a8

Reply via email to