crashpad/util/misc/from_pointer_cast.h
Mark Mentovai fbc365fa9e GCC 7.2 support (-Wnoexcept-type)
P0012R1, accepted into C++17, makes a function’s “noexcept” (or
“throw()”) specification part of its signature. GCC 7.2 provides a
warning, -Wnoexcept-type, that is triggered when a function pointer type
with an exception specification is used in pre-C++17 code in such a way
as to pose an ABI incompatibility with C++17 code.

https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/C_002b_002b-Dialect-Options.html#index-Wnoexcept-type

Warnings are of the form:

In file included from ../../util/misc/from_pointer_cast_test.cc:15:0:
../../util/misc/from_pointer_cast.h:64:1: error: mangled name for ‘typename std::enable_if<(std::is_pointer<From>::value && std::is_pointer<_Tp>::value), To>::type crashpad::FromPointerCast(From) [with To = const volatile void*; From = void* (*)(long unsigned int) throw ()]’ will change in C++17 because the exception specification is part of a function type [-Werror=noexcept-type]
 FromPointerCast(From from) {
 ^~~~~~~~~~~~~~~
../../util/misc/from_pointer_cast.h:64:1: error: mangled name for ‘typename std::enable_if<(std::is_pointer<From>::value && std::is_pointer<_Tp>::value), To>::type crashpad::FromPointerCast(From) [with To = volatile void*; From = void* (*)(long unsigned int) throw ()]’ will change in C++17 because the exception specification is part of a function type [-Werror=noexcept-type]

In Crashpad, this warning is triggered by the two FromPointerCast<>()
variants that accept function pointer “From” arguments. This occurs when
using glibc as the standard C library, since glibc declares its
functions as “throw()”. FromPointerCast<>() is used with pointers to
glibc functions such as malloc() and getpid().

The warning is disabled for the FromPointerCast<>() variants that would
trigger it. The warning is not useful or actionable in this internal
Crashpad code where ABI changes due to language version (including
mangling changes) are not a concern.

Clang 4.0 has the similar -Wc++1z-compat-mangling option (also available
as -Wc++17-compat-mangling and the GCC-compatible -Wnoexcept-type in
Clang 5.0) but it is not triggered by this pattern.

Change-Id: Id293db3954be415f67a55476ca72bfb7d399aa3b
Reviewed-on: https://chromium-review.googlesource.com/738292
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
Commit-Queue: Mark Mentovai <mark@chromium.org>
2017-10-25 18:29:58 +00:00

116 lines
4.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// 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
//
// http://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 CRASHPAD_UTIL_MISC_FROM_POINTER_CAST_H_
#define CRASHPAD_UTIL_MISC_FROM_POINTER_CAST_H_
#include <stdint.h>
#include <cstddef>
#include <type_traits>
#include "base/numerics/safe_conversions.h"
#include "build/build_config.h"
namespace crashpad {
#if DOXYGEN
//! \brief Casts from a pointer type to an integer.
//!
//! Compared to `reinterpret_cast<>()`, FromPointerCast<>() defines whether a
//! pointer type is sign-extended or zero-extended. Casts to signed integral
//! types are sign-extended. Casts to unsigned integral types are zero-extended.
//!
//! Use FromPointerCast<>() instead of `reinterpret_cast<>()` when casting a
//! pointer to an integral type that may not be the same width as a pointer.
//! There is no need to prefer FromPointerCast<>() when casting to an integral
//! type thats definitely the same width as a pointer, such as `uintptr_t` and
//! `intptr_t`.
template <typename To, typename From>
FromPointerCast(From from) {
return reinterpret_cast<To>(from);
}
#else // DOXYGEN
// Cast std::nullptr_t to any type.
//
// In C++14, the nullptr_t check could use std::is_null_pointer<From>::value
// instead of the is_same<remove_cv<From>::type, nullptr_t>::type construct.
template <typename To, typename From>
typename std::enable_if<
std::is_same<typename std::remove_cv<From>::type, std::nullptr_t>::value,
To>::type
FromPointerCast(From) {
return To();
}
// FromPointerCast<>() with a function pointer “From” type raises
// -Wnoexcept-type in GCC 7.2 if the function pointer type has a throw() or
// noexcept specification. This is the case for all standard C library functions
// provided by glibc. Various tests make use of FromPointerCast<>() with
// pointers to standard C library functions.
//
// Clang has the similar -Wc++1z-compat-mangling, which is not triggered by this
// pattern.
#if defined(COMPILER_GCC) && !defined(__clang__) && \
(__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnoexcept-type"
#endif
// Cast a pointer to any other pointer type.
template <typename To, typename From>
typename std::enable_if<std::is_pointer<From>::value &&
std::is_pointer<To>::value,
To>::type
FromPointerCast(From from) {
return reinterpret_cast<To>(from);
}
// Cast a pointer to an integral type. Sign-extend when casting to a signed
// type, zero-extend when casting to an unsigned type.
template <typename To, typename From>
typename std::enable_if<std::is_pointer<From>::value &&
std::is_integral<To>::value,
To>::type
FromPointerCast(From from) {
const auto intermediate =
reinterpret_cast<typename std::conditional<std::is_signed<To>::value,
intptr_t,
uintptr_t>::type>(from);
if (sizeof(To) >= sizeof(From)) {
// If the destination integral type is at least as wide as the source
// pointer type, use static_cast<>() and just return it.
return static_cast<To>(intermediate);
}
// If the destination integral type is narrower than the source pointer type,
// use checked_cast<>().
return base::checked_cast<To>(intermediate);
}
#if defined(COMPILER_GCC) && !defined(__clang__) && \
(__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2))
#pragma GCC diagnostic pop
#endif
#endif // DOXYGEN
} // namespace crashpad
#endif // CRASHPAD_UTIL_MISC_FROM_POINTER_CAST_H_