blob: 4adc2ebacd7e75ace877fdc6e7f948f0b574e0c7 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/memory/raw_ref.h"
#include <functional>
#include <type_traits>
#include "base/test/gtest_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
#include "base/memory/raw_ptr_asan_service.h"
#endif // BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
namespace {
class BaseClass {};
class SubClass : public BaseClass {};
// raw_ref just defers to the superclass for implementations, so it
// can't add more data types.
static_assert(sizeof(raw_ref<int>) == sizeof(raw_ptr<int>));
// Since it can't hold null, raw_ref is not default-constructible.
static_assert(!std::is_default_constructible_v<raw_ref<int>>);
static_assert(!std::is_default_constructible_v<raw_ref<const int>>);
// A mutable reference can only be constructed from a mutable lvalue reference.
static_assert(!std::is_constructible_v<raw_ref<int>, const int>);
static_assert(!std::is_constructible_v<raw_ref<int>, int>);
static_assert(!std::is_constructible_v<raw_ref<int>, const int&>);
static_assert(std::is_constructible_v<raw_ref<int>, int&>);
static_assert(!std::is_constructible_v<raw_ref<int>, const int*>);
static_assert(!std::is_constructible_v<raw_ref<int>, int*>);
static_assert(!std::is_constructible_v<raw_ref<int>, const int&&>);
static_assert(!std::is_constructible_v<raw_ref<int>, int&&>);
// Same for assignment.
static_assert(!std::is_assignable_v<raw_ref<int>, const int>);
static_assert(!std::is_assignable_v<raw_ref<int>, int>);
static_assert(!std::is_assignable_v<raw_ref<int>, const int&>);
static_assert(std::is_assignable_v<raw_ref<int>, int&>);
static_assert(!std::is_assignable_v<raw_ref<int>, const int*>);
static_assert(!std::is_assignable_v<raw_ref<int>, int*>);
static_assert(!std::is_assignable_v<raw_ref<int>, const int&&>);
static_assert(!std::is_assignable_v<raw_ref<int>, int&&>);
// A const reference can be constructed from a const or mutable lvalue
// reference.
static_assert(!std::is_constructible_v<raw_ref<const int>, const int>);
static_assert(!std::is_constructible_v<raw_ref<const int>, int>);
static_assert(std::is_constructible_v<raw_ref<const int>, const int&>);
static_assert(std::is_constructible_v<raw_ref<const int>, int&>);
static_assert(!std::is_constructible_v<raw_ref<const int>, const int*>);
static_assert(!std::is_constructible_v<raw_ref<const int>, int*>);
static_assert(!std::is_constructible_v<raw_ref<const int>, const int&&>);
static_assert(!std::is_constructible_v<raw_ref<const int>, int&&>);
// Same for assignment.
static_assert(!std::is_assignable_v<raw_ref<const int>, const int>);
static_assert(!std::is_assignable_v<raw_ref<const int>, int>);
static_assert(std::is_assignable_v<raw_ref<const int>, const int&>);
static_assert(std::is_assignable_v<raw_ref<const int>, int&>);
static_assert(!std::is_assignable_v<raw_ref<const int>, const int*>);
static_assert(!std::is_assignable_v<raw_ref<const int>, int*>);
static_assert(!std::is_assignable_v<raw_ref<const int>, const int&&>);
static_assert(!std::is_assignable_v<raw_ref<const int>, int&&>);
// Same trivial operations (or not) as raw_ptr<T>.
static_assert(std::is_trivially_constructible_v<raw_ref<int>, const int&> ==
std::is_trivially_constructible_v<raw_ptr<int>, const int&>);
static_assert(std::is_trivially_destructible_v<raw_ref<int>> ==
std::is_trivially_destructible_v<raw_ptr<int>>);
// But constructing from another raw_ref must check if it's internally null
// (which indicates use-after-move).
static_assert(!std::is_trivially_move_constructible_v<raw_ref<int>>);
static_assert(!std::is_trivially_move_assignable_v<raw_ref<int>>);
static_assert(!std::is_trivially_copy_constructible_v<raw_ref<int>>);
static_assert(!std::is_trivially_copy_assignable_v<raw_ref<int>>);
// A raw_ref can be copied or moved.
static_assert(std::is_move_constructible_v<raw_ref<int>>);
static_assert(std::is_copy_constructible_v<raw_ref<int>>);
static_assert(std::is_move_assignable_v<raw_ref<int>>);
static_assert(std::is_copy_assignable_v<raw_ref<int>>);
// A SubClass can be converted to a BaseClass.
static_assert(std::is_constructible_v<raw_ref<BaseClass>, raw_ref<SubClass>>);
static_assert(
std::is_constructible_v<raw_ref<BaseClass>, const raw_ref<SubClass>&>);
static_assert(std::is_constructible_v<raw_ref<BaseClass>, raw_ref<SubClass>&&>);
static_assert(std::is_assignable_v<raw_ref<BaseClass>, raw_ref<SubClass>>);
static_assert(
std::is_assignable_v<raw_ref<BaseClass>, const raw_ref<SubClass>&>);
static_assert(std::is_assignable_v<raw_ref<BaseClass>, raw_ref<SubClass>&&>);
// A BaseClass can't be implicitly downcasted.
static_assert(!std::is_constructible_v<raw_ref<SubClass>, raw_ref<BaseClass>>);
static_assert(
!std::is_constructible_v<raw_ref<SubClass>, const raw_ref<BaseClass>&>);
static_assert(
!std::is_constructible_v<raw_ref<SubClass>, raw_ref<BaseClass>&&>);
static_assert(!std::is_assignable_v<raw_ref<SubClass>, raw_ref<BaseClass>>);
static_assert(
!std::is_assignable_v<raw_ref<SubClass>, const raw_ref<BaseClass>&>);
static_assert(!std::is_assignable_v<raw_ref<SubClass>, raw_ref<BaseClass>&&>);
// A raw_ref<BaseClass> can be constructed directly from a SubClass.
static_assert(std::is_constructible_v<raw_ref<BaseClass>, SubClass&>);
static_assert(std::is_assignable_v<raw_ref<BaseClass>, SubClass&>);
static_assert(std::is_constructible_v<raw_ref<const BaseClass>, SubClass&>);
static_assert(std::is_assignable_v<raw_ref<const BaseClass>, SubClass&>);
static_assert(
std::is_constructible_v<raw_ref<const BaseClass>, const SubClass&>);
static_assert(std::is_assignable_v<raw_ref<const BaseClass>, const SubClass&>);
// But a raw_ref<SubClass> can't be constructed from an implicit downcast from a
// BaseClass.
static_assert(!std::is_constructible_v<raw_ref<SubClass>, BaseClass&>);
static_assert(!std::is_assignable_v<raw_ref<SubClass>, BaseClass&>);
static_assert(!std::is_constructible_v<raw_ref<const SubClass>, BaseClass&>);
static_assert(!std::is_assignable_v<raw_ref<const SubClass>, BaseClass&>);
static_assert(
!std::is_constructible_v<raw_ref<const SubClass>, const BaseClass&>);
static_assert(!std::is_assignable_v<raw_ref<const SubClass>, const BaseClass&>);
// A mutable reference can be converted to const reference.
static_assert(std::is_constructible_v<raw_ref<const int>, raw_ref<int>>);
static_assert(std::is_assignable_v<raw_ref<const int>, raw_ref<int>>);
// A const reference can't be converted to mutable.
static_assert(!std::is_constructible_v<raw_ref<int>, raw_ref<const int>>);
static_assert(!std::is_assignable_v<raw_ref<int>, raw_ref<const int>>);
// The deref operator gives the internal reference.
static_assert(std::is_same_v<int&, decltype(*std::declval<raw_ref<int>>())>);
static_assert(
std::is_same_v<int&, decltype(*std::declval<const raw_ref<int>>())>);
static_assert(std::is_same_v<int&, decltype(*std::declval<raw_ref<int>&>())>);
static_assert(
std::is_same_v<int&, decltype(*std::declval<const raw_ref<int>&>())>);
static_assert(std::is_same_v<int&, decltype(*std::declval<raw_ref<int>&&>())>);
static_assert(
std::is_same_v<int&, decltype(*std::declval<const raw_ref<int>&&>())>);
// A const T is always returned as const.
static_assert(
std::is_same_v<const int&, decltype(*std::declval<raw_ref<const int>>())>);
// The arrow operator gives a (non-null) pointer to the internal reference.
static_assert(
std::is_same_v<int*, decltype(std::declval<raw_ref<int>>().operator->())>);
static_assert(
std::is_same_v<const int*,
decltype(std::declval<raw_ref<const int>>().operator->())>);
TEST(RawRef, Construct) {
int i = 1;
auto r = raw_ref<int>(i);
EXPECT_EQ(&*r, &i);
auto cr = raw_ref<const int>(i);
EXPECT_EQ(&*cr, &i);
const int ci = 1;
auto cci = raw_ref<const int>(ci);
EXPECT_EQ(&*cci, &ci);
}
TEST(RawRef, CopyConstruct) {
{
int i = 1;
auto r = raw_ref<int>(i);
EXPECT_EQ(&*r, &i);
auto r2 = raw_ref<int>(r);
EXPECT_EQ(&*r2, &i);
}
{
int i = 1;
auto r = raw_ref<const int>(i);
EXPECT_EQ(&*r, &i);
auto r2 = raw_ref<const int>(r);
EXPECT_EQ(&*r2, &i);
}
}
TEST(RawRefDeathTest, CopyConstructAfterMove) {
int i = 1;
auto r = raw_ref<int>(i);
auto r2 = std::move(r);
EXPECT_CHECK_DEATH({ [[maybe_unused]] auto r3 = r; });
}
TEST(RawRef, MoveConstruct) {
{
int i = 1;
auto r = raw_ref<int>(i);
EXPECT_EQ(&*r, &i);
auto r2 = raw_ref<int>(std::move(r));
EXPECT_EQ(&*r2, &i);
}
{
int i = 1;
auto r = raw_ref<const int>(i);
EXPECT_EQ(&*r, &i);
auto r2 = raw_ref<const int>(std::move(r));
EXPECT_EQ(&*r2, &i);
}
}
TEST(RawRefDeathTest, MoveConstructAfterMove) {
int i = 1;
auto r = raw_ref<int>(i);
auto r2 = std::move(r);
EXPECT_CHECK_DEATH({ [[maybe_unused]] auto r3 = std::move(r); });
}
TEST(RawRef, CopyAssign) {
{
int i = 1;
auto r = raw_ref<int>(i);
EXPECT_EQ(&*r, &i);
int j = 2;
auto rj = raw_ref<int>(j);
r = rj;
EXPECT_EQ(&*r, &j);
}
{
int i = 1;
auto r = raw_ref<const int>(i);
EXPECT_EQ(&*r, &i);
int j = 2;
auto rj = raw_ref<const int>(j);
r = rj;
EXPECT_EQ(&*r, &j);
}
{
int i = 1;
auto r = raw_ref<const int>(i);
EXPECT_EQ(&*r, &i);
int j = 2;
auto rj = raw_ref<int>(j);
r = rj;
EXPECT_EQ(&*r, &j);
}
}
TEST(RawRefDeathTest, CopyAssignAfterMove) {
int i = 1;
auto r = raw_ref<int>(i);
auto r2 = std::move(r);
EXPECT_CHECK_DEATH({ r2 = r; });
}
TEST(RawRef, CopyReassignAfterMove) {
int i = 1;
auto r = raw_ref<int>(i);
auto r2 = std::move(r);
int j = 1;
r2 = raw_ref<int>(j);
// Reassign to the moved-from `r` so it can be used again.
r = r2;
EXPECT_EQ(&*r, &j);
}
TEST(RawRef, MoveAssign) {
{
int i = 1;
auto r = raw_ref<int>(i);
EXPECT_EQ(&*r, &i);
int j = 2;
r = raw_ref<int>(j);
EXPECT_EQ(&*r, &j);
}
{
int i = 1;
auto r = raw_ref<const int>(i);
EXPECT_EQ(&*r, &i);
int j = 2;
r = raw_ref<const int>(j);
EXPECT_EQ(&*r, &j);
}
{
int i = 1;
auto r = raw_ref<const int>(i);
EXPECT_EQ(&*r, &i);
int j = 2;
r = raw_ref<int>(j);
EXPECT_EQ(&*r, &j);
}
}
TEST(RawRefDeathTest, MoveAssignAfterMove) {
int i = 1;
auto r = raw_ref<int>(i);
auto r2 = std::move(r);
EXPECT_CHECK_DEATH({ r2 = std::move(r); });
}
TEST(RawRef, MoveReassignAfterMove) {
int i = 1;
auto r = raw_ref<int>(i);
auto r2 = std::move(r);
int j = 1;
// Reassign to the moved-from `r` so it can be used again.
r = raw_ref<int>(j);
EXPECT_EQ(&*r, &j);
}
TEST(RawRef, CopyConstructUpCast) {
{
auto s = SubClass();
auto r = raw_ref<SubClass>(s);
EXPECT_EQ(&*r, &s);
auto r2 = raw_ref<BaseClass>(r);
EXPECT_EQ(&*r2, &s);
}
{
auto s = SubClass();
auto r = raw_ref<const SubClass>(s);
EXPECT_EQ(&*r, &s);
auto r2 = raw_ref<const BaseClass>(r);
EXPECT_EQ(&*r2, &s);
}
}
TEST(RawRefDeathTest, CopyConstructAfterMoveUpCast) {
auto s = SubClass();
auto r = raw_ref<SubClass>(s);
auto moved = std::move(r);
EXPECT_CHECK_DEATH({ [[maybe_unused]] auto r2 = raw_ref<BaseClass>(r); });
}
TEST(RawRef, MoveConstructUpCast) {
{
auto s = SubClass();
auto r = raw_ref<SubClass>(s);
EXPECT_EQ(&*r, &s);
auto r2 = raw_ref<BaseClass>(std::move(r));
EXPECT_EQ(&*r2, &s);
}
{
auto s = SubClass();
auto r = raw_ref<const SubClass>(s);
EXPECT_EQ(&*r, &s);
auto r2 = raw_ref<const BaseClass>(std::move(r));
EXPECT_EQ(&*r2, &s);
}
}
TEST(RawRefDeathTest, MoveConstructAfterMoveUpCast) {
auto s = SubClass();
auto r = raw_ref<SubClass>(s);
auto moved = std::move(r);
EXPECT_CHECK_DEATH(
{ [[maybe_unused]] auto r2 = raw_ref<BaseClass>(std::move(r)); });
}
TEST(RawRef, FromPtr) {
int i = 42;
auto ref = raw_ref<int>::from_ptr(&i);
EXPECT_EQ(&i, &*ref);
}
TEST(RawRefDeathTest, FromPtrWithNullptr) {
EXPECT_CHECK_DEATH({ raw_ref<int>::from_ptr(nullptr); });
}
TEST(RawRef, CopyAssignUpCast) {
{
auto s = SubClass();
auto r = raw_ref<SubClass>(s);
auto t = BaseClass();
auto rt = raw_ref<BaseClass>(t);
rt = r;
EXPECT_EQ(&*rt, &s);
}
{
auto s = SubClass();
auto r = raw_ref<const SubClass>(s);
auto t = BaseClass();
auto rt = raw_ref<const BaseClass>(t);
rt = r;
EXPECT_EQ(&*rt, &s);
}
{
auto s = SubClass();
auto r = raw_ref<SubClass>(s);
auto t = BaseClass();
auto rt = raw_ref<const BaseClass>(t);
rt = r;
EXPECT_EQ(&*rt, &s);
}
}
TEST(RawRefDeathTest, CopyAssignAfterMoveUpCast) {
auto s = SubClass();
auto r = raw_ref<const SubClass>(s);
auto t = BaseClass();
auto rt = raw_ref<const BaseClass>(t);
auto moved = std::move(r);
EXPECT_CHECK_DEATH({ rt = r; });
}
TEST(RawRef, MoveAssignUpCast) {
{
auto s = SubClass();
auto r = raw_ref<SubClass>(s);
auto t = BaseClass();
auto rt = raw_ref<BaseClass>(t);
rt = std::move(r);
EXPECT_EQ(&*rt, &s);
}
{
auto s = SubClass();
auto r = raw_ref<const SubClass>(s);
auto t = BaseClass();
auto rt = raw_ref<const BaseClass>(t);
rt = std::move(r);
EXPECT_EQ(&*rt, &s);
}
{
auto s = SubClass();
auto r = raw_ref<SubClass>(s);
auto t = BaseClass();
auto rt = raw_ref<const BaseClass>(t);
rt = std::move(r);
EXPECT_EQ(&*rt, &s);
}
}
TEST(RawRefDeathTest, MoveAssignAfterMoveUpCast) {
auto s = SubClass();
auto r = raw_ref<const SubClass>(s);
auto t = BaseClass();
auto rt = raw_ref<const BaseClass>(t);
auto moved = std::move(r);
EXPECT_CHECK_DEATH({ rt = std::move(r); });
}
TEST(RawRef, Deref) {
int i;
auto r = raw_ref<int>(i);
EXPECT_EQ(&*r, &i);
}
TEST(RawRefDeathTest, DerefAfterMove) {
int i;
auto r = raw_ref<int>(i);
auto moved = std::move(r);
EXPECT_CHECK_DEATH({ r.operator*(); });
}
TEST(RawRef, Arrow) {
int i;
auto r = raw_ref<int>(i);
EXPECT_EQ(r.operator->(), &i);
}
TEST(RawRefDeathTest, ArrowAfterMove) {
int i;
auto r = raw_ref<int>(i);
auto moved = std::move(r);
EXPECT_CHECK_DEATH({ r.operator->(); });
}
TEST(RawRef, Swap) {
int i;
auto ri = raw_ref<int>(i);
int j;
auto rj = raw_ref<int>(j);
swap(ri, rj);
EXPECT_EQ(&*ri, &j);
EXPECT_EQ(&*rj, &i);
}
TEST(RawRefDeathTest, SwapAfterMove) {
{
int i;
auto ri = raw_ref<int>(i);
int j;
auto rj = raw_ref<int>(j);
auto moved = std::move(ri);
EXPECT_CHECK_DEATH({ swap(ri, rj); });
}
{
int i;
auto ri = raw_ref<int>(i);
int j;
auto rj = raw_ref<int>(j);
auto moved = std::move(rj);
EXPECT_CHECK_DEATH({ swap(ri, rj); });
}
}
TEST(RawRef, Equals) {
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
EXPECT_TRUE(r1 == r1);
EXPECT_TRUE(r1 == r2);
EXPECT_TRUE(r1 == i);
EXPECT_TRUE(i == r1);
int j = 1;
auto r3 = raw_ref<int>(j);
EXPECT_FALSE(r1 == r3);
EXPECT_FALSE(r1 == j);
EXPECT_FALSE(j == r1);
}
TEST(RawRefDeathTest, EqualsAfterMove) {
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 == r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r2);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 == r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 == r1; });
}
}
TEST(RawRef, NotEquals) {
int i = 1;
auto r1 = raw_ref<int>(i);
int j = 1;
auto r2 = raw_ref<int>(j);
EXPECT_TRUE(r1 != r2);
EXPECT_TRUE(r1 != j);
EXPECT_TRUE(j != r1);
EXPECT_FALSE(r1 != r1);
EXPECT_FALSE(r2 != j);
EXPECT_FALSE(j != r2);
}
TEST(RawRefDeathTest, NotEqualsAfterMove) {
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 != r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r2);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 != r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 != r1; });
}
}
TEST(RawRef, LessThan) {
int i[] = {1, 1};
auto r1 = raw_ref<int>(i[0]);
auto r2 = raw_ref<int>(i[1]);
EXPECT_TRUE(r1 < r2);
EXPECT_TRUE(r1 < i[1]);
EXPECT_FALSE(i[1] < r1);
EXPECT_FALSE(r2 < r1);
EXPECT_FALSE(r2 < i[0]);
EXPECT_TRUE(i[0] < r2);
EXPECT_FALSE(r1 < r1);
EXPECT_FALSE(r1 < i[0]);
EXPECT_FALSE(i[0] < r1);
}
TEST(RawRefDeathTest, LessThanAfterMove) {
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 < r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r2);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 < r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 < r1; });
}
}
TEST(RawRef, GreaterThan) {
int i[] = {1, 1};
auto r1 = raw_ref<int>(i[0]);
auto r2 = raw_ref<int>(i[1]);
EXPECT_TRUE(r2 > r1);
EXPECT_FALSE(r1 > r2);
EXPECT_FALSE(r1 > i[1]);
EXPECT_TRUE(i[1] > r1);
EXPECT_FALSE(r2 > r2);
EXPECT_FALSE(r2 > i[1]);
EXPECT_FALSE(i[1] > r2);
}
TEST(RawRefDeathTest, GreaterThanAfterMove) {
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 > r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r2);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 > r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 > r1; });
}
}
TEST(RawRef, LessThanOrEqual) {
int i[] = {1, 1};
auto r1 = raw_ref<int>(i[0]);
auto r2 = raw_ref<int>(i[1]);
EXPECT_TRUE(r1 <= r2);
EXPECT_TRUE(r1 <= r1);
EXPECT_TRUE(r2 <= r2);
EXPECT_FALSE(r2 <= r1);
EXPECT_TRUE(r1 <= i[1]);
EXPECT_TRUE(r1 <= i[0]);
EXPECT_TRUE(r2 <= i[1]);
EXPECT_FALSE(r2 <= i[0]);
EXPECT_FALSE(i[1] <= r1);
EXPECT_TRUE(i[0] <= r1);
EXPECT_TRUE(i[1] <= r2);
EXPECT_TRUE(i[0] <= r2);
}
TEST(RawRefDeathTest, LessThanOrEqualAfterMove) {
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 <= r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r2);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 <= r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 <= r1; });
}
}
TEST(RawRef, GreaterThanOrEqual) {
int i[] = {1, 1};
auto r1 = raw_ref<int>(i[0]);
auto r2 = raw_ref<int>(i[1]);
EXPECT_TRUE(r2 >= r1);
EXPECT_TRUE(r1 >= r1);
EXPECT_TRUE(r2 >= r2);
EXPECT_FALSE(r1 >= r2);
EXPECT_TRUE(r2 >= i[0]);
EXPECT_TRUE(r1 >= i[0]);
EXPECT_TRUE(r2 >= i[1]);
EXPECT_FALSE(r1 >= i[1]);
EXPECT_FALSE(i[0] >= r2);
EXPECT_TRUE(i[0] >= r1);
EXPECT_TRUE(i[1] >= r2);
EXPECT_TRUE(i[1] >= r1);
}
TEST(RawRefDeathTest, GreaterThanOrEqualAfterMove) {
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 >= r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto r2 = raw_ref<int>(i);
auto moved = std::move(r2);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 >= r2; });
}
{
int i = 1;
auto r1 = raw_ref<int>(i);
auto moved = std::move(r1);
EXPECT_CHECK_DEATH({ [[maybe_unused]] bool b = r1 >= r1; });
}
}
TEST(RawRef, CTAD) {
int i = 1;
auto r = raw_ref(i);
EXPECT_EQ(&*r, &i);
}
using RawPtrCountingImpl =
base::internal::RawPtrCountingImplWrapperForTest<base::DefaultRawPtrType>;
template <typename T>
using CountingRawRef = raw_ref<T, RawPtrCountingImpl>;
TEST(RawRef, StdLess) {
int i[] = {1, 1};
{
RawPtrCountingImpl::ClearCounters();
auto r1 = CountingRawRef<int>(i[0]);
auto r2 = CountingRawRef<int>(i[1]);
EXPECT_TRUE(std::less<CountingRawRef<int>>()(r1, r2));
EXPECT_FALSE(std::less<CountingRawRef<int>>()(r2, r1));
EXPECT_EQ(2, RawPtrCountingImpl::wrapped_ptr_less_cnt);
}
{
RawPtrCountingImpl::ClearCounters();
const auto r1 = CountingRawRef<int>(i[0]);
const auto r2 = CountingRawRef<int>(i[1]);
EXPECT_TRUE(std::less<CountingRawRef<int>>()(r1, r2));
EXPECT_FALSE(std::less<CountingRawRef<int>>()(r2, r1));
EXPECT_EQ(2, RawPtrCountingImpl::wrapped_ptr_less_cnt);
}
{
RawPtrCountingImpl::ClearCounters();
auto r1 = CountingRawRef<const int>(i[0]);
auto r2 = CountingRawRef<const int>(i[1]);
EXPECT_TRUE(std::less<CountingRawRef<const int>>()(r1, r2));
EXPECT_FALSE(std::less<CountingRawRef<const int>>()(r2, r1));
EXPECT_EQ(2, RawPtrCountingImpl::wrapped_ptr_less_cnt);
}
{
RawPtrCountingImpl::ClearCounters();
auto r1 = CountingRawRef<int>(i[0]);
auto r2 = CountingRawRef<int>(i[1]);
EXPECT_TRUE(std::less<CountingRawRef<int>>()(r1, i[1]));
EXPECT_FALSE(std::less<CountingRawRef<int>>()(r2, i[0]));
EXPECT_EQ(2, RawPtrCountingImpl::wrapped_ptr_less_cnt);
}
{
RawPtrCountingImpl::ClearCounters();
const auto r1 = CountingRawRef<int>(i[0]);
const auto r2 = CountingRawRef<int>(i[1]);
EXPECT_TRUE(std::less<CountingRawRef<int>>()(r1, i[1]));
EXPECT_FALSE(std::less<CountingRawRef<int>>()(r2, i[0]));
EXPECT_EQ(2, RawPtrCountingImpl::wrapped_ptr_less_cnt);
}
{
RawPtrCountingImpl::ClearCounters();
auto r1 = CountingRawRef<const int>(i[0]);
auto r2 = CountingRawRef<const int>(i[1]);
EXPECT_TRUE(std::less<CountingRawRef<const int>>()(r1, i[1]));
EXPECT_FALSE(std::less<CountingRawRef<const int>>()(r2, i[0]));
EXPECT_EQ(2, RawPtrCountingImpl::wrapped_ptr_less_cnt);
}
}
#if BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
TEST(AsanBackupRefPtrImpl, RawRefGet) {
if (!base::RawPtrAsanService::GetInstance().IsEnabled()) {
base::RawPtrAsanService::GetInstance().Configure(
base::EnableDereferenceCheck(true), base::EnableExtractionCheck(true),
base::EnableInstantiationCheck(true));
} else {
ASSERT_TRUE(
base::RawPtrAsanService::GetInstance().is_dereference_check_enabled());
ASSERT_TRUE(
base::RawPtrAsanService::GetInstance().is_extraction_check_enabled());
ASSERT_TRUE(base::RawPtrAsanService::GetInstance()
.is_instantiation_check_enabled());
}
auto ptr = ::std::make_unique<int>();
raw_ref<int> safe_ref(*ptr);
ptr.reset();
// This test is specifically to ensure that raw_ref.get() does not cause a
// dereference of the memory referred to by the reference. If there is a
// dereference, then this test will crash.
[[maybe_unused]] volatile int& ref = safe_ref.get();
}
#endif // BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
} // namespace