mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-13 21:12:26 +00:00
AK: Don't implicitly convert Optional<T&> to Optional<T>
C++ will jovially select the implicit conversion operator, even if it's complete bogus, such as for unknown-size types or non-destructible types. Therefore, all such conversions (which incur a copy) must (unfortunately) be explicit so that non-copyable types continue to work. NOTE: We make an exception for trivially copyable types, since they are, well, trivially copyable. Co-authored-by: kleines Filmröllchen <filmroellchen@serenityos.org>
This commit is contained in:
parent
8468fb9ae5
commit
d7596a0a61
Notes:
github-actions[bot]
2024-12-04 00:59:23 +00:00
Author: https://github.com/yyny
Commit: d7596a0a61
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2567
Reviewed-by: https://github.com/alimpfard
Reviewed-by: https://github.com/gmta ✅
22 changed files with 118 additions and 40 deletions
|
@ -13,6 +13,39 @@
|
|||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
|
||||
class NonCopyable {
|
||||
AK_MAKE_NONCOPYABLE(NonCopyable);
|
||||
AK_MAKE_DEFAULT_MOVABLE(NonCopyable);
|
||||
|
||||
public:
|
||||
NonCopyable() { }
|
||||
~NonCopyable() = default;
|
||||
|
||||
int x { 13 };
|
||||
};
|
||||
|
||||
class NonTriviallyCopyable {
|
||||
AK_MAKE_DEFAULT_COPYABLE(NonTriviallyCopyable);
|
||||
AK_MAKE_DEFAULT_MOVABLE(NonTriviallyCopyable);
|
||||
|
||||
public:
|
||||
NonTriviallyCopyable() = default;
|
||||
~NonTriviallyCopyable() = default;
|
||||
|
||||
ByteString x { "13" };
|
||||
};
|
||||
|
||||
class TriviallyCopyable {
|
||||
AK_MAKE_DEFAULT_COPYABLE(TriviallyCopyable);
|
||||
AK_MAKE_DEFAULT_MOVABLE(TriviallyCopyable);
|
||||
|
||||
public:
|
||||
TriviallyCopyable() = default;
|
||||
~TriviallyCopyable() = default;
|
||||
|
||||
int x { 13 };
|
||||
};
|
||||
|
||||
TEST_CASE(basic_optional)
|
||||
{
|
||||
Optional<int> x;
|
||||
|
@ -39,23 +72,12 @@ TEST_CASE(move_optional)
|
|||
|
||||
TEST_CASE(optional_rvalue_ref_qualified_getters)
|
||||
{
|
||||
struct DontCopyMe {
|
||||
DontCopyMe() { }
|
||||
~DontCopyMe() = default;
|
||||
DontCopyMe(DontCopyMe&&) = default;
|
||||
DontCopyMe& operator=(DontCopyMe&&) = default;
|
||||
DontCopyMe(DontCopyMe const&) = delete;
|
||||
DontCopyMe& operator=(DontCopyMe const&) = delete;
|
||||
|
||||
int x { 13 };
|
||||
};
|
||||
|
||||
auto make_an_optional = []() -> Optional<DontCopyMe> {
|
||||
return DontCopyMe {};
|
||||
auto make_an_optional = []() -> Optional<NonCopyable> {
|
||||
return NonCopyable {};
|
||||
};
|
||||
|
||||
EXPECT_EQ(make_an_optional().value().x, 13);
|
||||
EXPECT_EQ(make_an_optional().value_or(DontCopyMe {}).x, 13);
|
||||
EXPECT_EQ(make_an_optional().value_or(NonCopyable {}).x, 13);
|
||||
}
|
||||
|
||||
TEST_CASE(optional_leak_1)
|
||||
|
@ -299,6 +321,47 @@ static_assert(CheckAssignments<Optional<int const&>, int const&>::allowed);
|
|||
static_assert(CheckAssignments<Optional<int const&>, int&&>::allowed); // Lifetime extension
|
||||
static_assert(CheckAssignments<Optional<int const&>, int const&&>::allowed); // Lifetime extension
|
||||
|
||||
static_assert(CheckAssignments<Optional<NonTriviallyCopyable const&>, NonTriviallyCopyable&>::allowed);
|
||||
static_assert(CheckAssignments<Optional<NonTriviallyCopyable const&>, NonTriviallyCopyable const&>::allowed);
|
||||
static_assert(CheckAssignments<Optional<NonTriviallyCopyable const&>, NonTriviallyCopyable&&>::allowed); // Lifetime extension
|
||||
static_assert(CheckAssignments<Optional<NonTriviallyCopyable const&>, NonTriviallyCopyable const&&>::allowed); // Lifetime extension
|
||||
|
||||
static_assert(CheckAssignments<Optional<TriviallyCopyable const&>, TriviallyCopyable>::allowed);
|
||||
static_assert(CheckAssignments<Optional<TriviallyCopyable const&>, TriviallyCopyable const&>::allowed);
|
||||
static_assert(CheckAssignments<Optional<TriviallyCopyable const&>, Optional<TriviallyCopyable>>::allowed);
|
||||
static_assert(CheckAssignments<Optional<TriviallyCopyable const&>, Optional<TriviallyCopyable const&>>::allowed);
|
||||
static_assert(CheckAssignments<Optional<TriviallyCopyable>, Optional<TriviallyCopyable const&>>::allowed);
|
||||
|
||||
static_assert(CheckAssignments<Optional<NonTriviallyCopyable const&>, NonTriviallyCopyable>::allowed);
|
||||
static_assert(CheckAssignments<Optional<NonTriviallyCopyable const&>, NonTriviallyCopyable const&>::allowed);
|
||||
static_assert(CheckAssignments<Optional<NonTriviallyCopyable const&>, Optional<NonTriviallyCopyable>>::allowed);
|
||||
static_assert(CheckAssignments<Optional<NonTriviallyCopyable const&>, Optional<NonTriviallyCopyable const&>>::allowed);
|
||||
static_assert(!CheckAssignments<Optional<NonTriviallyCopyable>, Optional<NonTriviallyCopyable const&>>::allowed);
|
||||
|
||||
TEST_CASE(nontrivially_copyable_assignment)
|
||||
{
|
||||
{
|
||||
TriviallyCopyable x {};
|
||||
Optional<TriviallyCopyable const&> y = x;
|
||||
Optional<TriviallyCopyable> z = y; // Can copy implicitly
|
||||
EXPECT_EQ(z->x, 13);
|
||||
}
|
||||
|
||||
{
|
||||
NonTriviallyCopyable x {};
|
||||
Optional<NonTriviallyCopyable const&> y = x;
|
||||
Optional<NonTriviallyCopyable> z = y.copy(); // Have to copy explicitly
|
||||
EXPECT_EQ(z->x, "13");
|
||||
}
|
||||
|
||||
{
|
||||
NonTriviallyCopyable x {};
|
||||
Optional<NonTriviallyCopyable const&> y = x;
|
||||
Optional<NonTriviallyCopyable> z = Optional<NonTriviallyCopyable>(y); // Explicit copy constructor is still defined
|
||||
EXPECT_EQ(z->x, "13");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(string_specialization)
|
||||
{
|
||||
EXPECT_EQ(sizeof(Optional<String>), sizeof(String));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue