aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/version.h2
-rw-r--r--gdb/gnu-nat.c9
-rw-r--r--gdb/unittests/enum-flags-selftests.c27
-rw-r--r--gdbsupport/enum-flags.h103
-rw-r--r--include/diagnostics.h9
5 files changed, 75 insertions, 75 deletions
diff --git a/bfd/version.h b/bfd/version.h
index 1c1430a..e9af7d8 100644
--- a/bfd/version.h
+++ b/bfd/version.h
@@ -16,7 +16,7 @@
In releases, the date is not included in either version strings or
sonames. */
-#define BFD_VERSION_DATE 20241221
+#define BFD_VERSION_DATE 20241222
#define BFD_VERSION @bfd_version@
#define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@
#define REPORT_BUGS_TO @report_bugs_to@
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index a8a4da1..c6fe7a9 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -1016,15 +1016,16 @@ gnu_nat_target::inf_validate_procs (struct inf *inf)
{
/* Make things normally linear. */
mach_msg_type_number_t search_start = 0;
- /* Which thread in PROCS corresponds to each task thread, & the task. */
- struct proc *matched[num_threads + 1];
+
+ /* Which thread in PROCS corresponds to each task thread. */
+ std::vector<struct proc *> matched (num_threads);
+
/* The last thread in INF->threads, so we can add to the end. */
struct proc *last = 0;
+
/* The current thread we're considering. */
struct proc *thread = inf->threads;
- memset (matched, 0, sizeof (matched));
-
while (thread)
{
mach_msg_type_number_t left;
diff --git a/gdb/unittests/enum-flags-selftests.c b/gdb/unittests/enum-flags-selftests.c
index dddb1e2..f192da3 100644
--- a/gdb/unittests/enum-flags-selftests.c
+++ b/gdb/unittests/enum-flags-selftests.c
@@ -235,33 +235,6 @@ CHECK_VALID (true, UnsignedEnumFlag, ~UnsignedEnumFlag ())
CHECK_VALID (true, EnumFlag, true ? EnumFlag () : RawEnum ())
CHECK_VALID (true, EnumFlag, true ? RawEnum () : EnumFlag ())
-/* These are valid, but it's not a big deal since you won't be able to
- assign the resulting integer to an enum or an enum_flags without a
- cast.
-
- The latter two tests are disabled on older GCCs because they
- incorrectly fail with gcc 4.8 and 4.9 at least. Running the test
- outside a SFINAE context shows:
-
- invalid user-defined conversion from ‘EF’ to ‘RE2’
-
- They've been confirmed to compile/pass with gcc 5.3, gcc 7.1 and
- clang 3.7. */
-
-CHECK_VALID (true, int, true ? EnumFlag () : EnumFlag2 ())
-CHECK_VALID (true, int, true ? EnumFlag2 () : EnumFlag ())
-CHECK_VALID (true, int, true ? EnumFlag () : RawEnum2 ())
-CHECK_VALID (true, int, true ? RawEnum2 () : EnumFlag ())
-
-/* Same, but with an unsigned enum. */
-
-using uns = unsigned int;
-
-CHECK_VALID (true, uns, true ? EnumFlag () : UnsignedEnumFlag ())
-CHECK_VALID (true, uns, true ? UnsignedEnumFlag () : EnumFlag ())
-CHECK_VALID (true, uns, true ? EnumFlag () : UnsignedRawEnum ())
-CHECK_VALID (true, uns, true ? UnsignedRawEnum () : EnumFlag ())
-
/* Unfortunately this can't work due to the way C++ computes the
return type of the ternary conditional operator. int isn't
implicitly convertible to the raw enum type, so the type of the
diff --git a/gdbsupport/enum-flags.h b/gdbsupport/enum-flags.h
index d3291e9..71109bb 100644
--- a/gdbsupport/enum-flags.h
+++ b/gdbsupport/enum-flags.h
@@ -73,30 +73,6 @@
namespace. The compiler finds the corresponding
is_enum_flags_enum_type function via ADL. */
-/* Note that std::underlying_type<enum_type> is not what we want here,
- since that returns unsigned int even when the enum decays to signed
- int. */
-template<int size, bool sign> class integer_for_size { using type = void; };
-template<> struct integer_for_size<1, 0> { using type = uint8_t; };
-template<> struct integer_for_size<2, 0> { using type = uint16_t; };
-template<> struct integer_for_size<4, 0> { using type = uint32_t; };
-template<> struct integer_for_size<8, 0> { using type = uint64_t; };
-template<> struct integer_for_size<1, 1> { using type = int8_t; };
-template<> struct integer_for_size<2, 1> { using type = int16_t; };
-template<> struct integer_for_size<4, 1> { using type = int32_t; };
-template<> struct integer_for_size<8, 1> { using type = int64_t; };
-
-template<typename T>
-struct enum_underlying_type
-{
- DIAGNOSTIC_PUSH
- DIAGNOSTIC_IGNORE_ENUM_CONSTEXPR_CONVERSION
- using type
- = typename integer_for_size<sizeof (T),
- static_cast<bool>(T (-1) < T (0))>::type;
- DIAGNOSTIC_POP
-};
-
namespace enum_flags_detail
{
@@ -117,10 +93,61 @@ struct zero_type;
/* gdb::Requires trait helpers. */
template <typename enum_type>
using EnumIsUnsigned
- = std::is_unsigned<typename enum_underlying_type<enum_type>::type>;
+ = std::is_unsigned<typename std::underlying_type<enum_type>::type>;
+
+/* Helper to detect whether an enum has a fixed underlying type. This can be
+ achieved by using a scoped enum (in which case the type is "int") or
+ an explicit underlying type. C-style enums that are unscoped or do not
+ have an explicit underlying type have an implementation-defined underlying
+ type.
+
+ https://timsong-cpp.github.io/cppwp/n4659/dcl.enum#5
+
+ We need this trait in order to ensure that operator~ below does NOT
+ operate on old-style enums. This is because we apply operator~ on
+ the value and then cast the result to the enum_type. This is however
+ Undefined Behavior if the result does not fit in the range of possible
+ values for the enum. For enums with fixed underlying type, the entire
+ range of the integer is available. However, for old-style enums, the range
+ is only the smallest bit-field that can hold all the values of the
+ enumeration, typically much smaller than the underlying integer:
+
+ https://timsong-cpp.github.io/cppwp/n4659/expr.static.cast#10
+ https://timsong-cpp.github.io/cppwp/n4659/dcl.enum#8
+
+ To implement this, we leverage the fact that, since C++17, enums with
+ fixed underlying type can be list-initialized from an integer:
+ https://timsong-cpp.github.io/cppwp/n4659/dcl.init.list#3.7
+
+ Old-style enums cannot be initialized like that, leading to ill-formed
+ code.
+
+ We then use this together with SFINAE to create the desired trait.
+
+*/
+template <typename enum_type, typename = void>
+struct EnumHasFixedUnderlyingType : std::false_type
+{
+ static_assert(std::is_enum<enum_type>::value);
+};
+
+/* Specialization that is active only if enum_type can be
+ list-initialized from an integer (0). Only enums with fixed
+ underlying type satisfy this property in C++17. */
+template <typename enum_type>
+struct EnumHasFixedUnderlyingType<enum_type, std::void_t<decltype(enum_type{0})>> : std::true_type
+{
+ static_assert(std::is_enum<enum_type>::value);
+};
+
+template <typename enum_type>
+using EnumIsSafeForBitwiseComplement = std::conjunction<
+ EnumIsUnsigned<enum_type>,
+ EnumHasFixedUnderlyingType<enum_type>
+>;
+
template <typename enum_type>
-using EnumIsSigned
- = std::is_signed<typename enum_underlying_type<enum_type>::type>;
+using EnumIsUnsafeForBitwiseComplement = std::negation<EnumIsSafeForBitwiseComplement<enum_type>>;
}
@@ -129,7 +156,7 @@ class enum_flags
{
public:
using enum_type = E;
- using underlying_type = typename enum_underlying_type<enum_type>::type;
+ using underlying_type = typename std::underlying_type<enum_type>::type;
/* For to_string. Maps one enumerator of E to a string. */
struct string_mapping
@@ -392,33 +419,41 @@ ENUM_FLAGS_GEN_COMP (operator!=, !=)
template <typename enum_type,
typename = is_enum_flags_enum_type_t<enum_type>,
typename
- = gdb::Requires<enum_flags_detail::EnumIsUnsigned<enum_type>>>
+ = gdb::Requires<enum_flags_detail::EnumIsSafeForBitwiseComplement<enum_type>>>
constexpr enum_type
operator~ (enum_type e)
{
using underlying = typename enum_flags<enum_type>::underlying_type;
- return (enum_type) ~underlying (e);
+ /* Cast to ULONGEST first, to prevent integer promotions from enums
+ with fixed underlying type std::uint8_t or std::uint16_t to
+ signed int. This ensures we apply the bitwise complement on an
+ unsigned type. */
+ return (enum_type)(underlying) ~ULONGEST (e);
}
template <typename enum_type,
typename = is_enum_flags_enum_type_t<enum_type>,
- typename = gdb::Requires<enum_flags_detail::EnumIsSigned<enum_type>>>
+ typename = gdb::Requires<enum_flags_detail::EnumIsUnsafeForBitwiseComplement<enum_type>>>
constexpr void operator~ (enum_type e) = delete;
template <typename enum_type,
typename = is_enum_flags_enum_type_t<enum_type>,
typename
- = gdb::Requires<enum_flags_detail::EnumIsUnsigned<enum_type>>>
+ = gdb::Requires<enum_flags_detail::EnumIsSafeForBitwiseComplement<enum_type>>>
constexpr enum_flags<enum_type>
operator~ (enum_flags<enum_type> e)
{
using underlying = typename enum_flags<enum_type>::underlying_type;
- return (enum_type) ~underlying (e);
+ /* Cast to ULONGEST first, to prevent integer promotions from enums
+ with fixed underlying type std::uint8_t or std::uint16_t to
+ signed int. This ensures we apply the bitwise complement on an
+ unsigned type. */
+ return (enum_type)(underlying) ~ULONGEST (e);
}
template <typename enum_type,
typename = is_enum_flags_enum_type_t<enum_type>,
- typename = gdb::Requires<enum_flags_detail::EnumIsSigned<enum_type>>>
+ typename = gdb::Requires<enum_flags_detail::EnumIsUnsafeForBitwiseComplement<enum_type>>>
constexpr void operator~ (enum_flags<enum_type> e) = delete;
/* Delete operator<< and operator>>. */
diff --git a/include/diagnostics.h b/include/diagnostics.h
index 97e30ab..2a1d9b9 100644
--- a/include/diagnostics.h
+++ b/include/diagnostics.h
@@ -76,11 +76,6 @@
# define DIAGNOSTIC_ERROR_SWITCH \
DIAGNOSTIC_ERROR ("-Wswitch")
-# if __has_warning ("-Wenum-constexpr-conversion")
-# define DIAGNOSTIC_IGNORE_ENUM_CONSTEXPR_CONVERSION \
- DIAGNOSTIC_IGNORE ("-Wenum-constexpr-conversion")
-# endif
-
#elif defined (__GNUC__) /* GCC */
# define DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS \
@@ -159,8 +154,4 @@
# define DIAGNOSTIC_ERROR_SWITCH
#endif
-#ifndef DIAGNOSTIC_IGNORE_ENUM_CONSTEXPR_CONVERSION
-# define DIAGNOSTIC_IGNORE_ENUM_CONSTEXPR_CONVERSION
-#endif
-
#endif /* DIAGNOSTICS_H */