forked from OSchip/llvm-project
[libc++] Fix std::to_address(array).
There were basically two bugs here: When C++20 `to_address` is called on `int arr[10]`, then `const _Ptr&` becomes a reference to a const array, and then we dispatch to `__to_address<const int(&)[10]>`, which, oops, gives us a `const int*` result instead of an `int*` result. Solution: We need to provide the two standard-specified overloads of `std::to_address` in exactly the same way that we provide two overloads of `__to_address`. When `__to_address` is called on a pointer type, `__to_address(const _Ptr&)` is disabled so we successfully avoid trying to instantiate pointer_traits of that pointer type. But when it's called on an array type, it's not disabled for array types, so we go ahead and instantiate pointer_traits<int[10]>, which goes boom. Solution: We need to disable `__to_address(const _Ptr&)` for both pointer and array types. Also disable it for function types, so that they get the nice error message; and put a test on it. Differential Revision: https://reviews.llvm.org/D109331
This commit is contained in:
parent
84169fb67e
commit
dadbe88a13
|
@ -173,7 +173,9 @@ _Tp* __to_address(_Tp* __p) _NOEXCEPT {
|
|||
}
|
||||
|
||||
// enable_if is needed here to avoid instantiating checks for fancy pointers on raw pointers
|
||||
template <class _Pointer, class = _EnableIf<!is_pointer<_Pointer>::value> >
|
||||
template <class _Pointer, class = _EnableIf<
|
||||
!is_pointer<_Pointer>::value && !is_array<_Pointer>::value && !is_function<_Pointer>::value
|
||||
> >
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
typename decay<decltype(__to_address_helper<_Pointer>::__call(declval<const _Pointer&>()))>::type
|
||||
__to_address(const _Pointer& __p) _NOEXCEPT {
|
||||
|
@ -199,6 +201,12 @@ struct __to_address_helper<_Pointer, decltype((void)pointer_traits<_Pointer>::to
|
|||
};
|
||||
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY constexpr
|
||||
auto to_address(_Tp *__p) noexcept {
|
||||
return _VSTD::__to_address(__p);
|
||||
}
|
||||
|
||||
template <class _Pointer>
|
||||
inline _LIBCPP_INLINE_VISIBILITY constexpr
|
||||
auto to_address(const _Pointer& __p) noexcept {
|
||||
|
|
|
@ -137,6 +137,14 @@ TEST_CONSTEXPR_CXX14 bool test() {
|
|||
assert(std::__to_address(p8b) == p8_nil);
|
||||
ASSERT_SAME_TYPE(decltype(std::__to_address(p8b)), decltype(p8_nil));
|
||||
|
||||
int p9[2] = {};
|
||||
assert(std::__to_address(p9) == p9);
|
||||
ASSERT_SAME_TYPE(decltype(std::__to_address(p9)), int*);
|
||||
|
||||
const int p10[2] = {};
|
||||
assert(std::__to_address(p10) == p10);
|
||||
ASSERT_SAME_TYPE(decltype(std::__to_address(p10)), const int*);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <memory>
|
||||
|
||||
// template <class T> constexpr T* __to_address(T* p) noexcept;
|
||||
// Mandates: T is not a function type.
|
||||
|
||||
#include <memory>
|
||||
|
||||
int (*pf)();
|
||||
|
||||
void test() {
|
||||
(void)std::__to_address(pf); // expected-error@*:* {{is a function type}}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <memory>
|
||||
|
||||
// template <class T> constexpr T* __to_address(T* p) noexcept;
|
||||
// Mandates: T is not a function type.
|
||||
|
||||
#include <memory>
|
||||
|
||||
int f();
|
||||
|
||||
void test() {
|
||||
(void)std::__to_address(f); // expected-error@*:* {{is a function type}}
|
||||
}
|
|
@ -139,6 +139,18 @@ constexpr bool test() {
|
|||
assert(std::to_address(p8b) == p8_nil);
|
||||
ASSERT_SAME_TYPE(decltype(std::to_address(p8b)), decltype(p8_nil));
|
||||
|
||||
int p9[2] = {};
|
||||
assert(std::to_address(p9) == p9);
|
||||
ASSERT_SAME_TYPE(decltype(std::to_address(p9)), int*);
|
||||
|
||||
const int p10[2] = {};
|
||||
assert(std::to_address(p10) == p10);
|
||||
ASSERT_SAME_TYPE(decltype(std::to_address(p10)), const int*);
|
||||
|
||||
int (*p11)() = nullptr;
|
||||
assert(std::to_address(&p11) == &p11);
|
||||
ASSERT_SAME_TYPE(decltype(std::to_address(&p11)), int(**)());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <memory>
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
|
||||
// template <class T> constexpr T* to_address(T* p) noexcept;
|
||||
// Mandates: T is not a function type.
|
||||
|
||||
#include <memory>
|
||||
|
||||
int (*pf)();
|
||||
|
||||
void test() {
|
||||
(void)std::to_address(pf); // expected-error@*:* {{is a function type}}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <memory>
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
|
||||
// template <class T> constexpr T* to_address(T* p) noexcept;
|
||||
// Mandates: T is not a function type.
|
||||
|
||||
#include <memory>
|
||||
|
||||
int f();
|
||||
|
||||
void test() {
|
||||
(void)std::to_address(f); // expected-error@*:* {{is a function type}}
|
||||
}
|
Loading…
Reference in New Issue