blob: 9f2d79e27122f1bdb8dab3558f31809dea2d0d11 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This is a "No Compile Test" suite.
// http://dev.chromium.org/developers/testing/no-compile-tests
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "partition_alloc/pointers/raw_ptr.h"
#include "partition_alloc/partition_alloc_buildflags.h"
namespace {
// Using distinct enum types causes distinct `raw_ptr` template instantiations,
// so we get assertion failures below where we expect.
enum TypeA {};
enum TypeB {};
void UnknownTraits() {
constexpr auto InvalidRawPtrTrait = static_cast<base::RawPtrTraits>(-1);
raw_ptr<TypeA, InvalidRawPtrTrait> ptr_a; // expected-error@*:* {{Unknown raw_ptr trait(s)}}
raw_ptr<TypeB, DisableDanglingPtrDetection | InvalidRawPtrTrait> ptr_b; // expected-error@*:* {{Unknown raw_ptr trait(s)}}
}
void DifferentTypeAssignment() {
struct Unrelated {};
struct Producer {} p;
struct DerivedProducer : public Producer {} dp;
raw_ptr<Producer> ptr_p = &p;
raw_ptr<DerivedProducer> ptr_dp1 = &dp;
// Conversion
raw_ptr<DerivedProducer> ptr_dp2 = ptr_p; // expected-error {{no viable conversion from 'raw_ptr<Producer>' to 'raw_ptr<DerivedProducer>'}}
raw_ptr<DerivedProducer> ptr_dp3 =
static_cast<raw_ptr<DerivedProducer>>(ptr_p); // expected-error {{no matching conversion for static_cast from 'raw_ptr<Producer>' to 'raw_ptr<DerivedProducer>'}}
raw_ptr<DerivedProducer> ptr_dp4 = &p; // expected-error {{no viable conversion from 'struct Producer *' to 'raw_ptr<DerivedProducer>'}}
raw_ptr<Unrelated> ptr_u1 = &dp; // expected-error {{no viable conversion from 'struct DerivedProducer *' to 'raw_ptr<Unrelated>'}}
// Reference binding
raw_ptr<DerivedProducer>& ptr_dp5 = ptr_p; // expected-error {{non-const lvalue reference to type 'raw_ptr<DerivedProducer>' cannot bind to a value of unrelated type 'raw_ptr<Producer>'}}
raw_ptr<DerivedProducer>& ptr_dp6 =
static_cast<raw_ptr<DerivedProducer>&>(ptr_p); // expected-error {{non-const lvalue reference to type 'raw_ptr<DerivedProducer>' cannot bind to a value of unrelated type 'raw_ptr<Producer>'}}
// Casting
auto* ptr_u2 = static_cast<Unrelated*>(ptr_dp1); // expected-error@*:* {{static_cast from 'DerivedProducer *' to 'Unrelated *', which are not related by inheritance, is not allowed}}
}
void DereferenceVoidPtr() {
constexpr char kFoo[] = "42";
raw_ptr<const void> ptr = kFoo;
*ptr; // expected-error {{indirection requires pointer operand ('raw_ptr<const void>' invalid)}}
}
void FunctionPointerType() {
raw_ptr<void(int)> ptr; // expected-error@*:* {{raw_ptr<T> doesn't work with this kind of pointee type T}}
}
void Dangling() {
[[maybe_unused]] raw_ptr<int> ptr = std::make_unique<int>(2).get(); // expected-error {{object backing the pointer will be destroyed at the end of the full-expression}}
}
void BindRawPtrParam() {
// `raw_ptr` is not intended to be used as a function param type, so trying to
// bind to a function with a `raw_ptr<T>` param should error out.
raw_ptr<int> ptr = new int(3);
base::BindOnce([](raw_ptr<int> ptr) {}, ptr); // expected-error@*:* {{base::Bind() target functor has a parameter of type raw_ptr<T>.}}
}
void PointerArithmetic() {
using PtrCanDoArithmetic =
raw_ptr<int, base::RawPtrTraits::kAllowPtrArithmetic>;
PtrCanDoArithmetic ptr1 = new int(3);
struct {} s;
ptr1 += s; // expected-error@*:* {{no viable overloaded '+='}}
ptr1 -= s; // expected-error@*:* {{no viable overloaded '-='}}
PtrCanDoArithmetic ptr2 = ptr1 + s; // expected-error@*:* {{no viable overloaded '+='}}
ptr2 = ptr1 - s; // expected-error@*:* {{no viable overloaded '-='}}
#if !BUILDFLAG(HAS_64_BIT_POINTERS)
ptr1 += uint64_t{2}; // expected-error@*:* {{no viable overloaded '+='}}
ptr1 -= uint64_t{2}; // expected-error@*:* {{no viable overloaded '-='}}
ptr2 = ptr1 + uint64_t{2}; // expected-error@*:* {{no viable overloaded '+='}}
ptr2 = ptr1 - uint64_t{2}; // expected-error@*:* {{no viable overloaded '-='}}
#endif // !BUILDFLAG(HAS_64_BIT_POINTERS)
}
#if BUILDFLAG(ENABLE_POINTER_ARITHMETIC_TRAIT_CHECK)
void PointerArithmeticDisabled() {
raw_ptr<TypeA> ptr_a1 = new TypeA();
ptr_a1++; // expected-error@*:* {{cannot increment raw_ptr unless AllowPtrArithmetic trait is present.}}
ptr_a1--; // expected-error@*:* {{cannot decrement raw_ptr unless AllowPtrArithmetic trait is present.}}
++ptr_a1; // expected-error@*:* {{cannot increment raw_ptr unless AllowPtrArithmetic trait is present.}}
--ptr_a1; // expected-error@*:* {{cannot decrement raw_ptr unless AllowPtrArithmetic trait is present.}}
raw_ptr<TypeA> ptr_a2 = ptr_a1 + 1; // expected-error@*:* {{cannot increment raw_ptr unless AllowPtrArithmetic trait is present.}}
ptr_a2 = ptr_a1 - 1; // expected-error@*:* {{cannot decrement raw_ptr unless AllowPtrArithmetic trait is present.}}
raw_ptr<TypeB> ptr_b1 = new TypeB();
raw_ptr<TypeB> ptr_b2 = 1 + ptr_b1; // expected-error@*:* {{cannot increment raw_ptr unless AllowPtrArithmetic trait is present.}}
}
void Indexing() {
raw_ptr<int> ptr = new int(3);
[[maybe_unused]] int val = ptr[1]; // expected-error@*:* {{cannot index raw_ptr unless AllowPtrArithmetic trait is present.}}
}
#endif
using DanglingPtrA = raw_ptr<TypeA, base::RawPtrTraits::kMayDangle>;
using DanglingPtrB = raw_ptr<TypeB, base::RawPtrTraits::kMayDangle>;
void CrossKindConversionFromMayDangle() {
// Conversions may add the `kMayDangle` trait, but not remove it.
DanglingPtrA ptr_a1 = new TypeA();
DanglingPtrB ptr_b1 = new TypeB();
raw_ptr<TypeA> ptr_a2 = ptr_a1; // expected-error {{no viable conversion from 'raw_ptr<[...], base::RawPtrTraits::kMayDangle aka 1>' to 'raw_ptr<[...], (default) RawPtrTraits::kEmpty aka 0>'}}
raw_ptr<TypeA> ptr_a3(ptr_a1); // expected-error@*:* {{static assertion failed due to requirement 'Traits == (raw_ptr<(anonymous namespace)::TypeA, partition_alloc::internal::RawPtrTraits::kMayDangle>::Traits | RawPtrTraits::kMayDangle)'}}
raw_ptr<TypeA> ptr_a4 = std::move(ptr_a1); // expected-error {{no viable conversion from '__libcpp_remove_reference_t<raw_ptr<TypeA, partition_alloc::internal::RawPtrTraits::kMayDangle> &>' (aka 'base::raw_ptr<(anonymous namespace)::TypeA, partition_alloc::internal::RawPtrTraits::kMayDangle>') to 'raw_ptr<TypeA>'}}
raw_ptr<TypeB> ptr_b2(std::move(ptr_b1)); // expected-error@*:* {{static assertion failed due to requirement 'Traits == (raw_ptr<(anonymous namespace)::TypeB, partition_alloc::internal::RawPtrTraits::kMayDangle>::Traits | RawPtrTraits::kMayDangle)'}}
}
void CrossKindConversionFromDummy() {
// Only the `kMayDangle` trait can change in an implicit conversion.
raw_ptr<TypeA, base::RawPtrTraits::kDummyForTest> ptr_a1 = new TypeA();
raw_ptr<TypeB, base::RawPtrTraits::kDummyForTest> ptr_b1 = new TypeB();
DanglingPtrA ptr_a2 = ptr_a1; // expected-error {{no viable conversion from 'raw_ptr<[...], base::RawPtrTraits::kDummyForTest aka 2048>' to 'raw_ptr<[...], base::RawPtrTraits::kMayDangle aka 1>'}}
DanglingPtrA ptr_a3(ptr_a1); // expected-error@*:* {{static assertion failed due to requirement 'Traits == (raw_ptr<(anonymous namespace)::TypeA, partition_alloc::internal::RawPtrTraits::kDummyForTest>::Traits | RawPtrTraits::kMayDangle)'}}
DanglingPtrA ptr_a4 = std::move(ptr_a1); // expected-error {{no viable conversion from '__libcpp_remove_reference_t<raw_ptr<TypeA, partition_alloc::internal::RawPtrTraits::kDummyForTest> &>' (aka 'base::raw_ptr<(anonymous namespace)::TypeA, partition_alloc::internal::RawPtrTraits::kDummyForTest>') to 'DanglingPtrA' (aka 'raw_ptr<TypeA, base::RawPtrTraits::kMayDangle>')}}
DanglingPtrB ptr_b2(std::move(ptr_b1)); // expected-error@*:* {{static assertion failed due to requirement 'Traits == (raw_ptr<(anonymous namespace)::TypeB, partition_alloc::internal::RawPtrTraits::kDummyForTest>::Traits | RawPtrTraits::kMayDangle)'}}
}
} // namespace