The following fixes PR57140 - we did not properly consider loops marked for removal when copying them during inlining. The following patch simply keeps them that way and makes sure to schedule a fixup.
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2013-05-02 Richard Biener <rguent...@suse.de> PR middle-end/57140 * tree-inline.c (copy_loops): Properly handle removed loops. (copy_cfg_body): Mark destination loops for fixup if source loops needed fixup. * g++.dg/torture/pr57140.C: New testcase. Index: gcc/tree-inline.c =================================================================== *** gcc/tree-inline.c (revision 198441) --- gcc/tree-inline.c (working copy) *************** copy_loops (bitmap blocks_to_copy, *** 2211,2218 **** /* Assign the new loop its header and latch and associate those with the new loop. */ ! dest_loop->header = (basic_block)src_loop->header->aux; ! dest_loop->header->loop_father = dest_loop; if (src_loop->latch != NULL) { dest_loop->latch = (basic_block)src_loop->latch->aux; --- 2211,2221 ---- /* Assign the new loop its header and latch and associate those with the new loop. */ ! if (src_loop->header != NULL) ! { ! dest_loop->header = (basic_block)src_loop->header->aux; ! dest_loop->header->loop_father = dest_loop; ! } if (src_loop->latch != NULL) { dest_loop->latch = (basic_block)src_loop->latch->aux; *************** copy_cfg_body (copy_body_data * id, gcov *** 2341,2346 **** --- 2344,2354 ---- loops_state_set (LOOPS_NEED_FIXUP); } + /* If the loop tree in the source function needed fixup, mark the + destination loop tree for fixup, too. */ + if (loops_for_fn (src_cfun)->state & LOOPS_NEED_FIXUP) + loops_state_set (LOOPS_NEED_FIXUP); + if (gimple_in_ssa_p (cfun)) FOR_ALL_BB_FN (bb, cfun_to_copy) if (!blocks_to_copy Index: gcc/testsuite/g++.dg/torture/pr57140.C =================================================================== --- gcc/testsuite/g++.dg/torture/pr57140.C (revision 0) +++ gcc/testsuite/g++.dg/torture/pr57140.C (working copy) @@ -0,0 +1,186 @@ +// { dg-do compile } + +namespace std { + typedef long unsigned int size_t; + template<typename> class allocator; + template<class _CharT> struct char_traits; + template<typename _CharT, typename _Traits = char_traits<_CharT>, typename _Alloc = allocator<_CharT> > class basic_string; + typedef basic_string<char> string; +} +namespace std __attribute__ ((__visibility__ ("default"))) { +} +namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) { +} +namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) { + template<typename _Tp> class new_allocator { + }; +} +namespace std __attribute__ ((__visibility__ ("default"))) { + template<typename _Tp> class allocator: public __gnu_cxx::new_allocator<_Tp> { + public: + template<typename _Tp1> struct rebind { + typedef allocator<_Tp1> other; + }; + }; +} +namespace std { +} +namespace __gnu_cxx __attribute__ ((__visibility__ ("default"))) { +} +namespace std __attribute__ ((__visibility__ ("default"))) { + template<typename _CharT, typename _Traits, typename _Alloc> class basic_string { + struct _Alloc_hider : _Alloc { + _Alloc_hider(_CharT* __dat, const _Alloc& __a) : _Alloc(__a), _M_p(__dat) { + } + _CharT* _M_p; + }; + mutable _Alloc_hider _M_dataplus; + public: + basic_string(const _CharT* __s, const _Alloc& __a = _Alloc()); + }; + template<typename _CharT, typename _Traits, typename _Alloc> inline bool operator==(const basic_string<_CharT, _Traits, _Alloc>& __lhs, const _CharT* __rhs) { + } +} +extern "C" { +} +namespace std __attribute__ ((__visibility__ ("default"))) { + namespace __detail { + struct _List_node_base { + _List_node_base* _M_next; + }; + } + template<typename _Tp> struct _List_node : public __detail::_List_node_base { + }; + template<typename _Tp> struct _List_iterator { + typedef _List_iterator<_Tp> _Self; + typedef _Tp& reference; + reference operator*() const { + } + bool operator!=(const _Self& __x) const { + } + }; + template<typename _Tp, typename _Alloc> class _List_base { + protected: + typedef typename _Alloc::template rebind<_List_node<_Tp> >::other _Node_alloc_type; + struct _List_impl : public _Node_alloc_type { + __detail::_List_node_base _M_node; + _List_impl() : _Node_alloc_type(), _M_node() { + } + _List_impl(const _Node_alloc_type& __a) : _Node_alloc_type(__a), _M_node() { + } + }; + _List_impl _M_impl; + ~_List_base() { + } + void _M_clear(); + }; + template<typename _Tp, typename _Alloc = std::allocator<_Tp> > class list : protected _List_base<_Tp, _Alloc> { + typedef _List_iterator<_Tp> iterator; + typedef size_t size_type; + public: + iterator begin() { + } + iterator end() { + } + bool empty() const { + } + size_type size() const { + } + void swap(list& __x) { + } + template<typename _StrictWeakOrdering> void merge(list& __x, _StrictWeakOrdering __comp); + template<typename _StrictWeakOrdering> void sort(_StrictWeakOrdering); + }; + template<typename _Tp, typename _Alloc> template <typename _StrictWeakOrdering> void list<_Tp, _Alloc>:: merge(list& __x, _StrictWeakOrdering __comp) { + if (this != &__x) { + iterator __first1 = begin(); + iterator __last1 = end(); + iterator __first2 = __x.begin(); + iterator __last2 = __x.end(); + while (__first1 != __last1 && __first2 != __last2) if (__comp(*__first2, *__first1)) { + iterator __next = __first2; + __first2 = __next; + } + } + } + template<typename _Tp, typename _Alloc> template <typename _StrictWeakOrdering> void list<_Tp, _Alloc>:: sort(_StrictWeakOrdering __comp) { + if (this->_M_impl._M_node._M_next != &this->_M_impl._M_node && this->_M_impl._M_node._M_next->_M_next != &this->_M_impl._M_node) { + list __carry; + list __tmp[64]; + list * __fill = &__tmp[0]; + list * __counter; + do { + for(__counter = &__tmp[0]; + __counter != __fill && !__counter->empty(); + ++__counter) { __counter->merge(__carry, __comp); __carry.swap(*__counter); } + } + while ( !empty() ); + for (__counter = &__tmp[1]; + __counter != __fill; + ++__counter) __counter->merge(*(__counter - 1), __comp); + } + } +} +namespace gloox { + class Tag { + }; + class StanzaExtension { + }; +} +namespace gloox { +} +using namespace gloox; +class AbstractPurpleRequest { +}; +class AdhocCommandHandler : public AbstractPurpleRequest { +}; +class AdhocTag : public Tag { +}; +class AbstractConfigInterfaceHandler { +}; +namespace gloox { + class DataFormField { + public: + const std::string& value() const { + } + }; + class DataFormFieldContainer { + public: + bool hasField( const std::string& field ) const { + } + DataFormField* field( const std::string& field ) const; + }; + class DataForm : public StanzaExtension, public DataFormFieldContainer { + }; +} +enum { + SORT_BY_JID, SORT_BY_UIN, SORT_BY_BUDDIES, }; +struct SortData { +}; +struct ListData { + std::list<SortData> output; + int sort_by; +}; +class AdhocAdmin : public AdhocCommandHandler, public AbstractConfigInterfaceHandler { + AdhocTag *handleAdhocTag(Tag *stanzaTag); + AdhocTag *handleUnregisterUserForm(Tag *tag, const DataForm &form); + AdhocTag *handleListUsersForm(Tag *tag, const DataForm &form); + ListData m_listUsersData; +}; +namespace gloox { +} +static bool compareIDataASC(SortData &a, SortData &b) { +} +AdhocTag *AdhocAdmin::handleListUsersForm(Tag *tag, const DataForm &form) { + ListData &data = m_listUsersData; + if (data.output.size() == 0) { + if (!form.hasField("users_vip") || !form.hasField("show_jid") || !form.hasField("show_uin") || !form.hasField("show_buddies") || !form.hasField("show_sort_by") || !form.hasField("show_sort_order") || !form.hasField("show_max_per_page") ) { + } + bool sort_asc = form.field("show_sort_order")->value() == "asc"; + if (data.sort_by == SORT_BY_BUDDIES) { + if (sort_asc) data.output.sort(compareIDataASC); + } + else { + } + } +}