Commit 5668c20e by Abseil Team Committed by Copybara-Service

Add Nullability annotations to Abseil.

PiperOrigin-RevId: 541915097
Change-Id: I7ebfbafc36db38b59b30ab5b312cd7e22082a805
parent 76548f86
...@@ -26,6 +26,7 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -26,6 +26,7 @@ set(ABSL_INTERNAL_DLL_FILES
"base/internal/low_level_alloc.cc" "base/internal/low_level_alloc.cc"
"base/internal/low_level_alloc.h" "base/internal/low_level_alloc.h"
"base/internal/low_level_scheduling.h" "base/internal/low_level_scheduling.h"
"base/internal/nullability_impl.h"
"base/internal/per_thread_tls.h" "base/internal/per_thread_tls.h"
"base/internal/prefetch.h" "base/internal/prefetch.h"
"base/prefetch.h" "base/prefetch.h"
...@@ -56,6 +57,7 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -56,6 +57,7 @@ set(ABSL_INTERNAL_DLL_FILES
"base/log_severity.cc" "base/log_severity.cc"
"base/log_severity.h" "base/log_severity.h"
"base/macros.h" "base/macros.h"
"base/nullability.h"
"base/optimization.h" "base/optimization.h"
"base/options.h" "base/options.h"
"base/policy_checks.h" "base/policy_checks.h"
......
...@@ -63,6 +63,18 @@ cc_library( ...@@ -63,6 +63,18 @@ cc_library(
) )
cc_library( cc_library(
name = "nullability",
srcs = ["internal/nullability_impl.h"],
hdrs = ["nullability.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":core_headers",
"//absl/meta:type_traits",
],
)
cc_library(
name = "raw_logging_internal", name = "raw_logging_internal",
srcs = ["internal/raw_logging.cc"], srcs = ["internal/raw_logging.cc"],
hdrs = ["internal/raw_logging.h"], hdrs = ["internal/raw_logging.h"],
...@@ -553,6 +565,16 @@ cc_test( ...@@ -553,6 +565,16 @@ cc_test(
) )
cc_test( cc_test(
name = "nullability_test",
srcs = ["nullability_test.cc"],
deps = [
":core_headers",
":nullability",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "raw_logging_test", name = "raw_logging_test",
srcs = ["raw_logging_test.cc"], srcs = ["raw_logging_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
......
...@@ -54,6 +54,33 @@ absl_cc_library( ...@@ -54,6 +54,33 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
) )
absl_cc_library(
NAME
nullability
HDRS
"nullability.h"
SRCS
"internal/nullability_impl.h"
DEPS
absl::core_headers
absl::type_traits
COPTS
${ABSL_DEFAULT_COPTS}
)
absl_cc_test(
NAME
nullability_test
SRCS
"nullability_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::core_headers
absl::nullability
GTest::gtest_main
)
# Internal-only target, do not depend on directly. # Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
......
// Copyright 2023 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
#define ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
#include <memory>
#include <type_traits>
#include "absl/base/attributes.h"
#include "absl/meta/type_traits.h"
namespace absl {
namespace nullability_internal {
// `IsNullabilityCompatible` checks whether its first argument is a class
// explicitly tagged as supporting nullability annotations. The tag is the type
// declaration `absl_nullability_compatible`.
template <typename, typename = void>
struct IsNullabilityCompatible : std::false_type {};
template <typename T>
struct IsNullabilityCompatible<
T, absl::void_t<typename T::absl_nullability_compatible>> : std::true_type {
};
template <typename T>
constexpr bool IsSupportedType = IsNullabilityCompatible<T>::value;
template <typename T>
constexpr bool IsSupportedType<T*> = true;
template <typename T, typename U>
constexpr bool IsSupportedType<T U::*> = true;
template <typename T, typename... Deleter>
constexpr bool IsSupportedType<std::unique_ptr<T, Deleter...>> = true;
template <typename T>
constexpr bool IsSupportedType<std::shared_ptr<T>> = true;
template <typename T>
struct EnableNullable {
static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
"Template argument must be a raw or supported smart pointer "
"type. See absl/base/nullability.h.");
using type = T;
};
template <typename T>
struct EnableNonNull {
static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
"Template argument must be a raw or supported smart pointer "
"type. See absl/base/nullability.h.");
using type = T;
};
template <typename T>
struct EnableNullabilityUnknown {
static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
"Template argument must be a raw or supported smart pointer "
"type. See absl/base/nullability.h.");
using type = T;
};
// Note: we do not apply Clang nullability attributes (e.g. _Nullable). These
// only support raw pointers, and conditionally enabling them only for raw
// pointers inhibits template arg deduction. Ideally, they would support all
// pointer-like types.
template <typename T, typename = typename EnableNullable<T>::type>
using NullableImpl
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
[[clang::annotate("Nullable")]]
#endif
= T;
template <typename T, typename = typename EnableNonNull<T>::type>
using NonNullImpl
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
[[clang::annotate("Nonnull")]]
#endif
= T;
template <typename T, typename = typename EnableNullabilityUnknown<T>::type>
using NullabilityUnknownImpl
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
[[clang::annotate("Nullability_Unspecified")]]
#endif
= T;
} // namespace nullability_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
// Copyright 2023 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/base/nullability.h"
#include <cassert>
#include <memory>
#include <utility>
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
namespace {
using ::absl::NonNull;
using ::absl::NullabilityUnknown;
using ::absl::Nullable;
void funcWithNonnullArg(NonNull<int*> /*arg*/) {}
template <typename T>
void funcWithDeducedNonnullArg(NonNull<T*> /*arg*/) {}
TEST(NonNullTest, NonNullArgument) {
int var = 0;
funcWithNonnullArg(&var);
funcWithDeducedNonnullArg(&var);
}
NonNull<int*> funcWithNonnullReturn() {
static int var = 0;
return &var;
}
TEST(NonNullTest, NonNullReturn) {
auto var = funcWithNonnullReturn();
(void)var;
}
TEST(PassThroughTest, PassesThroughRawPointerToInt) {
EXPECT_TRUE((std::is_same<NonNull<int*>, int*>::value));
EXPECT_TRUE((std::is_same<Nullable<int*>, int*>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<int*>, int*>::value));
}
TEST(PassThroughTest, PassesThroughRawPointerToVoid) {
EXPECT_TRUE((std::is_same<NonNull<void*>, void*>::value));
EXPECT_TRUE((std::is_same<Nullable<void*>, void*>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<void*>, void*>::value));
}
TEST(PassThroughTest, PassesThroughUniquePointerToInt) {
using T = std::unique_ptr<int>;
EXPECT_TRUE((std::is_same<NonNull<T>, T>::value));
EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
}
TEST(PassThroughTest, PassesThroughSharedPointerToInt) {
using T = std::shared_ptr<int>;
EXPECT_TRUE((std::is_same<NonNull<T>, T>::value));
EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
}
TEST(PassThroughTest, PassesThroughSharedPointerToVoid) {
using T = std::shared_ptr<void>;
EXPECT_TRUE((std::is_same<NonNull<T>, T>::value));
EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
}
TEST(PassThroughTest, PassesThroughPointerToMemberObject) {
using T = decltype(&std::pair<int, int>::first);
EXPECT_TRUE((std::is_same<NonNull<T>, T>::value));
EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
}
TEST(PassThroughTest, PassesThroughPointerToMemberFunction) {
using T = decltype(&std::unique_ptr<int>::reset);
EXPECT_TRUE((std::is_same<NonNull<T>, T>::value));
EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
}
} // namespace
// Nullable ADL lookup test
namespace util {
// Helper for NullableAdlTest. Returns true, denoting that argument-dependent
// lookup found this implementation of DidAdlWin. Must be in namespace
// util itself, not a nested anonymous namespace.
template <typename T>
bool DidAdlWin(T*) {
return true;
}
// Because this type is defined in namespace util, an unqualified call to
// DidAdlWin with a pointer to MakeAdlWin will find the above implementation.
struct MakeAdlWin {};
} // namespace util
namespace {
// Returns false, denoting that ADL did not inspect namespace util. If it
// had, the better match (T*) above would have won out over the (...) here.
bool DidAdlWin(...) { return false; }
TEST(NullableAdlTest, NullableAddsNothingToArgumentDependentLookup) {
// Treatment: util::Nullable<int*> contributes nothing to ADL because
// int* itself doesn't.
EXPECT_FALSE(DidAdlWin((int*)nullptr));
EXPECT_FALSE(DidAdlWin((Nullable<int*>)nullptr));
// Control: Argument-dependent lookup does find the implementation in
// namespace util when the underlying pointee type resides there.
EXPECT_TRUE(DidAdlWin((util::MakeAdlWin*)nullptr));
EXPECT_TRUE(DidAdlWin((Nullable<util::MakeAdlWin*>)nullptr));
}
} // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment