From: Pedro Alves Date: Tue, 25 Apr 2017 00:27:42 +0000 (+0100) Subject: Don't memcpy non-trivially-copyable types: Make enum_flags triv. copyable X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=23bcc18f470ee4364bd362a8b78c6c1415a9dadb;p=binutils-gdb.git Don't memcpy non-trivially-copyable types: Make enum_flags triv. copyable 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, by simply removing the user-provided copy constructor and assignment operator. The compiler-generated versions work just fine. 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: 2017-04-25 Pedro Alves * common/enum-flags.h (enum_flags): Don't implement copy ctor and assignment operator. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 33dd53bb396..f5419dbc8f2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +2017-04-25 Pedro Alves + + * common/enum-flags.h (enum_flags): Don't implement copy ctor and + assignment operator. + 2017-04-24 Yao Qi * doublest.c (convert_doublest_to_floatformat): Call diff --git a/gdb/common/enum-flags.h b/gdb/common/enum-flags.h index e63c8a46bd8..ddfcddfb8b0 100644 --- a/gdb/common/enum-flags.h +++ b/gdb/common/enum-flags.h @@ -120,16 +120,6 @@ 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; - } - /* If you get an error saying these two overloads are ambiguous, then you tried to mix values of different enum types. */ enum_flags (enum_type e)