From 071b4f70628cab2be31f1c36768eab6b4b64259a Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 10 Jun 2026 12:04:27 +0100 Subject: [PATCH] AK: Allow derived types to create base badges Derived classes can now mint their own badge and pass it to APIs that accept a badge for an authorized base class. --- AK/Badge.h | 49 ++++++++++++++++++++++++++++ Tests/AK/TestBadge.cpp | 74 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/AK/Badge.h b/AK/Badge.h index 49835f462c..dd43cb339d 100644 --- a/AK/Badge.h +++ b/AK/Badge.h @@ -8,9 +8,18 @@ #include #include +#include namespace AK { +namespace Detail { + +template +inline constexpr bool IsBadgeType = IsSame + || IsBaseOf; + +} + template class Badge; @@ -22,6 +31,14 @@ class Badge { public: using Type = T; + // Friendship is not inherited, so derived classes mint Badge and + // convert it to Badge. + template + requires(IsBaseOf && !IsSame) + constexpr Badge(Badge const&) + { + } + private: friend T; constexpr Badge() = default; @@ -34,6 +51,13 @@ class Badge { AK_MAKE_NONCOPYABLE(Badge); AK_MAKE_NONMOVABLE(Badge); +public: + template + requires(Detail::IsBadgeType || Detail::IsBadgeType) + constexpr Badge(Badge const&) + { + } + private: friend T; friend U; @@ -45,6 +69,14 @@ class Badge { AK_MAKE_NONCOPYABLE(Badge); AK_MAKE_NONMOVABLE(Badge); +public: + template + requires(Detail::IsBadgeType || Detail::IsBadgeType + || Detail::IsBadgeType) + constexpr Badge(Badge const&) + { + } + private: friend T; friend U; @@ -57,6 +89,14 @@ class Badge { AK_MAKE_NONCOPYABLE(Badge); AK_MAKE_NONMOVABLE(Badge); +public: + template + requires(Detail::IsBadgeType || Detail::IsBadgeType + || Detail::IsBadgeType || Detail::IsBadgeType) + constexpr Badge(Badge const&) + { + } + private: friend T; friend U; @@ -70,6 +110,15 @@ class Badge { AK_MAKE_NONCOPYABLE(Badge); AK_MAKE_NONMOVABLE(Badge); +public: + template + requires(Detail::IsBadgeType || Detail::IsBadgeType + || Detail::IsBadgeType || Detail::IsBadgeType + || Detail::IsBadgeType) + constexpr Badge(Badge const&) + { + } + private: friend T; friend U; diff --git a/Tests/AK/TestBadge.cpp b/Tests/AK/TestBadge.cpp index 3a270576f1..91c9b1b9cc 100644 --- a/Tests/AK/TestBadge.cpp +++ b/Tests/AK/TestBadge.cpp @@ -36,6 +36,16 @@ struct MultipleBadgeUserE { struct UnrelatedBadgeUser { }; +struct BaseBadgeUser { + static void call_base_badge(); + static void call_multi_base_badge(); +}; + +struct DerivedBadgeUser : BaseBadgeUser { + static void call_base_badge(); + static void call_multi_base_badge(); +}; + static void accepts_two_argument_badge(Badge) { } @@ -52,6 +62,14 @@ static void accepts_five_argument_badge(Badge) +{ +} + +static void accepts_multi_base_badge(Badge) +{ +} + void MultipleBadgeUserA::call_two_argument_badge() { accepts_two_argument_badge({}); @@ -92,6 +110,26 @@ void MultipleBadgeUserE::call_five_argument_badge() accepts_five_argument_badge({}); } +void BaseBadgeUser::call_base_badge() +{ + accepts_base_badge({}); +} + +void BaseBadgeUser::call_multi_base_badge() +{ + accepts_multi_base_badge({}); +} + +void DerivedBadgeUser::call_base_badge() +{ + accepts_base_badge(Badge {}); +} + +void DerivedBadgeUser::call_multi_base_badge() +{ + accepts_multi_base_badge(Badge {}); +} + } TEST_CASE(should_provide_underlying_type) @@ -104,11 +142,13 @@ TEST_CASE(should_allow_multiple_underlying_types) static_assert(!IsConstructible>); static_assert(!IsConstructible>); static_assert(!IsConstructible>); - static_assert(!IsConstructible, Badge>); static_assert(!IsConstructible>); - static_assert(!IsConstructible< + static_assert(IsConstructible< Badge, Badge const&>); + static_assert(IsConstructible< + Badge, + Badge const&>); static_assert(!IsConstructible, Badge>); MultipleBadgeUserA::call_two_argument_badge(); @@ -120,3 +160,33 @@ TEST_CASE(should_allow_multiple_underlying_types) MultipleBadgeUserD::call_four_argument_badge(); MultipleBadgeUserE::call_five_argument_badge(); } + +TEST_CASE(should_allow_derived_types_to_create_base_badges) +{ + static_assert(IsConstructible< + Badge, + Badge const&>); + static_assert(IsConstructible< + Badge, + Badge const&>); + static_assert(IsConstructible< + Badge, + Badge const&>); + static_assert(IsConstructible< + Badge, + Badge const&>); + static_assert(!IsConstructible< + Badge, + Badge const&>); + static_assert(!IsConstructible< + Badge, + Badge const&>); + static_assert(!IsConstructible< + Badge, + Badge const&>); + + BaseBadgeUser::call_base_badge(); + BaseBadgeUser::call_multi_base_badge(); + DerivedBadgeUser::call_base_badge(); + DerivedBadgeUser::call_multi_base_badge(); +}