1// Copyright 2023 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
16#define ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
17
18#include <memory>
19#include <type_traits>
20
21#include "absl/base/attributes.h"
22#include "absl/meta/type_traits.h"
23
24namespace absl {
25
26namespace nullability_internal {
27
28// `IsNullabilityCompatible` checks whether its first argument is a class
29// explicitly tagged as supporting nullability annotations. The tag is the type
30// declaration `absl_nullability_compatible`.
31template <typename, typename = void>
32struct IsNullabilityCompatible : std::false_type {};
33
34template <typename T>
35struct IsNullabilityCompatible<
36 T, absl::void_t<typename T::absl_nullability_compatible>> : std::true_type {
37};
38
39template <typename T>
40constexpr bool IsSupportedType = IsNullabilityCompatible<T>::value;
41
42template <typename T>
43constexpr bool IsSupportedType<T*> = true;
44
45template <typename T, typename U>
46constexpr bool IsSupportedType<T U::*> = true;
47
48template <typename T, typename... Deleter>
49constexpr bool IsSupportedType<std::unique_ptr<T, Deleter...>> = true;
50
51template <typename T>
52constexpr bool IsSupportedType<std::shared_ptr<T>> = true;
53
54template <typename T>
55struct EnableNullable {
56 static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
57 "Template argument must be a raw or supported smart pointer "
58 "type. See absl/base/nullability.h.");
59 using type = T;
60};
61
62template <typename T>
63struct EnableNonnull {
64 static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
65 "Template argument must be a raw or supported smart pointer "
66 "type. See absl/base/nullability.h.");
67 using type = T;
68};
69
70template <typename T>
71struct EnableNullabilityUnknown {
72 static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
73 "Template argument must be a raw or supported smart pointer "
74 "type. See absl/base/nullability.h.");
75 using type = T;
76};
77
78// Note: we do not apply Clang nullability attributes (e.g. _Nullable). These
79// only support raw pointers, and conditionally enabling them only for raw
80// pointers inhibits template arg deduction. Ideally, they would support all
81// pointer-like types.
82template <typename T, typename = typename EnableNullable<T>::type>
83using NullableImpl
84#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
85 [[clang::annotate("Nullable")]]
86#endif
87 = T;
88
89template <typename T, typename = typename EnableNonnull<T>::type>
90using NonnullImpl
91#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
92 [[clang::annotate("Nonnull")]]
93#endif
94 = T;
95
96template <typename T, typename = typename EnableNullabilityUnknown<T>::type>
97using NullabilityUnknownImpl
98#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
99 [[clang::annotate("Nullability_Unspecified")]]
100#endif
101 = T;
102
103} // namespace nullability_internal
104} // namespace absl
105
106#endif // ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
107