910e62b5创建于 1月15日历史提交
// 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.

#ifndef BASE_FUNCTIONAL_UNRETAINED_TRAITS_H_
#define BASE_FUNCTIONAL_UNRETAINED_TRAITS_H_

#include <type_traits>

#include "base/types/is_complete.h"
#include "base/types/same_as_any.h"
#include "build/build_config.h"

// Various opaque system types that should still be usable with the base
// callback system. Please keep sorted.
#define BASE_INTERNAL_LIST_OF_SAFE_FOR_UNRETAINED                      \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(ANativeWindow)                     \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(DBusMessage)                       \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(HWND__)                            \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(VkBuffer_T)                        \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(VkDeviceMemory_T)                  \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(VkImage_T)                         \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(VkSemaphore_T)                     \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(VmaAllocation_T)                   \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(WGPUAdapterImpl)                   \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_action_t__)                   \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_annotation_t__)               \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_attachment_t__)               \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_bookmark_t__)                 \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_document_t__)                 \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_form_handle_t__)              \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_page_t__)                     \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_structelement_t__)            \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_structelement_attr_t__)       \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_structelement_attr_value_t__) \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(hb_set_t)                          \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(wl_gpu)                            \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(wl_shm)                            \
  BASE_INTERNAL_SAFE_FOR_UNRETAINED(wl_surface)

#define BASE_INTERNAL_SAFE_FOR_UNRETAINED(x) struct x;
BASE_INTERNAL_LIST_OF_SAFE_FOR_UNRETAINED
#undef BASE_INTERNAL_SAFE_FOR_UNRETAINED

namespace base::internal {

// Determining whether a type can be used with `Unretained()` requires that `T`
// be completely defined. Some system types have an intentionally opaque and
// incomplete representation, but should still be usable with `Unretained()`.
template <typename T>
concept SafeIncompleteTypeForUnretained =
    SameAsAny<std::remove_cvref_t<T>,
#define BASE_INTERNAL_SAFE_FOR_UNRETAINED(x) x,
              BASE_INTERNAL_LIST_OF_SAFE_FOR_UNRETAINED
#undef BASE_INTERNAL_SAFE_FOR_UNRETAINED
              // void* is occasionally used with callbacks; in the future,
              // this may be more restricted/limited, but allow it for now.
              void>;

// Customization point. Specialize this to be `false` for types as needed. In
// general, you should not need this; types that do not support `Unretained()`
// should use `DISALLOW_UNRETAINED()`. However, this is necessary when
// disallowing `Unretained()` for types that do not (or cannot) use //base.
template <typename T>
inline constexpr bool kCustomizeSupportsUnretained = true;

template <typename T>
concept DisallowsUnretained = !kCustomizeSupportsUnretained<T> || requires {
  // Matches against the marker tag created by the `DISALLOW_UNRETAINED()` macro
  // in //base/functional/disallow_unretained.h.
  typename T::DisallowBaseUnretainedMarker;
};

template <typename T>
struct SupportsUnretainedImpl {
  // For context on this "templated struct with a lambda that asserts" pattern,
  // see comments in `Invoker<>`.
  template <bool v = IsComplete<T> || SafeIncompleteTypeForUnretained<T>>
  struct AllowlistIncompleteTypes {
    static constexpr bool value = [] {
// Incrementally enforce the requirement to be completely defined. For now,
// limit the failures to:
//
// - non-test code
// - non-official code (because these builds don't run as part of the default CQ
//   and are slower due to PGO and LTO)
// - Android, Linux or Windows
//
// to make this easier to land without potentially breaking the tree.
//
// TODO(crbug.com/40247956): Enable this on all platforms, then in
// official builds, and then in non-test code as well.
#if defined(FORCE_UNRETAINED_COMPLETENESS_CHECKS_FOR_TESTS) || \
    (!defined(UNIT_TEST) && !defined(OFFICIAL_BUILD) &&        \
     (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)))
      static_assert(v,
                    "Argument requires unretained storage, but type is not "
                    "fully defined. This prevents determining whether "
                    "`Unretained()` is supported.");
      return v;
#else
      return true;
#endif
    }();
  };

  template <bool v = !DisallowsUnretained<T>>
  struct AllowsUnretained {
    static constexpr bool value = [] {
      static_assert(v,
                    "Argument requires unretained storage, but type does not "
                    "support `Unretained()`. See "
                    "base/functional/disallow_unretained.h for alternatives.");
      return v;
    }();
  };

  static constexpr bool value =
      std::conjunction_v<AllowlistIncompleteTypes<>, AllowsUnretained<>>;
};

// Not meant for general use: merely checking this concept will
// `static_assert()` if the type does not support unretained. This is meant only
// for use inside the `Bind()` machinery, which wants that assertion.
//
// If we ever want to use this concept outside that machinery, we'll need to not
// only move the "allows unretained" assertion from above to the `Bind()` side,
// we'll also need to hoist or duplicate the incomplete type check there (and
// not assert in that case) so it does not fire multiple `static_assert()`s for
// incomplete types.
template <typename T>
concept SupportsUnretained = SupportsUnretainedImpl<T>::value;

}  // namespace base::internal

#endif  // BASE_FUNCTIONAL_UNRETAINED_TRAITS_H_