In this testcase we have C c = bar (X{1}); which store_init_value sees as c = TARGET_EXPR <D.2332, bar (TARGET_EXPR <D.2298, {.i=1, .n=(&<PLACEHOLDER_EXPR struct X>)->i}>)> i.e. we're initializing "c" with a TARGET_EXPR. We call replace_placeholders that walks the whole tree to substitute the placeholders. Eventually we find the nested <PLACEHOLDER_EXPR struct X> but that's for another object, so we crash. Seems that we shouldn't have stepped into the second TARGET_EXPR at all; it has nothing to with "c", it's bar's argument.
It occurred to me that we shouldn't step into CALL_EXPRs and leave the placeholders in function arguments to cp_gimplify_init_expr which calls replace_placeholders for constructors. Not sure if it's enough to handle CALL_EXPRs like this, anything else? Bootstrapped/regtested on x86_64-linux, ok for trunk and 6? 2017-03-07 Marek Polacek <pola...@redhat.com> PR c++/79937 - ICE in replace_placeholders_r * tree.c (replace_placeholders_r): Don't walk into CALL_EXPRs. * g++.dg/cpp1y/nsdmi-aggr7.C: New test. diff --git gcc/cp/tree.c gcc/cp/tree.c index d3c63b8..6a4f065 100644 --- gcc/cp/tree.c +++ gcc/cp/tree.c @@ -2751,6 +2751,11 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_) switch (TREE_CODE (*t)) { + case CALL_EXPR: + /* Don't mess with placeholders in an unrelated object. */ + *walk_subtrees = false; + break; + case PLACEHOLDER_EXPR: { tree x = obj; diff --git gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C index e69de29..c2fd404 100644 --- gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C +++ gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C @@ -0,0 +1,21 @@ +// PR c++/79937 +// { dg-do compile { target c++14 } } + +struct C {}; + +struct X { + unsigned i; + unsigned n = i; +}; + +C +bar (X) +{ + return {}; +} + +void +foo () +{ + C c = bar (X{1}); +} Marek