On Wed, 10 Jun 2015, Pierre-Marie de Rodat wrote: > On 06/10/2015 03:36 PM, Richard Biener wrote: > > Hmm, yes. It meant to break after the first ;) (without LTO > > there usually is only one TU decl, apart from Java I think). > > The hunk isn't in mainline because it was part of an experimental patch I > > did on the early-debug branch. > > Understood, thanks! > > > Yeah, that looks great! > > > > Of course I wonder about Java (builds multiple ones, one for each > > input file) and Go (no idea). I suppose Java would need to build > > another one where all the "defaults" go (or it doesn't have any > > such entities). > > Yeah, I'm not familiar with them neither... > > > In theory we could have changed dwarf2out_init to get a > > translation-unit-decl argument as well. But your patch looks like > > we don't have such at the point of dwarf2out_init in all frontends. > > > > Your patch is ok (and ok to backport) IMHO, though please give > > others the chance to chime in. > > Thank you very much. :-) I will soon become unavailable until July, so I think > I'll wait until then to commit anyway.
FYI, I decided to backport the fix causing this regression to the 4.8 branch today, guarded with in_lto_p, thus eliminating the effect on non-LTO links. The adjusted patch looks like the following and I'll also adjust the 4.9 branch accordingly, leaving the GCC 5 branch with the original fix. Richard. 2015-06-11 Richard Biener <rguent...@suse.de> Backport from mainline, guarded with in_lto_p 2015-06-02 Richard Biener <rguent...@suse.de> PR debug/65549 * dwarf2out.c (lookup_context_die): New function. (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 if we have a context DIE present. * g++.dg/lto/pr65549_0.C: New testcase. 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 <typename _Tp, _Tp> struct integral_constant { + static constexpr _Tp value = 0; + }; + template <typename> struct __and_; + struct is_member_object_pointer : integral_constant<bool, false> {}; + template <typename> + struct is_member_function_pointer : integral_constant<bool, false> {}; + template <typename> struct remove_reference { typedef int type; }; + template <typename> class C; + template <bool, int, typename...> struct __result_of_impl; + template <typename _Functor, typename... _ArgTypes> + struct __result_of_impl<false, 0, _Functor, _ArgTypes...> { + typedef decltype(0) type; + }; + template <typename _Functor, typename... _ArgTypes> + struct C<_Functor(_ArgTypes...)> + : __result_of_impl<is_member_object_pointer::value, + is_member_function_pointer< + typename remove_reference<_Functor>::type>::value, + _Functor> {}; + template <typename _Tp> using result_of_t = typename C<_Tp>::type; + template <typename> void forward(); + template <typename _Tp> _Tp move(_Tp) {} + namespace __cxx11 { + class basic_string typedef string; + } + template <typename> struct allocator_traits { typedef decltype(0) pointer; }; + } + struct F : std::allocator_traits<int> {}; + 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 <typename> class function; + template <typename _Functor> class _Base_manager { + protected: + static _Functor *_M_get_pointer(int) {} + }; + template <typename, typename> class _Function_handler; + template <typename _Res, typename _Functor, typename... _ArgTypes> + class _Function_handler<_Res(_ArgTypes...), _Functor> + : _Base_manager<_Functor> { + public: + static _Res _M_invoke(const int &) { + (*_Base_manager<_Functor>::_M_get_pointer(0))(); + } + }; + template <typename, typename> using __check_func_return_type = int; + template <typename _Res, typename... _ArgTypes> + class function<_Res(_ArgTypes...)> { + template <typename> using _Invoke = decltype(0); + template <typename _Functor> + using _Callable = __and_<__check_func_return_type<_Invoke<_Functor>, _Res>>; + template <typename, typename> using _Requires = int; + + public: + template <typename _Functor, typename = _Requires<_Callable<_Functor>, void>> + function(_Functor); + using _Invoker_type = _Res (*)(const int &); + _Invoker_type _M_invoker; + }; + template <typename _Res, typename... _ArgTypes> + template <typename _Functor, typename> + function<_Res(_ArgTypes...)>::function(_Functor) { + _M_invoker = _Function_handler<_Res(), _Functor>::_M_invoke; + } + class unique_ptr { + public: + ~unique_ptr(); + }; + template <typename _Tp, typename... _Args> _Tp make_unique(_Args... __args) { + _Tp(__args...); + } + } + class A { + public: + template <class T> T as(); + }; + class variables_map { + public: + A operator[](std::basic_string); + }; + class B { + public: + variables_map configuration(); + void run(int, int, std::function<void()>); + }; + class H; + struct G { + enum {} _state; + }; + class D { + G _local_state; + std::unique_ptr _task; + template <typename Func> void schedule(Func func) { + struct task_with_state { + task_with_state(Func func) : _func(func) {} + Func _func; + } tws = std::make_unique<task_with_state>(std::move(func)); + } + friend H; + }; + template <typename> using futurize_t = H; + class H { + D *_promise; + template <typename Func> void schedule(Func func) { + G __trans_tmp_1; + struct task_with_ready_state { + task_with_ready_state(Func, G); + }; + std::make_unique<task_with_ready_state>(std::move(func), __trans_tmp_1); + _promise->schedule(std::move(func)); + } + template <typename Func, typename Param> void then(Func func, Param) { + using P = D; + P pr; + schedule([ pr = std::move(pr), func, param = std::forward<Param> ]{}); + } + + public: + template <typename Func> futurize_t<std::result_of_t<Func()>> then(Func) { + then(0, [] {}); + } + } clients; + main() { + B app; + app.run(0, 0, [&] { + auto config = app.configuration()[0].as<std::string>(); + clients.then([] {}); + }); + } Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 224363) +++ gcc/dwarf2out.c (working copy) @@ -19697,6 +19697,28 @@ is_naming_typedef_decl (const_tree decl) != TYPE_NAME (TREE_TYPE (decl)))); } +/* Looks up the DIE for a context. */ + +static inline dw_die_ref +lookup_context_die (tree context) +{ + if (context) + { + /* Find die that represents this context. */ + if (TYPE_P (context)) + { + context = TYPE_MAIN_VARIANT (context); + dw_die_ref ctx = lookup_type_die (context); + if (!ctx) + return NULL; + return strip_naming_typedef (context, ctx); + } + else + return lookup_decl_die (context); + } + return comp_unit_die (); +} + /* Returns the DIE for a context. */ static inline dw_die_ref @@ -22751,8 +22773,25 @@ resolve_addr (dw_die_ref die) && DECL_EXTERNAL (tdecl) && DECL_ABSTRACT_ORIGIN (tdecl) == NULL_TREE) { - force_decl_die (tdecl); - tdie = lookup_decl_die (tdecl); + dw_die_ref cdie; + if (!in_lto_p) + { + force_decl_die (tdecl); + tdie = lookup_decl_die (tdecl); + } + else if ((cdie = lookup_context_die (DECL_CONTEXT (tdecl)))) + { + /* 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, cdie, NULL_TREE); + add_AT_flag (tdie, DW_AT_external, 1); + add_AT_flag (tdie, DW_AT_declaration, 1); + add_linkage_attr (tdie, tdecl); + add_name_and_src_coords_attributes (tdie, tdecl); + equate_decl_number_to_die (tdecl, tdie); + } } if (tdie) {