On Thu, Apr 25, 2024 at 02:02:32PM +0200, Jakub Jelinek wrote: > I've tried the following patch, but unfortunately that lead to large > number of regressions: > +FAIL: g++.dg/cpp0x/initlist25.C -std=c++17 (test for excess errors)
So the reduced testcase for this is template <typename T, typename U> struct A { T a1; U a2; template <typename V, typename W, bool = true> constexpr A(V &&x, W &&y) : a1(x), a2(y) {} }; template <typename> struct B; namespace std { template <class> struct initializer_list { int *_M_array; decltype (sizeof 0) _M_len; }; } template <typename T, typename U> struct C { void foo (std::initializer_list<A<const T, U>>); }; template <class> struct D; template <typename T, typename = D<T>, typename = B<T>> struct E { E (const char *); ~E (); }; int main () { C<E<char>, E<char>> m; m.foo ({{"t", "t"}, {"y", "y"}}); } Without the patch I've just posted or even with the earlier version of the patch the _ZN1AIK1EIc1DIcE1BIcEES5_EC[12]IRA2_KcSB_Lb1EEEOT_OT0_ ctors were emitted, but with this patch they are unresolved externals. The reason is that the code actually uses (calls) the _ZN1AIK1EIc1DIcE1BIcEES5_EC1IRA2_KcSB_Lb1EEEOT_OT0_ __ct_comp constructor, that one has TREE_USED, while the _ZN1AIK1EIc1DIcE1BIcEES5_EC2IRA2_KcSB_Lb1EEEOT_OT0_ __ct_base constructor is not TREE_USED. But the c_parse_final_cleanups loop over FOR_EACH_VEC_SAFE_ELT (deferred_fns, i, decl) will ignore the TREE_USED __ct_comp because it is an alias and so has !DECL_SAVED_TREE: 5273 if (!DECL_SAVED_TREE (decl)) 5274 continue; With the following incremental patch the tests in make check-g++ (haven't tried the coroutine one) which failed with the earlier patch now pass. --- gcc/cp/decl2.cc.jj 2024-04-25 10:52:21.057535959 +0200 +++ gcc/cp/decl2.cc 2024-04-25 16:19:17.385547357 +0200 @@ -5271,7 +5271,19 @@ c_parse_final_cleanups (void) generate_tls_wrapper (decl); if (!DECL_SAVED_TREE (decl)) - continue; + { + cgraph_node *node; + tree tgt; + /* Even when maybe_clone_body created same body alias + has no DECL_SAVED_TREE, if its alias target does, + don't skip it. */ + if (!DECL_CLONED_FUNCTION (decl) + || !(node = cgraph_node::get (decl)) + || !node->cpp_implicit_alias + || !(tgt = node->get_alias_target_tree ()) + || !DECL_SAVED_TREE (tgt)) + continue; + } cgraph_node *node = cgraph_node::get_create (decl); @@ -5299,7 +5311,7 @@ c_parse_final_cleanups (void) node = node->get_alias_target (); node->call_for_symbol_thunks_and_aliases (clear_decl_external, - NULL, true); + NULL, true); /* If we mark !DECL_EXTERNAL one of the symbols in some comdat group, we need to mark all symbols in the same comdat group that way. */ @@ -5309,7 +5321,7 @@ c_parse_final_cleanups (void) next != node; next = dyn_cast<cgraph_node *> (next->same_comdat_group)) next->call_for_symbol_thunks_and_aliases (clear_decl_external, - NULL, true); + NULL, true); } /* If we're going to need to write this function out, and Jakub