From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 98420 invoked by alias); 17 Apr 2015 09:05:26 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 98409 invoked by uid 89); 17 Apr 2015 09:05:25 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.5 required=5.0 tests=AWL,BAYES_00,KAM_ASCII_DIVIDERS,KAM_LAZY_DOMAIN_SECURITY,KAM_STOCKGEN,T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mx2.suse.de Received: from cantor2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (CAMELLIA256-SHA encrypted) ESMTPS; Fri, 17 Apr 2015 09:05:22 +0000 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 10A28ABD1; Fri, 17 Apr 2015 09:05:19 +0000 (UTC) Date: Fri, 17 Apr 2015 09:05:00 -0000 From: Richard Biener To: gcc-patches@gcc.gnu.org cc: jason@redhat.com Subject: [PATCH] Fix PR65549, avoid force_decl_die in late compilation Message-ID: User-Agent: Alpine 2.11 (LSU 23 2013-08-11) MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-SW-Source: 2015-04/txt/msg00858.txt.bz2 For PR65549 the issue is that the force_decl_die DW_TAG_GNU_call_site resolve_addr does can end up creating DIEs for types we won't emit (it re-populates the limbo DIE list for the testcase). For the particular testcase this happens because the context of the function called (a lambda type) wasn't needed (it's created/used in another LTRANS unit). The DW_TAG_GNU_call_site support doesn't actually need a full DIE tree for the callee decl (which is external in the case in question): static void resolve_addr (dw_die_ref die) { ... FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a) switch (AT_class (a)) { ... case dw_val_class_addr: ... if (die->die_tag == DW_TAG_GNU_call_site && a->dw_attr == DW_AT_abstract_origin) { tree tdecl = SYMBOL_REF_DECL (a->dw_attr_val.v.val_addr); dw_die_ref tdie = lookup_decl_die (tdecl); if (tdie == NULL && DECL_EXTERNAL (tdecl) && DECL_ABSTRACT_ORIGIN (tdecl) == NULL_TREE) { force_decl_die (tdecl); tdie = lookup_decl_die (tdecl); instead it is enough to create a DIE with enough information for the debugger to associate it with the callee - namely a declaration with just a name. This is what the patch does. Bootstrap and regtest in progress on x86_64-unknown-linux-gnu (I'm also double-checking LTO bootstrap). I've manually verified gdb is still happy with the DW_TAG_GNU_call_site info (not sure if we have a guality test for the feature). Ok for trunk and affected branches? (I've also run into this when doing the LTO early debug work this week which is where the fix originates). Thanks, Richard. 2015-04-17 Richard Biener PR debug/65549 * dwarf2out.c (resolve_addr): Avoid forcing a full DIE for the target of a DW_TAG_GNU_call_site during late compilation. Instead create a stub DIE without a type. * g++.dg/lto/pr65549_0.C: New testcase. Index: gcc/dwarf2out.c =================================================================== *** gcc/dwarf2out.c (revision 222165) --- gcc/dwarf2out.c (working copy) *************** resolve_addr (dw_die_ref die) *** 23950,23957 **** && DECL_EXTERNAL (tdecl) && DECL_ABSTRACT_ORIGIN (tdecl) == NULL_TREE) { ! force_decl_die (tdecl); ! tdie = lookup_decl_die (tdecl); } if (tdie) { --- 23950,23966 ---- && DECL_EXTERNAL (tdecl) && DECL_ABSTRACT_ORIGIN (tdecl) == NULL_TREE) { ! /* Creating a full DIE for tdecl is overly expensive and ! at this point even wrong when in the LTO phase ! as it can end up generating new type DIEs we didn't ! output and thus optimize_external_refs will crash. */ ! tdie = new_die (DW_TAG_subprogram, comp_unit_die (), NULL_TREE); ! add_AT_flag (tdie, DW_AT_external, 1); ! add_AT_flag (tdie, DW_AT_declaration, 1); ! /* GDB is happy with either of the following but add both. */ ! add_linkage_attr (tdie, tdecl); ! add_name_and_src_coords_attributes (tdie, tdecl); ! equate_decl_number_to_die (tdecl, tdie); } if (tdie) { Index: gcc/testsuite/g++.dg/lto/pr65549_0.C =================================================================== *** gcc/testsuite/g++.dg/lto/pr65549_0.C (revision 0) --- gcc/testsuite/g++.dg/lto/pr65549_0.C (working copy) *************** *** 0 **** --- 1,144 ---- + // { dg-lto-do link } + // { dg-lto-options { { -std=gnu++14 -flto -g } { -std=gnu++14 -flto -g -O2 -fno-inline -flto-partition=max } } } + // { dg-extra-ld-options "-r -nostdlib" } + + namespace std { + inline namespace __cxx11 {} + template struct integral_constant { + static constexpr _Tp value = 0; + }; + template struct __and_; + struct is_member_object_pointer : integral_constant {}; + template + struct is_member_function_pointer : integral_constant {}; + template struct remove_reference { typedef int type; }; + template class C; + template struct __result_of_impl; + template + struct __result_of_impl { + typedef decltype(0) type; + }; + template + struct C<_Functor(_ArgTypes...)> + : __result_of_impl::type>::value, + _Functor> {}; + template using result_of_t = typename C<_Tp>::type; + template void forward(); + template _Tp move(_Tp) {} + namespace __cxx11 { + class basic_string typedef string; + } + template struct allocator_traits { typedef decltype(0) pointer; }; + } + struct F : std::allocator_traits {}; + namespace std { + namespace __cxx11 { + class basic_string { + public: + struct _Alloc_hider : F { + _Alloc_hider(pointer); + } _M_dataplus; + basic_string(int) : _M_dataplus(0) {} + ~basic_string(); + }; + } + template class function; + template class _Base_manager { + protected: + static _Functor *_M_get_pointer(int) {} + }; + template class _Function_handler; + template + class _Function_handler<_Res(_ArgTypes...), _Functor> + : _Base_manager<_Functor> { + public: + static _Res _M_invoke(const int &) { + (*_Base_manager<_Functor>::_M_get_pointer(0))(); + } + }; + template using __check_func_return_type = int; + template + class function<_Res(_ArgTypes...)> { + template using _Invoke = decltype(0); + template + using _Callable = __and_<__check_func_return_type<_Invoke<_Functor>, _Res>>; + template using _Requires = int; + + public: + template , void>> + function(_Functor); + using _Invoker_type = _Res (*)(const int &); + _Invoker_type _M_invoker; + }; + template + template + function<_Res(_ArgTypes...)>::function(_Functor) { + _M_invoker = _Function_handler<_Res(), _Functor>::_M_invoke; + } + class unique_ptr { + public: + ~unique_ptr(); + }; + template _Tp make_unique(_Args... __args) { + _Tp(__args...); + } + } + class A { + public: + template T as(); + }; + class variables_map { + public: + A operator[](std::basic_string); + }; + class B { + public: + variables_map configuration(); + void run(int, int, std::function); + }; + class H; + struct G { + enum {} _state; + }; + class D { + G _local_state; + std::unique_ptr _task; + template void schedule(Func func) { + struct task_with_state { + task_with_state(Func func) : _func(func) {} + Func _func; + } tws = std::make_unique(std::move(func)); + } + friend H; + }; + template using futurize_t = H; + class H { + D *_promise; + template void schedule(Func func) { + G __trans_tmp_1; + struct task_with_ready_state { + task_with_ready_state(Func, G); + }; + std::make_unique(std::move(func), __trans_tmp_1); + _promise->schedule(std::move(func)); + } + template void then(Func func, Param) { + using P = D; + P pr; + schedule([ pr = std::move(pr), func, param = std::forward ]{}); + } + + public: + template futurize_t> then(Func) { + then(0, [] {}); + } + } clients; + main() { + B app; + app.run(0, 0, [&] { + auto config = app.configuration()[0].as(); + clients.then([] {}); + }); + }