2019-08-30 Jakub Jelinek Backported from mainline 2019-02-13 Jakub Jelinek PR middle-end/89303 * tree-ssa-structalias.c (set_uids_in_ptset): Or in vi->is_heap_var into pt->vars_contains_escaped_heap instead of setting pt->vars_contains_escaped_heap to it. 2019-02-13 Jonathan Wakely Jakub Jelinek PR middle-end/89303 * g++.dg/torture/pr89303.C: New test. --- gcc/tree-ssa-structalias.c (revision 268865) +++ gcc/tree-ssa-structalias.c (revision 268866) @@ -6385,7 +6385,7 @@ set_uids_in_ptset (bitmap into, bitmap f && bitmap_bit_p (escaped_vi->solution, i))) { pt->vars_contains_escaped = true; - pt->vars_contains_escaped_heap = vi->is_heap_var; + pt->vars_contains_escaped_heap |= vi->is_heap_var; } if (vi->is_restrict_var) --- gcc/testsuite/g++.dg/torture/pr89303.C (nonexistent) +++ gcc/testsuite/g++.dg/torture/pr89303.C (revision 268866) @@ -0,0 +1,792 @@ +// PR middle-end/89303 +// { dg-do run } +// { dg-additional-options "-std=c++14" } + +namespace std +{ + typedef __SIZE_TYPE__ size_t; + typedef decltype(nullptr) nullptr_t; + + template + struct integral_constant + { + static constexpr _Tp value = __v; + typedef _Tp value_type; + typedef integral_constant<_Tp, __v> type; + constexpr operator value_type() const noexcept { return value; } + constexpr value_type operator()() const noexcept { return value; } + }; + + template + constexpr _Tp integral_constant<_Tp, __v>::value; + + typedef integral_constant true_type; + typedef integral_constant false_type; + + template + using __bool_constant = integral_constant; + + template + struct conditional; + + template + struct __and_; + + template<> + struct __and_<> + : public true_type + { }; + + template + struct __and_<_B1> + : public _B1 + { }; + + template + struct __and_<_B1, _B2> + : public conditional<_B1::value, _B2, _B1>::type + { }; + + template + struct __and_<_B1, _B2, _B3, _Bn...> + : public conditional<_B1::value, __and_<_B2, _B3, _Bn...>, _B1>::type + { }; + + template + struct remove_cv; + + template + struct __is_void_helper + : public false_type { }; + + template<> + struct __is_void_helper + : public true_type { }; + + template + struct is_void + : public __is_void_helper::type>::type + { }; + + template + _Up + __declval(int); + + template + _Tp + __declval(long); + + template + auto declval() noexcept -> decltype(__declval<_Tp>(0)); + + template + struct is_same + : public false_type { }; + + template + struct is_same<_Tp, _Tp> + : public true_type { }; + + template + struct remove_const + { typedef _Tp type; }; + + template + struct remove_const<_Tp const> + { typedef _Tp type; }; + + template + struct remove_volatile + { typedef _Tp type; }; + + template + struct remove_volatile<_Tp volatile> + { typedef _Tp type; }; + + template + struct remove_cv + { + typedef typename + remove_const::type>::type type; + }; + + template + struct remove_reference + { typedef _Tp type; }; + + template + struct remove_reference<_Tp&> + { typedef _Tp type; }; + + template + struct remove_reference<_Tp&&> + { typedef _Tp type; }; + + template + struct enable_if + { }; + + template + struct enable_if + { typedef _Tp type; }; + + template + using _Require = typename enable_if<__and_<_Cond...>::value>::type; + + template + struct conditional + { typedef _Iftrue type; }; + + template + struct conditional + { typedef _Iffalse type; }; + + template + struct __declval_protector + { + static const bool __stop = false; + }; + + template + auto declval() noexcept -> decltype(__declval<_Tp>(0)) + { + static_assert(__declval_protector<_Tp>::__stop, + "declval() must not be used!"); + return __declval<_Tp>(0); + } + + namespace void_details { + template + struct make_void { using type = void; }; +} + +template using __void_t = typename void_details ::make_void::type; + + template + inline constexpr _Tp* + __addressof(_Tp& __r) noexcept + { + return reinterpret_cast<_Tp*> + (&const_cast(reinterpret_cast(__r))); + } + + template + constexpr _Tp&& + forward(typename std::remove_reference<_Tp>::type& __t) noexcept + { return static_cast<_Tp&&>(__t); } + + template + constexpr _Tp&& + forward(typename std::remove_reference<_Tp>::type&& __t) noexcept + { + return static_cast<_Tp&&>(__t); + } + + template + constexpr typename std::remove_reference<_Tp>::type&& + move(_Tp&& __t) noexcept + { return static_cast::type&&>(__t); } +} + +inline void* operator new(std::size_t, void* p) { return p; } + +extern "C" void* malloc(std::size_t); +extern "C" void free(void*); + +namespace std +{ + template + class allocator + { + public: + using value_type = T; + + allocator() { } + + template + allocator(const allocator&) { } + + T* allocate(size_t n) { return (T*)malloc(n*sizeof(T)); } + void deallocate(T* p, size_t) { free(p); } + + template + void construct(U* p, Args&&... args) + { ::new((void*)p) U(args...); } + + template + void destroy(U* p) + { p->~U(); } + }; + + class __undefined; + + template + struct __replace_first_arg + { }; + + template class _Template, typename _Up, + typename _Tp, typename... _Types> + struct __replace_first_arg<_Template<_Tp, _Types...>, _Up> + { using type = _Template<_Up, _Types...>; }; + + struct __allocator_traits_base + { + template + struct __rebind : __replace_first_arg<_Tp, _Up> { }; + + template + struct __rebind<_Tp, _Up, + __void_t::other>> + { using type = typename _Tp::template rebind<_Up>::other; }; + }; + + template + using __alloc_rebind + = typename __allocator_traits_base::template __rebind<_Alloc, _Up>::type; + + template + struct allocator_traits; + + template + struct allocator_traits> + { + using allocator_type = allocator<_Tp>; + using value_type = _Tp; + using pointer = _Tp*; + using const_pointer = const _Tp*; + using size_type = std::size_t; + + static pointer + allocate(allocator_type& __a, size_type __n) + { return __a.allocate(__n); } + + static void + deallocate(allocator_type& __a, pointer __p, size_type __n) + { __a.deallocate(__p, __n); } + + template + static void + construct(allocator_type& __a, _Up* __p, _Args&&... __args) + { __a.construct(__p, std::forward<_Args>(__args)...); } + + template + static void + destroy(allocator_type& __a, _Up* __p) + { __a.destroy(__p); } + }; + + template + struct __allocated_ptr + { + using pointer = typename allocator_traits<_Alloc>::pointer; + using value_type = typename allocator_traits<_Alloc>::value_type; + + __allocated_ptr(_Alloc& __a, pointer __ptr) noexcept + : _M_alloc(std::__addressof(__a)), _M_ptr(__ptr) + { } + + template>> + __allocated_ptr(_Alloc& __a, _Ptr __ptr) + : _M_alloc(std::__addressof(__a)), + _M_ptr(__ptr) + { } + + __allocated_ptr(__allocated_ptr&& __gd) noexcept + : _M_alloc(__gd._M_alloc), _M_ptr(__gd._M_ptr) + { __gd._M_ptr = nullptr; } + + ~__allocated_ptr() + { + if (_M_ptr != nullptr) + std::allocator_traits<_Alloc>::deallocate(*_M_alloc, _M_ptr, 1); + } + + __allocated_ptr& + operator=(std::nullptr_t) noexcept + { + _M_ptr = nullptr; + return *this; + } + + value_type* get() { return _M_ptr; } + + private: + _Alloc* _M_alloc; + pointer _M_ptr; + }; + + template + __allocated_ptr<_Alloc> + __allocate_guarded(_Alloc& __a) + { + return { __a, std::allocator_traits<_Alloc>::allocate(__a, 1) }; + } + + template + struct __aligned_buffer + { + alignas(__alignof__(_Tp)) unsigned char _M_storage[sizeof(_Tp)]; + __aligned_buffer() = default; + + void* + _M_addr() noexcept + { + return static_cast(&_M_storage); + } + + const void* + _M_addr() const noexcept + { + return static_cast(&_M_storage); + } + + _Tp* + _M_ptr() noexcept + { return static_cast<_Tp*>(_M_addr()); } + + const _Tp* + _M_ptr() const noexcept + { return static_cast(_M_addr()); } + }; + + class bad_weak_ptr { }; + + inline void + __throw_bad_weak_ptr() + { (throw (bad_weak_ptr())); } + + class _Sp_counted_base + { + public: + _Sp_counted_base() noexcept + : _M_use_count(1), _M_weak_count(1) { } + + virtual + ~_Sp_counted_base() noexcept + { } + + virtual void + _M_dispose() noexcept = 0; + + virtual void + _M_destroy() noexcept + { delete this; } + + void + _M_add_ref_copy() + { ++_M_use_count; } + + void + _M_add_ref_lock() + { + if (_M_use_count == 0) + __throw_bad_weak_ptr(); + ++_M_use_count; + } + + void + _M_release() noexcept + { + if (--_M_use_count == 0) + { + _M_dispose(); + if (--_M_weak_count == 0) + _M_destroy(); + } + } + + void + _M_weak_add_ref() noexcept + { ++_M_weak_count; } + + void + _M_weak_release() noexcept + { + if (--_M_weak_count == 0) + _M_destroy(); + } + + long + _M_get_use_count() const noexcept + { + return _M_use_count; + } + + private: + _Sp_counted_base(_Sp_counted_base const&) = delete; + _Sp_counted_base& operator=(_Sp_counted_base const&) = delete; + + int _M_use_count; + int _M_weak_count; + }; + + template + class shared_ptr; + + template + class weak_ptr; + + template + class enable_shared_from_this; + + class __weak_count; + + class __shared_count; + + template + struct _Sp_alloc_shared_tag + { + const _Alloc& _M_a; + }; + + template + class _Sp_counted_ptr_inplace final : public _Sp_counted_base + { + class _Impl : _Alloc + { + public: + explicit _Impl(_Alloc __a) noexcept : _Alloc(__a) { } + + _Alloc& _M_alloc() noexcept { return *this; } + + __aligned_buffer<_Tp> _M_storage; + }; + + public: + using __allocator_type = __alloc_rebind<_Alloc, _Sp_counted_ptr_inplace>; + + template + _Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args) + : _M_impl(__a) + { + allocator_traits<_Alloc>::construct(__a, _M_ptr(), + std::forward<_Args>(__args)...); + } + + ~_Sp_counted_ptr_inplace() noexcept { } + + virtual void + _M_dispose() noexcept + { + allocator_traits<_Alloc>::destroy(_M_impl._M_alloc(), _M_ptr()); + } + + virtual void + _M_destroy() noexcept + { + __allocator_type __a(_M_impl._M_alloc()); + __allocated_ptr<__allocator_type> __guard_ptr{ __a, this }; + this->~_Sp_counted_ptr_inplace(); + } + + private: + friend class __shared_count; + + _Tp* _M_ptr() noexcept { return _M_impl._M_storage._M_ptr(); } + + _Impl _M_impl; + }; + + class __shared_count + { + public: + constexpr __shared_count() noexcept : _M_pi(0) + { } + + template + __shared_count(_Tp*& __p, _Sp_alloc_shared_tag<_Alloc> __a, + _Args&&... __args) + { + typedef _Sp_counted_ptr_inplace<_Tp, _Alloc> _Sp_cp_type; + typename _Sp_cp_type::__allocator_type __a2(__a._M_a); + auto __guard = std::__allocate_guarded(__a2); + _Sp_cp_type* __mem = __guard.get(); + auto __pi = ::new (__mem) + _Sp_cp_type(__a._M_a, std::forward<_Args>(__args)...); + __guard = nullptr; + _M_pi = __pi; + __p = __pi->_M_ptr(); + } + + ~__shared_count() noexcept + { + if (_M_pi != nullptr) + _M_pi->_M_release(); + } + + __shared_count(const __shared_count& __r) noexcept + : _M_pi(__r._M_pi) + { + if (_M_pi != 0) + _M_pi->_M_add_ref_copy(); + } + + explicit __shared_count(const __weak_count& __r); + + long + _M_get_use_count() const noexcept + { return _M_pi != 0 ? _M_pi->_M_get_use_count() : 0; } + + private: + friend class __weak_count; + + _Sp_counted_base* _M_pi; + }; + + class __weak_count + { + public: + constexpr __weak_count() noexcept : _M_pi(nullptr) + { } + + __weak_count(const __shared_count& __r) noexcept + : _M_pi(__r._M_pi) + { + if (_M_pi != nullptr) + _M_pi->_M_weak_add_ref(); + } + + __weak_count(const __weak_count& __r) noexcept + : _M_pi(__r._M_pi) + { + if (_M_pi != nullptr) + _M_pi->_M_weak_add_ref(); + } + + __weak_count(__weak_count&& __r) noexcept + : _M_pi(__r._M_pi) + { __r._M_pi = nullptr; } + + ~__weak_count() noexcept + { + if (_M_pi != nullptr) + { + _M_pi->_M_weak_release(); + } + } + + __weak_count& + operator=(const __shared_count& __r) noexcept + { + _Sp_counted_base* __tmp = __r._M_pi; + if (__tmp != nullptr) + __tmp->_M_weak_add_ref(); + if (_M_pi != nullptr) + _M_pi->_M_weak_release(); + _M_pi = __tmp; + return *this; + } + + long + _M_get_use_count() const noexcept + { return _M_pi != nullptr ? _M_pi->_M_get_use_count() : 0; } + + private: + friend class __shared_count; + + _Sp_counted_base* _M_pi; + }; + + inline + __shared_count::__shared_count(const __weak_count& __r) + : _M_pi(__r._M_pi) + { + if (_M_pi != nullptr) + _M_pi->_M_add_ref_lock(); + else + __throw_bad_weak_ptr(); + } + + template + class shared_ptr + { + public: + using element_type = _Tp; + + constexpr shared_ptr() noexcept + : _M_ptr(0), _M_refcount() + { } + + shared_ptr(const shared_ptr&) noexcept = default; + shared_ptr& operator=(const shared_ptr&) noexcept = default; + ~shared_ptr() = default; + + template + explicit shared_ptr(const weak_ptr<_Yp>& __r) + : _M_refcount(__r._M_refcount) // may throw + { + // It is now safe to copy __r._M_ptr, as + // _M_refcount(__r._M_refcount) did not throw. + _M_ptr = __r._M_ptr; + } + + long + use_count() const noexcept + { return _M_refcount._M_get_use_count(); } + + element_type* operator->() const noexcept { return _M_ptr; } + + protected: + + template + shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args) + : _M_ptr(), _M_refcount(_M_ptr, __tag, std::forward<_Args>(__args)...) + { _M_enable_shared_from_this_with(_M_ptr); } + + template + friend shared_ptr<_Tp1> + allocate_shared(const _Alloc& __a, _Args&&... __args); + + friend class weak_ptr<_Tp>; + + private: + + template + using __esft_base_t = decltype(__enable_shared_from_this_base( + std::declval(), + std::declval<_Yp*>())); + + template + struct __has_esft_base + : false_type { }; + + template + struct __has_esft_base<_Yp, __void_t<__esft_base_t<_Yp>>> + : true_type { }; + + template::type> + typename enable_if<__has_esft_base<_Yp2>::value>::type + _M_enable_shared_from_this_with(_Yp* __p) noexcept + { + if (auto __base = __enable_shared_from_this_base(_M_refcount, __p)) + __base->_M_weak_assign(const_cast<_Yp2*>(__p), _M_refcount); + } + + template friend class shared_ptr; + template friend class weak_ptr; + + element_type* _M_ptr; + __shared_count _M_refcount; + }; + + template + class weak_ptr + { + public: + using element_type = _Tp; + + constexpr weak_ptr() noexcept + : _M_ptr(nullptr), _M_refcount() + { } + + weak_ptr(const weak_ptr&) noexcept = default; + + ~weak_ptr() = default; + + weak_ptr& + operator=(const weak_ptr& __r) noexcept = default; + + long + use_count() const noexcept + { return _M_refcount._M_get_use_count(); } + + private: + + void + _M_assign(_Tp* __ptr, const __shared_count& __refcount) noexcept + { + if (use_count() == 0) + { + _M_ptr = __ptr; + _M_refcount = __refcount; + } + } + + template friend class shared_ptr; + template friend class weak_ptr; + friend class enable_shared_from_this<_Tp>; + + element_type* _M_ptr; + __weak_count _M_refcount; + }; + + template + class enable_shared_from_this + { + protected: + constexpr enable_shared_from_this() noexcept { } + + enable_shared_from_this(const enable_shared_from_this&) noexcept { } + + enable_shared_from_this& + operator=(const enable_shared_from_this&) noexcept + { return *this; } + + ~enable_shared_from_this() { } + + public: + shared_ptr<_Tp> + shared_from_this() + { return shared_ptr<_Tp>(this->_M_weak_this); } + + shared_ptr + shared_from_this() const + { return shared_ptr(this->_M_weak_this); } + + private: + template + void + _M_weak_assign(_Tp1* __p, const __shared_count& __n) const noexcept + { _M_weak_this._M_assign(__p, __n); } + + friend const enable_shared_from_this* + __enable_shared_from_this_base(const __shared_count&, + const enable_shared_from_this* __p) + { return __p; } + + template + friend class shared_ptr; + + mutable weak_ptr<_Tp> _M_weak_this; + }; + + template + inline shared_ptr<_Tp> + allocate_shared(const _Alloc& __a, _Args&&... __args) + { + return shared_ptr<_Tp>(_Sp_alloc_shared_tag<_Alloc>{__a}, + std::forward<_Args>(__args)...); + } + + template + inline shared_ptr<_Tp> + make_shared(_Args&&... __args) + { + typedef typename std::remove_const<_Tp>::type _Tp_nc; + return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(), + std::forward<_Args>(__args)...); + } +} + +class blob final: public std::enable_shared_from_this +{ + int* data; + +public: + blob() { data = new int; } + ~blob() { delete data; } +}; + +static int +bar(std::shared_ptr) +{ + return 0; +} + +int main() +{ + std::shared_ptr tg = std::make_shared(); + return tg->shared_from_this().use_count() - 2; +}