Commit 485f2be7 by Martin Brænne Committed by Copybara-Service

Add nullability attributes to nullability type aliases.

This is a followup to the [previous
change](https://github.com/abseil/abseil-cpp/commit/69195d5bd2416a7224416887c78353ee8edf67ee)
that added the `ABSL_NULLABILITY_COMPATIBLE` attribute macro.

Adding these attributes has the following benefits:

- Clang itself can now diagnose certain nullability errors through the
  `-Wnonnull` and `-Wnullability` warnings.

- The nullability annotations can now also be used on pointers to incomplete
  types, as we have removed the `IsSupportedType` mechanism that used the
  `absl_nullability_compatible` tag to check whether a type is
  nullability-compatible (which only worked for complete types) and instead let
  Clang perform this check through the `ABSL_NULLABILITY_COMPATIBLE` attribute
  (which also works on incomplete types).

PiperOrigin-RevId: 684342145
Change-Id: I94c8affd5be704cb49340058ced177f09ebd83a3
parent 8634e35f
......@@ -26,80 +26,41 @@ namespace absl {
ABSL_NAMESPACE_BEGIN
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
// Don't add the _Nullable attribute in Objective-C compiles. Many Objective-C
// projects enable the `-Wnullable-to-nonnull-conversion warning`, which is
// liable to produce false positives.
#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
= T _Nullable;
#else
= T;
#endif
template <typename T, typename = typename EnableNonnull<T>::type>
template <typename T>
using NonnullImpl
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
[[clang::annotate("Nonnull")]]
#endif
#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
= T _Nonnull;
#else
= T;
#endif
template <typename T, typename = typename EnableNullabilityUnknown<T>::type>
template <typename T>
using NullabilityUnknownImpl
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
[[clang::annotate("Nullability_Unspecified")]]
#endif
#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
= T _Null_unspecified;
#else
= T;
#endif
} // namespace nullability_internal
ABSL_NAMESPACE_END
......
......@@ -135,17 +135,9 @@
// ...
// };
//
// Note: For the time being, nullability-compatible classes should additionally
// be marked with an `absl_nullability_compatible` nested type (this will soon
// be deprecated). The actual definition of this inner type is not relevant as
// it is used merely as a marker. It is common to use a using declaration of
// `absl_nullability_compatible` set to void.
//
// // Example:
// struct MyPtr {
// using absl_nullability_compatible = void;
// ...
// };
// Note: Compilers that don't support the `nullability_on_classes` feature will
// allow nullability annotations to be applied to any type, not just ones
// marked with `ABSL_NULLABILITY_COMPATIBLE`.
//
// DISCLAIMER:
// ===========================================================================
......@@ -279,6 +271,10 @@ ABSL_NAMESPACE_END
// struct ABSL_NULLABILITY_COMPATIBLE MyPtr {
// ...
// };
//
// Note: Compilers that don't support the `nullability_on_classes` feature will
// allow nullability annotations to be applied to any type, not just ones marked
// with `ABSL_NULLABILITY_COMPATIBLE`.
#if ABSL_HAVE_FEATURE(nullability_on_classes)
#define ABSL_NULLABILITY_COMPATIBLE _Nullable
#else
......
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