From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 106568 invoked by alias); 20 Apr 2017 03:34:33 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 106554 invoked by uid 89); 20 Apr 2017 03:34:32 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-23.9 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,SPF_HELO_PASS,SPF_SOFTFAIL autolearn=ham version=3.3.2 spammy=instances X-HELO: simark.ca Received: from simark.ca (HELO simark.ca) (158.69.221.121) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 20 Apr 2017 03:34:30 +0000 Received: by simark.ca (Postfix, from userid 33) id BC19E1E48D; Wed, 19 Apr 2017 23:34:30 -0400 (EDT) To: Pedro Alves Subject: Re: [PATCH 2/5] Don't memcpy non-trivially-copyable types: Make enum_flags triv. copyable X-PHP-Originating-Script: 33:rcube.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Date: Thu, 20 Apr 2017 03:34:00 -0000 From: Simon Marchi Cc: gdb-patches@sourceware.org In-Reply-To: <1492050475-9238-3-git-send-email-palves@redhat.com> References: <1492050475-9238-1-git-send-email-palves@redhat.com> <1492050475-9238-3-git-send-email-palves@redhat.com> Message-ID: X-Sender: simon.marchi@polymtl.ca User-Agent: Roundcube Webmail/1.2.4 X-IsSubscribed: yes X-SW-Source: 2017-04/txt/msg00577.txt.bz2 On 2017-04-12 22:27, Pedro Alves wrote: > The delete-memcpy-with-non-trivial-types patch exposed many instances > of this problem: > > src/gdb/btrace.h: In function ‘btrace_insn_s* > VEC_btrace_insn_s_quick_insert(VEC_btrace_insn_s*, unsigned int, const > btrace_insn_s*, const char*, unsigned int)’: > src/gdb/common/vec.h:948:62: error: use of deleted function ‘void* > memmove(T*, const U*, size_t) [with T = btrace_insn; U = btrace_insn; > = void; size_t = long unsigned int]’ > memmove (slot_ + 1, slot_, (vec_->num++ - ix_) * sizeof (T)); \ > ^ > src/gdb/common/vec.h:436:1: note: in expansion of macro > ‘DEF_VEC_FUNC_O’ > DEF_VEC_FUNC_O(T) \ > ^ > src/gdb/btrace.h:84:1: note: in expansion of macro ‘DEF_VEC_O’ > DEF_VEC_O (btrace_insn_s); > ^ > [...] > src/gdb/common/vec.h:1060:31: error: use of deleted function ‘void* > memcpy(T*, const U*, size_t) [with T = btrace_insn; U = btrace_insn; > = void; size_t = long unsigned int]’ > sizeof (T) * vec2_->num); \ > ^ > src/gdb/common/vec.h:437:1: note: in expansion of macro > ‘DEF_VEC_ALLOC_FUNC_O’ > DEF_VEC_ALLOC_FUNC_O(T) \ > ^ > src/gdb/btrace.h:84:1: note: in expansion of macro ‘DEF_VEC_O’ > DEF_VEC_O (btrace_insn_s); > ^ > > So, VECs (given it's C roots) rely on memcpy/memcpy of VEC elements to > be well defined, in order to grow/reallocate its internal elements > array. This means that we can only put trivially copyable types in > VECs. E.g., if a type requires using a custom copy/move ctor to > relocate, then we can't put it in a VEC (so we use std::vector > instead). But, as shown above, we're violating that requirement. > > btrace_insn is currently not trivially copyable, because it contains > an enum_flags field, and that is itself not trivially copyable. This > patch corrects that. > > Note that std::vector relies on std::is_trivially_copyable too to know > whether it can reallocate its elements with memcpy/memmove instead of > having to call copy/move ctors and dtors, so if we have types in > std::vectors that weren't trivially copyable because of enum_flags, > this will make such vectors more efficient. > > gdb/ChangeLog: > yyyy-mm-dd Pedro Alves > > * common/enum-flags.h (enum_flags): Define copy/move ctors/op= as > defaulted. > --- > gdb/common/enum-flags.h | 15 ++++++--------- > 1 file changed, 6 insertions(+), 9 deletions(-) > > diff --git a/gdb/common/enum-flags.h b/gdb/common/enum-flags.h > index e63c8a4..bea0ad5 100644 > --- a/gdb/common/enum-flags.h > +++ b/gdb/common/enum-flags.h > @@ -120,15 +120,12 @@ public: > : m_enum_value ((enum_type) 0) > {} > > - enum_flags (const enum_flags &other) > - : m_enum_value (other.m_enum_value) > - {} > - > - enum_flags &operator= (const enum_flags &other) > - { > - m_enum_value = other.m_enum_value; > - return *this; > - } > + /* Define copy/move ctor/op= as defaulted so that enum_flags is > + trivially copyable. */ > + enum_flags (const enum_flags &other) = default; > + enum_flags (enum_flags &&) noexcept = default; > + enum_flags &operator= (const enum_flags &other) = default; > + enum_flags &operator= (enum_flags &&) = default; What's the difference between defining these as default, and not defining them at all (which I assume will still make the compiler emit the default versions)? Do you want to add a static_assert(is_pod...) for that class? For now we have the VECs that will warn us if it becomes non-POD, but eventually they'll be gone. Simon