On 12/12/24 1:42 PM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
This ICE started with the recent prvalue optimization (r15-6052). In
cp_fold_r we have:
if (tree &init = TARGET_EXPR_INITIAL (stmt))
{
cp_walk_tree (&init, cp_fold_r, data, NULL);
// ...
tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt));
What can happen here is that originally the TARGET_EXPR is:
TARGET_EXPR <D.2747, <<< Unknown tree: aggr_init_expr
5
__ct_comp
D.2747
(struct subrange *) <<< Unknown tree: void_cst >>>
&TARGET_EXPR <D.2707, {.it=TARGET_EXPR <D.2695, ...>}> >>>>
but after the first cp_walk_tree we fold the D.2707 TARGET_EXPR into:
TARGET_EXPR <D.2707, <<< Unknown tree: expr_stmt
D.2707.it = TARGET_EXPR <D.2695, ...> >>>>
and then we pass the EXPR_STMT to maybe_constant_init, with D.2707 as
the object. But their types don't match anymore, so we crash. We'd
have to pass D.2707.it as the object for it to work.
But I don't think we need to pass any object to maybe_constant_init;
it'll grab the appropriate one itself.
Hmm, it seems to me that the crash is happening because the deduced type
is wrong, and so with this change we'll end up only producing an
initializer for the first member. Because cp_fold_r throws away the
information that initialized_type needs to know the type of the complete
object being initialized.
What if we move cp_fold_r of init after the maybe_constant_init?
constexpr-prvalue3.C is reduced from a large std::ranges libstdc++ test.
PR c++/117980
gcc/cp/ChangeLog:
* cp-gimplify.cc (cp_fold_r) <case TARGET_EXPR>: Don't pass an object
to maybe_constant_init.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/constexpr-prvalue2.C: New test.
* g++.dg/cpp0x/constexpr-prvalue3.C: New test.
---
gcc/cp/cp-gimplify.cc | 2 +-
.../g++.dg/cpp0x/constexpr-prvalue2.C | 15 +++++++++++
.../g++.dg/cpp0x/constexpr-prvalue3.C | 26 +++++++++++++++++++
3 files changed, 42 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue2.C
create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue3.C
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 623e2ee6e96..a861331c7c7 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -1477,7 +1477,7 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
*walk_subtrees = 0;
if (!flag_no_inline)
{
- tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt));
+ tree folded = maybe_constant_init (init);
if (folded != init && TREE_CONSTANT (folded))
init = folded;
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue2.C
b/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue2.C
new file mode 100644
index 00000000000..46053231cf8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue2.C
@@ -0,0 +1,15 @@
+// PR c++/117980
+// { dg-do compile { target c++11 } }
+// { dg-options "-O" }
+
+struct S {
+ constexpr S(S &); // { dg-warning "used but never defined" }
+ ~S();
+};
+struct B {
+ S s;
+};
+struct A {
+ B b;
+};
+void fn(B b) { A{b}; }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue3.C
b/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue3.C
new file mode 100644
index 00000000000..a2eb12c02d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue3.C
@@ -0,0 +1,26 @@
+// PR c++/117980
+// { dg-do compile { target c++11 } }
+// { dg-options "-O" }
+
+struct _Safe_iterator {
+ _Safe_iterator();
+ ~_Safe_iterator();
+};
+template <typename _Tp>
+struct vector {
+ vector(int) {}
+ constexpr _Safe_iterator end() {
+ return _Safe_iterator();
+ }
+};
+template <typename It> struct sentinel {
+ It it;
+};
+template <typename _Sent>
+struct subrange {
+ subrange(sentinel<_Safe_iterator>) {}
+};
+void test01() {
+ vector<int> v{0};
+ subrange<sentinel<_Safe_iterator>>{sentinel<_Safe_iterator>{v.end()}};
+}
base-commit: 2cbb2408a830a63fbd901a4da3bfd341cec4b6ef