from_pointer_cast.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright 2017 The Crashpad Authors. All rights reserved.
  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. // http://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. #ifndef CRASHPAD_UTIL_MISC_FROM_POINTER_CAST_H_
  15. #define CRASHPAD_UTIL_MISC_FROM_POINTER_CAST_H_
  16. #include <stdint.h>
  17. #include <cstddef>
  18. #include <type_traits>
  19. #include "base/numerics/safe_conversions.h"
  20. #include "build/build_config.h"
  21. namespace crashpad {
  22. #if DOXYGEN
  23. //! \brief Casts from a pointer type to an integer.
  24. //!
  25. //! Compared to `reinterpret_cast<>()`, FromPointerCast<>() defines whether a
  26. //! pointer type is sign-extended or zero-extended. Casts to signed integral
  27. //! types are sign-extended. Casts to unsigned integral types are zero-extended.
  28. //!
  29. //! Use FromPointerCast<>() instead of `reinterpret_cast<>()` when casting a
  30. //! pointer to an integral type that may not be the same width as a pointer.
  31. //! There is no need to prefer FromPointerCast<>() when casting to an integral
  32. //! type that’s definitely the same width as a pointer, such as `uintptr_t` and
  33. //! `intptr_t`.
  34. template <typename To, typename From>
  35. FromPointerCast(From from) {
  36. return reinterpret_cast<To>(from);
  37. }
  38. #else // DOXYGEN
  39. // Cast std::nullptr_t to any type.
  40. //
  41. // In C++14, the nullptr_t check could use std::is_null_pointer<From>::value
  42. // instead of the is_same<remove_cv<From>::type, nullptr_t>::type construct.
  43. template <typename To, typename From>
  44. typename std::enable_if<
  45. std::is_same<typename std::remove_cv<From>::type, std::nullptr_t>::value,
  46. To>::type
  47. FromPointerCast(From) {
  48. return To();
  49. }
  50. // FromPointerCast<>() with a function pointer “From” type raises
  51. // -Wnoexcept-type in GCC 7.2 if the function pointer type has a throw() or
  52. // noexcept specification. This is the case for all standard C library functions
  53. // provided by glibc. Various tests make use of FromPointerCast<>() with
  54. // pointers to standard C library functions.
  55. //
  56. // Clang has the similar -Wc++1z-compat-mangling, which is not triggered by this
  57. // pattern.
  58. #if defined(COMPILER_GCC) && !defined(__clang__) && \
  59. (__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2))
  60. #pragma GCC diagnostic push
  61. #pragma GCC diagnostic ignored "-Wnoexcept-type"
  62. #endif
  63. // Cast a pointer to any other pointer type.
  64. template <typename To, typename From>
  65. typename std::enable_if<std::is_pointer<From>::value &&
  66. std::is_pointer<To>::value,
  67. To>::type
  68. FromPointerCast(From from) {
  69. return reinterpret_cast<To>(from);
  70. }
  71. // Cast a pointer to an integral type. Sign-extend when casting to a signed
  72. // type, zero-extend when casting to an unsigned type.
  73. template <typename To, typename From>
  74. typename std::enable_if<std::is_pointer<From>::value &&
  75. std::is_integral<To>::value,
  76. To>::type
  77. FromPointerCast(From from) {
  78. const auto intermediate =
  79. reinterpret_cast<typename std::conditional<std::is_signed<To>::value,
  80. intptr_t,
  81. uintptr_t>::type>(from);
  82. if (sizeof(To) >= sizeof(From)) {
  83. // If the destination integral type is at least as wide as the source
  84. // pointer type, use static_cast<>() and just return it.
  85. return static_cast<To>(intermediate);
  86. }
  87. // If the destination integral type is narrower than the source pointer type,
  88. // use checked_cast<>().
  89. return base::checked_cast<To>(intermediate);
  90. }
  91. #if defined(COMPILER_GCC) && !defined(__clang__) && \
  92. (__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2))
  93. #pragma GCC diagnostic pop
  94. #endif
  95. #endif // DOXYGEN
  96. } // namespace crashpad
  97. #endif // CRASHPAD_UTIL_MISC_FROM_POINTER_CAST_H_