e(T (-1) < T (0))>::type | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /wrkdirs/usr/ports/devel/gdb/work-py311/gdb-15.1/gdb/../gdbsupport/enum-flags.h:134:20: note: in instantiation of template class 'enum_underlying_type' requested here 134 | typedef typename enum_underlying_type::type underlying_type; | ^ /wrkdirs/usr/ports/devel/gdb/work-py311/gdb-15.1/gdb/ui-out.h:385:16: note: in instantiation of template class 'enum_flags' requested here 385 | ui_out_flags m_flags; | ^ /wrkdirs/usr/ports/devel/gdb/work-py311/gdb-15.1/gdb/../gdbsupport/enum-flags.h:97:52: note: integer value -1 is outside the valid range of values [0, 15] for the enumeration type 'ui_out_flag' 97 | integer_for_size(T (-1) < T (0))>::type | ^ This is because enum-flags.h does some trickery with casting enum values to -1 to determine whether the underlying type is signed or not, as part of its custom template to determine the actual underlying type. It only works because -Wenum-constexpr-conversion is suppressed for this part, but newer versions of clang turn the warning into a hard error. Upstream had https://sourceware.org/bugzilla/show_bug.cgi?id=31331 for this problem. Pull in the patch for it, plus two prerequisites. PR: 292054 Approved by: maintainer timeout (2 weeks) MFH: 2026Q1 --- .../patch-gdb-15-branchpoint-0753-gb050b744be4 | 94 +++++ .../patch-gdb-15-branchpoint-0754-gba96d2e697a | 460 +++++++++++++++++++++ .../patch-gdb-15-branchpoint-1903-g4a0b2cb7210 | 317 ++++++++++++++ 3 files changed, 871 insertions(+) diff --git a/devel/gdb/files/patch-gdb-15-branchpoint-0753-gb050b744be4 b/devel/gdb/files/patch-gdb-15-branchpoint-0753-gb050b744be4 new file mode 100644 index 000000000000..e1b5e6b50c30 --- /dev/null +++ b/devel/gdb/files/patch-gdb-15-branchpoint-0753-gb050b744be4 @@ -0,0 +1,94 @@ +commit b050b744be4c35cb6743e2e4d55935fdff56a01b +Author: Simon Marchi +Date: 2024-05-30T16:28:20-04:00 + + gdb, gdbsupport: use `using` in enum flags code + + I think that `using` is easier to read than `typedef`, and it's the + modern C++ thing anyway. + + Change-Id: Iccb62dc3869cddfb6a684ef3023dcd5b799f3ab2 + +diff --git gdb/unittests/enum-flags-selftests.c gdb/unittests/enum-flags-selftests.c +index b55d8c31406..154a473dd48 100644 +--- gdb/unittests/enum-flags-selftests.c ++++ gdb/unittests/enum-flags-selftests.c +@@ -85,7 +85,7 @@ static EF ef ATTRIBUTE_UNUSED; + #define CHECK_VALID(VALID, EXPR_TYPE, EXPR) \ + CHECK_VALID_EXPR_6 (EF, RE, EF2, RE2, UEF, URE, VALID, EXPR_TYPE, EXPR) + +-typedef std::underlying_type::type und; ++using und = std::underlying_type::type; + + /* Test construction / conversion from/to different types. */ + +@@ -253,7 +253,7 @@ CHECK_VALID (true, int, true ? RE2 () : EF ()) + + /* Same, but with an unsigned enum. */ + +-typedef unsigned int uns; ++using uns = unsigned int; + + CHECK_VALID (true, uns, true ? EF () : UEF ()) + CHECK_VALID (true, uns, true ? UEF () : EF ()) +diff --git gdbsupport/enum-flags.h gdbsupport/enum-flags.h +index 56e0c524f00..764d5219663 100644 +--- gdbsupport/enum-flags.h ++++ gdbsupport/enum-flags.h +@@ -55,7 +55,7 @@ + enum_flags wrapper class for ENUM, and enables the global operator + overloads for ENUM. */ + #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type) \ +- typedef enum_flags flags_type; \ ++ using flags_type = enum_flags; \ + void is_enum_flags_enum_type (enum_type *) + + /* To enable the global enum_flags operators for enum, declare an +@@ -76,24 +76,24 @@ + /* Note that std::underlying_type is not what we want here, + since that returns unsigned int even when the enum decays to signed + int. */ +-template class integer_for_size { typedef void type; }; +-template<> struct integer_for_size<1, 0> { typedef uint8_t type; }; +-template<> struct integer_for_size<2, 0> { typedef uint16_t type; }; +-template<> struct integer_for_size<4, 0> { typedef uint32_t type; }; +-template<> struct integer_for_size<8, 0> { typedef uint64_t type; }; +-template<> struct integer_for_size<1, 1> { typedef int8_t type; }; +-template<> struct integer_for_size<2, 1> { typedef int16_t type; }; +-template<> struct integer_for_size<4, 1> { typedef int32_t type; }; +-template<> struct integer_for_size<8, 1> { typedef int64_t type; }; ++template 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 + struct enum_underlying_type + { + DIAGNOSTIC_PUSH + DIAGNOSTIC_IGNORE_ENUM_CONSTEXPR_CONVERSION +- typedef typename +- integer_for_size(T (-1) < T (0))>::type +- type; ++ using type ++ = typename integer_for_size(T (-1) < T (0))>::type; + DIAGNOSTIC_POP + }; + +@@ -128,8 +128,8 @@ template + class enum_flags + { + public: +- typedef E enum_type; +- typedef typename enum_underlying_type::type underlying_type; ++ using enum_type = E; ++ using underlying_type = typename enum_underlying_type::type; + + /* For to_string. Maps one enumerator of E to a string. */ + struct string_mapping diff --git a/devel/gdb/files/patch-gdb-15-branchpoint-0754-gba96d2e697a b/devel/gdb/files/patch-gdb-15-branchpoint-0754-gba96d2e697a new file mode 100644 index 000000000000..b06849eb6328 --- /dev/null +++ b/devel/gdb/files/patch-gdb-15-branchpoint-0754-gba96d2e697a @@ -0,0 +1,460 @@ +commit ba96d2e697a35517c5ee6b6c20a2fe9a055f7e5f +Author: Simon Marchi +Date: 2024-05-30T16:28:21-04:00 + + gdb: change names of enumerations in enum flags selftest + + When reading this test (in the context of PR 31331), I had trouble + understanding the tests, because of the abbreviated names. I would + prefer if the names were a bit more explicit, like this. + + Change-Id: I85669b238a9d5dacf673a7bbfc1ca18f80d2b2cf + +diff --git gdb/unittests/enum-flags-selftests.c gdb/unittests/enum-flags-selftests.c +index 154a473dd48..dddb1e26202 100644 +--- gdb/unittests/enum-flags-selftests.c ++++ gdb/unittests/enum-flags-selftests.c +@@ -29,49 +29,49 @@ namespace enum_flags_tests { + make it simpler to use. They could be named differently. */ + + /* A "real enum". */ +-enum RE +- { +- RE_FLAG1 = 1 << 1, +- RE_FLAG2 = 1 << 2, +- }; ++enum RawEnum ++{ ++ RawEnum_Flag1 = 1 << 1, ++ RawEnum_Flag2 = 1 << 2, ++}; + + /* Another "real enum". */ +-enum RE2 +- { +- RE2_FLAG1 = 1 << 1, +- RE2_FLAG2 = 1 << 2, +- }; ++enum RawEnum2 ++{ ++ RawEnum2_Flag1 = 1 << 1, ++ RawEnum2_Flag2 = 1 << 2, ++}; + + /* An unsigned "real enum". */ +-enum URE : unsigned +- { +- URE_FLAG1 = 1 << 1, +- URE_FLAG2 = 1 << 2, +- URE_FLAG3 = 0xffffffff, +- }; ++enum UnsignedRawEnum : unsigned ++{ ++ UnsignedRawEnum_Flag1 = 1 << 1, ++ UnsignedRawEnum_Flag2 = 1 << 2, ++ UnsignedRawEnum_Flag3 = 0xffffffff, ++}; + + /* A non-flags enum. */ +-enum NF +- { +- NF_FLAG1 = 1 << 1, +- NF_FLAG2 = 1 << 2, +- }; ++enum NonFlagsEnum ++{ ++ NonFlagsEnum_Flag1 = 1 << 1, ++ NonFlagsEnum_Flag2 = 1 << 2, ++}; + + /* The corresponding "enum flags" types. */ +-DEF_ENUM_FLAGS_TYPE (RE, EF); +-DEF_ENUM_FLAGS_TYPE (RE2, EF2); +-DEF_ENUM_FLAGS_TYPE (URE, UEF); ++DEF_ENUM_FLAGS_TYPE (RawEnum, EnumFlag); ++DEF_ENUM_FLAGS_TYPE (RawEnum2, EnumFlag2); ++DEF_ENUM_FLAGS_TYPE (UnsignedRawEnum, UnsignedEnumFlag); + + /* So that std::vectors of types that have enum_flags fields can + reallocate efficiently memcpy. */ +-static_assert (std::is_trivially_copyable::value); ++static_assert (std::is_trivially_copyable::value); + + /* A couple globals used as lvalues in the CHECK_VALID expressions + below. Their names (and types) match the uppercase type names + exposed by CHECK_VALID just to make the expressions easier to + follow. */ +-static RE re ATTRIBUTE_UNUSED; +-static EF ef ATTRIBUTE_UNUSED; ++static RawEnum re ATTRIBUTE_UNUSED; ++static EnumFlag ef ATTRIBUTE_UNUSED; + + /* First, compile-time tests that: + +@@ -82,30 +82,32 @@ static EF ef ATTRIBUTE_UNUSED; + types do compile and that they return the correct type. + */ + +-#define CHECK_VALID(VALID, EXPR_TYPE, EXPR) \ +- CHECK_VALID_EXPR_6 (EF, RE, EF2, RE2, UEF, URE, VALID, EXPR_TYPE, EXPR) ++#define CHECK_VALID(VALID, EXPR_TYPE, EXPR) \ ++ CHECK_VALID_EXPR_6 (EnumFlag, RawEnum, EnumFlag2, RawEnum2, \ ++ UnsignedEnumFlag, UnsignedRawEnum, VALID, EXPR_TYPE, \ ++ EXPR) + +-using und = std::underlying_type::type; ++using und = std::underlying_type::type; + + /* Test construction / conversion from/to different types. */ + + /* RE/EF -> underlying (explicit) */ +-CHECK_VALID (true, und, und (RE ())) +-CHECK_VALID (true, und, und (EF ())) ++CHECK_VALID (true, und, und (RawEnum ())) ++CHECK_VALID (true, und, und (EnumFlag ())) + + /* RE/EF -> int (explicit) */ +-CHECK_VALID (true, int, int (RE ())) +-CHECK_VALID (true, int, int (EF ())) ++CHECK_VALID (true, int, int (RawEnum ())) ++CHECK_VALID (true, int, int (EnumFlag ())) + + /* other -> RE */ + + /* You can construct a raw enum value from an int explicitly to punch + a hole in the type system if need to. */ +-CHECK_VALID (true, RE, RE (1)) +-CHECK_VALID (true, RE, RE (RE2 ())) +-CHECK_VALID (false, void, RE (EF2 ())) +-CHECK_VALID (true, RE, RE (RE ())) +-CHECK_VALID (false, void, RE (EF ())) ++CHECK_VALID (true, RawEnum, RawEnum (1)) ++CHECK_VALID (true, RawEnum, RawEnum (RawEnum2 ())) ++CHECK_VALID (false, void, RawEnum (EnumFlag2 ())) ++CHECK_VALID (true, RawEnum, RawEnum (RawEnum ())) ++CHECK_VALID (false, void, RawEnum (EnumFlag ())) + + /* other -> EF. */ + +@@ -113,125 +115,125 @@ CHECK_VALID (false, void, RE (EF ())) + enum. Unlike with raw enums, you can't construct an enum flags + from an integer nor from an unrelated enum type explicitly. Add an + intermediate conversion via the raw enum if you really need it. */ +-CHECK_VALID (false, void, EF (1)) +-CHECK_VALID (false, void, EF (1u)) +-CHECK_VALID (false, void, EF (RE2 ())) +-CHECK_VALID (false, void, EF (EF2 ())) +-CHECK_VALID (true, EF, EF (RE ())) +-CHECK_VALID (true, EF, EF (EF ())) ++CHECK_VALID (false, void, EnumFlag (1)) ++CHECK_VALID (false, void, EnumFlag (1u)) ++CHECK_VALID (false, void, EnumFlag (RawEnum2 ())) ++CHECK_VALID (false, void, EnumFlag (EnumFlag2 ())) ++CHECK_VALID (true, EnumFlag, EnumFlag (RawEnum ())) ++CHECK_VALID (true, EnumFlag, EnumFlag (EnumFlag ())) + + /* Test operators. */ + + /* operator OP (raw_enum, int) */ + +-CHECK_VALID (false, void, RE () | 1) +-CHECK_VALID (false, void, RE () & 1) +-CHECK_VALID (false, void, RE () ^ 1) ++CHECK_VALID (false, void, RawEnum () | 1) ++CHECK_VALID (false, void, RawEnum () & 1) ++CHECK_VALID (false, void, RawEnum () ^ 1) + + /* operator OP (int, raw_enum) */ + +-CHECK_VALID (false, void, 1 | RE ()) +-CHECK_VALID (false, void, 1 & RE ()) +-CHECK_VALID (false, void, 1 ^ RE ()) ++CHECK_VALID (false, void, 1 | RawEnum ()) ++CHECK_VALID (false, void, 1 & RawEnum ()) ++CHECK_VALID (false, void, 1 ^ RawEnum ()) + + /* operator OP (enum_flags, int) */ + +-CHECK_VALID (false, void, EF () | 1) +-CHECK_VALID (false, void, EF () & 1) +-CHECK_VALID (false, void, EF () ^ 1) ++CHECK_VALID (false, void, EnumFlag () | 1) ++CHECK_VALID (false, void, EnumFlag () & 1) ++CHECK_VALID (false, void, EnumFlag () ^ 1) + + /* operator OP (int, enum_flags) */ + +-CHECK_VALID (false, void, 1 | EF ()) +-CHECK_VALID (false, void, 1 & EF ()) +-CHECK_VALID (false, void, 1 ^ EF ()) ++CHECK_VALID (false, void, 1 | EnumFlag ()) ++CHECK_VALID (false, void, 1 & EnumFlag ()) ++CHECK_VALID (false, void, 1 ^ EnumFlag ()) + + /* operator OP (raw_enum, raw_enum) */ + +-CHECK_VALID (false, void, RE () | RE2 ()) +-CHECK_VALID (false, void, RE () & RE2 ()) +-CHECK_VALID (false, void, RE () ^ RE2 ()) +-CHECK_VALID (true, RE, RE () | RE ()) +-CHECK_VALID (true, RE, RE () & RE ()) +-CHECK_VALID (true, RE, RE () ^ RE ()) ++CHECK_VALID (false, void, RawEnum () | RawEnum2 ()) ++CHECK_VALID (false, void, RawEnum () & RawEnum2 ()) ++CHECK_VALID (false, void, RawEnum () ^ RawEnum2 ()) ++CHECK_VALID (true, RawEnum, RawEnum () | RawEnum ()) ++CHECK_VALID (true, RawEnum, RawEnum () & RawEnum ()) ++CHECK_VALID (true, RawEnum, RawEnum () ^ RawEnum ()) + + /* operator OP (enum_flags, raw_enum) */ + +-CHECK_VALID (false, void, EF () | RE2 ()) +-CHECK_VALID (false, void, EF () & RE2 ()) +-CHECK_VALID (false, void, EF () ^ RE2 ()) +-CHECK_VALID (true, EF, EF () | RE ()) +-CHECK_VALID (true, EF, EF () & RE ()) +-CHECK_VALID (true, EF, EF () ^ RE ()) ++CHECK_VALID (false, void, EnumFlag () | RawEnum2 ()) ++CHECK_VALID (false, void, EnumFlag () & RawEnum2 ()) ++CHECK_VALID (false, void, EnumFlag () ^ RawEnum2 ()) ++CHECK_VALID (true, EnumFlag, EnumFlag () | RawEnum ()) ++CHECK_VALID (true, EnumFlag, EnumFlag () & RawEnum ()) ++CHECK_VALID (true, EnumFlag, EnumFlag () ^ RawEnum ()) + + /* operator OP= (raw_enum, raw_enum), rvalue ref on the lhs. */ + +-CHECK_VALID (false, void, RE () |= RE2 ()) +-CHECK_VALID (false, void, RE () &= RE2 ()) +-CHECK_VALID (false, void, RE () ^= RE2 ()) +-CHECK_VALID (false, void, RE () |= RE ()) +-CHECK_VALID (false, void, RE () &= RE ()) +-CHECK_VALID (false, void, RE () ^= RE ()) ++CHECK_VALID (false, void, RawEnum () |= RawEnum2 ()) ++CHECK_VALID (false, void, RawEnum () &= RawEnum2 ()) ++CHECK_VALID (false, void, RawEnum () ^= RawEnum2 ()) ++CHECK_VALID (false, void, RawEnum () |= RawEnum ()) ++CHECK_VALID (false, void, RawEnum () &= RawEnum ()) ++CHECK_VALID (false, void, RawEnum () ^= RawEnum ()) + + /* operator OP= (raw_enum, raw_enum), lvalue ref on the lhs. */ + +-CHECK_VALID (false, void, re |= RE2 ()) +-CHECK_VALID (false, void, re &= RE2 ()) +-CHECK_VALID (false, void, re ^= RE2 ()) +-CHECK_VALID (true, RE&, re |= RE ()) +-CHECK_VALID (true, RE&, re &= RE ()) +-CHECK_VALID (true, RE&, re ^= RE ()) ++CHECK_VALID (false, void, re |= RawEnum2 ()) ++CHECK_VALID (false, void, re &= RawEnum2 ()) ++CHECK_VALID (false, void, re ^= RawEnum2 ()) ++CHECK_VALID (true, RawEnum&, re |= RawEnum ()) ++CHECK_VALID (true, RawEnum&, re &= RawEnum ()) ++CHECK_VALID (true, RawEnum&, re ^= RawEnum ()) + + /* operator OP= (enum_flags, raw_enum), rvalue ref on the lhs. */ + +-CHECK_VALID (false, void, EF () |= RE2 ()) +-CHECK_VALID (false, void, EF () &= RE2 ()) +-CHECK_VALID (false, void, EF () ^= RE2 ()) +-CHECK_VALID (false, void, EF () |= RE ()) +-CHECK_VALID (false, void, EF () &= RE ()) +-CHECK_VALID (false, void, EF () ^= RE ()) ++CHECK_VALID (false, void, EnumFlag () |= RawEnum2 ()) ++CHECK_VALID (false, void, EnumFlag () &= RawEnum2 ()) ++CHECK_VALID (false, void, EnumFlag () ^= RawEnum2 ()) ++CHECK_VALID (false, void, EnumFlag () |= RawEnum ()) ++CHECK_VALID (false, void, EnumFlag () &= RawEnum ()) ++CHECK_VALID (false, void, EnumFlag () ^= RawEnum ()) + + /* operator OP= (enum_flags, raw_enum), lvalue ref on the lhs. */ + +-CHECK_VALID (false, void, ef |= RE2 ()) +-CHECK_VALID (false, void, ef &= RE2 ()) +-CHECK_VALID (false, void, ef ^= RE2 ()) +-CHECK_VALID (true, EF&, ef |= EF ()) +-CHECK_VALID (true, EF&, ef &= EF ()) +-CHECK_VALID (true, EF&, ef ^= EF ()) ++CHECK_VALID (false, void, ef |= RawEnum2 ()) ++CHECK_VALID (false, void, ef &= RawEnum2 ()) ++CHECK_VALID (false, void, ef ^= RawEnum2 ()) ++CHECK_VALID (true, EnumFlag&, ef |= EnumFlag ()) ++CHECK_VALID (true, EnumFlag&, ef &= EnumFlag ()) ++CHECK_VALID (true, EnumFlag&, ef ^= EnumFlag ()) + + /* operator OP= (enum_flags, enum_flags), rvalue ref on the lhs. */ + +-CHECK_VALID (false, void, EF () |= EF2 ()) +-CHECK_VALID (false, void, EF () &= EF2 ()) +-CHECK_VALID (false, void, EF () ^= EF2 ()) +-CHECK_VALID (false, void, EF () |= EF ()) +-CHECK_VALID (false, void, EF () &= EF ()) +-CHECK_VALID (false, void, EF () ^= EF ()) ++CHECK_VALID (false, void, EnumFlag () |= EnumFlag2 ()) ++CHECK_VALID (false, void, EnumFlag () &= EnumFlag2 ()) ++CHECK_VALID (false, void, EnumFlag () ^= EnumFlag2 ()) ++CHECK_VALID (false, void, EnumFlag () |= EnumFlag ()) ++CHECK_VALID (false, void, EnumFlag () &= EnumFlag ()) ++CHECK_VALID (false, void, EnumFlag () ^= EnumFlag ()) + + /* operator OP= (enum_flags, enum_flags), lvalue ref on the lhs. */ + +-CHECK_VALID (false, void, ef |= EF2 ()) +-CHECK_VALID (false, void, ef &= EF2 ()) +-CHECK_VALID (false, void, ef ^= EF2 ()) +-CHECK_VALID (true, EF&, ef |= EF ()) +-CHECK_VALID (true, EF&, ef &= EF ()) +-CHECK_VALID (true, EF&, ef ^= EF ()) ++CHECK_VALID (false, void, ef |= EnumFlag2 ()) ++CHECK_VALID (false, void, ef &= EnumFlag2 ()) ++CHECK_VALID (false, void, ef ^= EnumFlag2 ()) ++CHECK_VALID (true, EnumFlag&, ef |= EnumFlag ()) ++CHECK_VALID (true, EnumFlag&, ef &= EnumFlag ()) ++CHECK_VALID (true, EnumFlag&, ef ^= EnumFlag ()) + + /* operator~ (raw_enum) */ + +-CHECK_VALID (false, void, ~RE ()) +-CHECK_VALID (true, URE, ~URE ()) ++CHECK_VALID (false, void, ~RawEnum ()) ++CHECK_VALID (true, UnsignedRawEnum, ~UnsignedRawEnum ()) + + /* operator~ (enum_flags) */ + +-CHECK_VALID (false, void, ~EF ()) +-CHECK_VALID (true, UEF, ~UEF ()) ++CHECK_VALID (false, void, ~EnumFlag ()) ++CHECK_VALID (true, UnsignedEnumFlag, ~UnsignedEnumFlag ()) + + /* Check ternary operator. This exercises implicit conversions. */ + +-CHECK_VALID (true, EF, true ? EF () : RE ()) +-CHECK_VALID (true, EF, true ? RE () : EF ()) ++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 +@@ -246,19 +248,19 @@ CHECK_VALID (true, EF, true ? RE () : EF ()) + They've been confirmed to compile/pass with gcc 5.3, gcc 7.1 and + clang 3.7. */ + +-CHECK_VALID (true, int, true ? EF () : EF2 ()) +-CHECK_VALID (true, int, true ? EF2 () : EF ()) +-CHECK_VALID (true, int, true ? EF () : RE2 ()) +-CHECK_VALID (true, int, true ? RE2 () : EF ()) ++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 ? EF () : UEF ()) +-CHECK_VALID (true, uns, true ? UEF () : EF ()) +-CHECK_VALID (true, uns, true ? EF () : URE ()) +-CHECK_VALID (true, uns, true ? URE () : EF ()) ++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 +@@ -270,39 +272,39 @@ CHECK_VALID (true, uns, true ? URE () : EF ()) + error: operands to ?: have different types ‘enum_flags’ and ‘int’ + Confirmed to work with gcc 4.9, 5.3 and clang 3.7. + */ +-CHECK_VALID (false, void, true ? EF () : 0) +-CHECK_VALID (false, void, true ? 0 : EF ()) ++CHECK_VALID (false, void, true ? EnumFlag () : 0) ++CHECK_VALID (false, void, true ? 0 : EnumFlag ()) + + /* Check that the ++/--/<>/<<=/>>= operators are deleted. */ + +-CHECK_VALID (false, void, RE ()++) +-CHECK_VALID (false, void, ++RE ()) +-CHECK_VALID (false, void, --RE ()) +-CHECK_VALID (false, void, RE ()--) ++CHECK_VALID (false, void, RawEnum ()++) ++CHECK_VALID (false, void, ++RawEnum ()) ++CHECK_VALID (false, void, --RawEnum ()) ++CHECK_VALID (false, void, RawEnum ()--) + +-CHECK_VALID (false, void, RE () << 1) +-CHECK_VALID (false, void, RE () >> 1) +-CHECK_VALID (false, void, EF () << 1) +-CHECK_VALID (false, void, EF () >> 1) ++CHECK_VALID (false, void, RawEnum () << 1) ++CHECK_VALID (false, void, RawEnum () >> 1) ++CHECK_VALID (false, void, EnumFlag () << 1) ++CHECK_VALID (false, void, EnumFlag () >> 1) + +-CHECK_VALID (false, void, RE () <<= 1) +-CHECK_VALID (false, void, RE () >>= 1) +-CHECK_VALID (false, void, EF () <<= 1) +-CHECK_VALID (false, void, EF () >>= 1) ++CHECK_VALID (false, void, RawEnum () <<= 1) ++CHECK_VALID (false, void, RawEnum () >>= 1) ++CHECK_VALID (false, void, EnumFlag () <<= 1) ++CHECK_VALID (false, void, EnumFlag () >>= 1) + + /* Test comparison operators. */ + +-CHECK_VALID (false, void, EF () == EF2 ()) +-CHECK_VALID (false, void, EF () == RE2 ()) +-CHECK_VALID (false, void, RE () == EF2 ()) ++CHECK_VALID (false, void, EnumFlag () == EnumFlag2 ()) ++CHECK_VALID (false, void, EnumFlag () == RawEnum2 ()) ++CHECK_VALID (false, void, RawEnum () == EnumFlag2 ()) + +-CHECK_VALID (true, bool, EF (RE (1)) == EF (RE (1))) +-CHECK_VALID (true, bool, EF (RE (1)) == RE (1)) +-CHECK_VALID (true, bool, RE (1) == EF (RE (1))) ++CHECK_VALID (true, bool, EnumFlag (RawEnum (1)) == EnumFlag (RawEnum (1))) ++CHECK_VALID (true, bool, EnumFlag (RawEnum (1)) == RawEnum (1)) ++CHECK_VALID (true, bool, RawEnum (1) == EnumFlag (RawEnum (1))) + +-CHECK_VALID (false, void, EF () != EF2 ()) +-CHECK_VALID (false, void, EF () != RE2 ()) +-CHECK_VALID (false, void, RE () != EF2 ()) ++CHECK_VALID (false, void, EnumFlag () != EnumFlag2 ()) ++CHECK_VALID (false, void, EnumFlag () != RawEnum2 ()) ++CHECK_VALID (false, void, RawEnum () != EnumFlag2 ()) + + /* Disable -Wenum-compare due to: + +@@ -323,23 +325,23 @@ CHECK_VALID (false, void, RE () != EF2 ()) + # pragma GCC diagnostic push + # pragma GCC diagnostic ignored "-Wenum-compare" + #endif +-CHECK_VALID (true, bool, RE () == RE2 ()) +-CHECK_VALID (true, bool, RE () != RE2 ()) ++CHECK_VALID (true, bool, RawEnum () == RawEnum2 ()) ++CHECK_VALID (true, bool, RawEnum () != RawEnum2 ()) + #if defined __GNUC__ + # pragma GCC diagnostic pop + #endif + +-CHECK_VALID (true, bool, EF (RE (1)) != EF (RE (2))) +-CHECK_VALID (true, bool, EF (RE (1)) != RE (2)) +-CHECK_VALID (true, bool, RE (1) != EF (RE (2))) ++CHECK_VALID (true, bool, EnumFlag (RawEnum (1)) != EnumFlag (RawEnum (2))) ++CHECK_VALID (true, bool, EnumFlag (RawEnum (1)) != RawEnum (2)) ++CHECK_VALID (true, bool, RawEnum (1) != EnumFlag (RawEnum (2))) + +-CHECK_VALID (true, bool, EF () == 0) ++CHECK_VALID (true, bool, EnumFlag () == 0) + + /* Check we didn't disable/delete comparison between non-flags enums + and unrelated types by mistake. */ +-CHECK_VALID (true, bool, NF (1) == NF (1)) +-CHECK_VALID (true, bool, NF (1) == int (1)) +-CHECK_VALID (true, bool, NF (1) == char (1)) ++CHECK_VALID (true, bool, NonFlagsEnum (1) == NonFlagsEnum (1)) ++CHECK_VALID (true, bool, NonFlagsEnum (1) == int (1)) ++CHECK_VALID (true, bool, NonFlagsEnum (1) == char (1)) + + /* -------------------------------------------------------------------- */ + diff --git a/devel/gdb/files/patch-gdb-15-branchpoint-1903-g4a0b2cb7210 b/devel/gdb/files/patch-gdb-15-branchpoint-1903-g4a0b2cb7210 new file mode 100644 index 000000000000..003c8d5dec33 --- /dev/null +++ b/devel/gdb/files/patch-gdb-15-branchpoint-1903-g4a0b2cb7210 @@ -0,0 +1,317 @@ +commit 4a0b2cb7210c65c8c9f4a56345749bb7294fbfbf +Author: Carlos Galvez +Date: 2024-12-21T22:25:40+01:00 + + Fix -Wenum-constexpr-conversion in enum-flags.h + + This fixes PR 31331: + https://sourceware.org/bugzilla/show_bug.cgi?id=31331 + + Currently, enum-flags.h is suppressing the warning + -Wenum-constexpr-conversion coming from recent versions of Clang. + This warning is intended to be made a compiler error + (non-downgradeable) in future versions of Clang: + + https://github.com/llvm/llvm-project/issues/59036 + + The rationale is that casting a value of an integral type into an + enumeration is Undefined Behavior if the value does not fit in the + range of values of the enum: + https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1766 + + Undefined Behavior is not allowed in constant expressions, leading to + an ill-formed program. + + In this case, in enum-flags.h, we are casting the value -1 to an enum + of a positive range only, which is UB as per the Standard and thus not + allowed in a constexpr context. + + The purpose of doing this instead of using std::underlying_type is + because, for C-style enums, std::underlying_type typically returns + "unsigned int". However, when operating with it arithmetically, the + enum is promoted to *signed* int, which is what we want to avoid. + + This patch solves this issue as follows: + + * Use std::underlying_type and remove the custom enum_underlying_type. + + * Ensure that operator~ is called always on an unsigned integer. We do + this by casting the input enum into std::size_t, which can fit any + unsigned integer. We have the guarantee that the cast is safe, + because we have checked that the underlying type is unsigned. If the + enum had negative values, the underlying type would be signed. + + This solves the issue with C-style enums, but also solves a hidden + issue: enums with underlying type of std::uint8_t or std::uint16_t are + *also* promoted to signed int. Now they are all explicitly casted + to the largest unsigned int type and operator~ is safe to use. + + * There is one more thing that needs fix. Currently, operator~ is + implemented as follows: + + return (enum_type) ~underlying(e); + + After applying ~underlying(e), the result is a very large value, + which we then cast to "enum_type". This cast is Undefined Behavior + if the large value does not fit in the range of the enum. For + C++ enums (scoped and/or with explicit underlying type), the range + of the enum is the entire range of the underlying type, so the cast + is safe. However, for C-style enums, the range is the smallest + bit-field that can hold all the values of the enumeration. So the + range is a lot smaller and casting a large value to the enum would + invoke Undefined Behavior. + + To solve this problem, we create a new trait + EnumHasFixedUnderlyingType, to ensure operator~ may only be called + on C++-style enums. This behavior is roughly the same as what we + had on trunk, but relying on different properties of the enums. + + * Once this is implemented, the following tests fail to compile: + + CHECK_VALID (true, int, true ? EF () : EF2 ()) + + This is because it expects the enums to be promoted to signed int, + instead of unsigned int (which is the true underlying type). + + I propose to remove these tests altogether, because: + + - The comment nearby say they are not very important. + - Comparing 2 enums of different type like that is strange, relies + on integer promotions and thus hurts readability. As per comments + in the related PR, we likely don't want this type of code in gdb + code anyway, so there's no point in testing it. + - Most importantly, this type of comparison will be ill-formed in + C++26 for regular enums, so enum_flags does not need to emulate + that. + + Since this is the only place where the warning was suppressed, remove + also the corresponding macro in include/diagnostics.h. + + The change has been tested by running the entire gdb test suite + (make check) and comparing the results (testsuite/gdb.sum) against + trunk. No noticeable differences have been observed. + + Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31331 + Tested-by: Keith Seitz + Approved-By: Tom Tromey + +diff --git gdb/unittests/enum-flags-selftests.c gdb/unittests/enum-flags-selftests.c +index dddb1e26202..f192da37b41 100644 +--- gdb/unittests/enum-flags-selftests.c ++++ 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 gdbsupport/enum-flags.h gdbsupport/enum-flags.h +index d3291e95d7e..71109bb8c99 100644 +--- gdbsupport/enum-flags.h ++++ 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 is not what we want here, +- since that returns unsigned int even when the enum decays to signed +- int. */ +-template 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 +-struct enum_underlying_type +-{ +- DIAGNOSTIC_PUSH +- DIAGNOSTIC_IGNORE_ENUM_CONSTEXPR_CONVERSION +- using type +- = typename integer_for_size(T (-1) < T (0))>::type; +- DIAGNOSTIC_POP +-}; +- + namespace enum_flags_detail + { + +@@ -117,10 +93,61 @@ struct zero_type; + /* gdb::Requires trait helpers. */ + template + using EnumIsUnsigned +- = std::is_unsigned::type>; ++ = std::is_unsigned::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 ++struct EnumHasFixedUnderlyingType : std::false_type ++{ ++ static_assert(std::is_enum::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 +-using EnumIsSigned +- = std::is_signed::type>; ++struct EnumHasFixedUnderlyingType> : std::true_type ++{ ++ static_assert(std::is_enum::value); ++}; ++ ++template ++using EnumIsSafeForBitwiseComplement = std::conjunction< ++ EnumIsUnsigned, ++ EnumHasFixedUnderlyingType ++>; ++ ++template ++using EnumIsUnsafeForBitwiseComplement = std::negation>; + + } + +@@ -129,7 +156,7 @@ class enum_flags + { + public: + using enum_type = E; +- using underlying_type = typename enum_underlying_type::type; ++ using underlying_type = typename std::underlying_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 +- = gdb::Requires>> ++ = gdb::Requires>> + constexpr enum_type + operator~ (enum_type e) + { + using underlying = typename enum_flags::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 = gdb::Requires>> ++ typename = gdb::Requires>> + constexpr void operator~ (enum_type e) = delete; + + template , + typename +- = gdb::Requires>> ++ = gdb::Requires>> + constexpr enum_flags + operator~ (enum_flags e) + { + using underlying = typename enum_flags::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 = gdb::Requires>> ++ typename = gdb::Requires>> + constexpr void operator~ (enum_flags e) = delete; + + /* Delete operator<< and operator>>. */ +diff --git include/diagnostics.h include/diagnostics.h +index 97e30ab807f..2a1d9b92fad 100644 +--- include/diagnostics.h ++++ 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 */