Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[libc++] Introduce __is_pointer_in_range
This checks whether a pointer is within a range, even during constant evaluation. This allows running optimized code paths during constant evaluation, instead of falling back to the general-purpose implementation all the time. This is also a central place for comparing unrelated pointers, which is technically UB. Reviewed By: ldionne, #libc Spies: libcxx-commits Differential Revision: https://reviews.llvm.org/D143327
- Loading branch information
1 parent
5aea839
commit 7949ee0
Showing
7 changed files
with
149 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef _LIBCPP___UTILITY_IS_POINTER_IN_RANGE_H | ||
#define _LIBCPP___UTILITY_IS_POINTER_IN_RANGE_H | ||
|
||
#include <__algorithm/comp.h> | ||
#include <__assert> | ||
#include <__config> | ||
#include <__type_traits/enable_if.h> | ||
#include <__type_traits/integral_constant.h> | ||
#include <__type_traits/is_constant_evaluated.h> | ||
#include <__type_traits/is_function.h> | ||
#include <__type_traits/is_member_pointer.h> | ||
#include <__type_traits/void_t.h> | ||
#include <__utility/declval.h> | ||
|
||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | ||
# pragma GCC system_header | ||
#endif | ||
|
||
_LIBCPP_BEGIN_NAMESPACE_STD | ||
|
||
template <class _Tp, class _Up> | ||
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") bool __is_pointer_in_range( | ||
const _Tp* __begin, const _Tp* __end, const _Up* __ptr) { | ||
static_assert(!is_function<_Tp>::value && !is_function<_Up>::value, | ||
"__is_pointer_in_range should not be called with function pointers"); | ||
static_assert(!is_member_pointer<_Tp>::value && !is_member_pointer<_Up>::value, | ||
"__is_pointer_in_range should not be called with member pointers"); | ||
|
||
if (__libcpp_is_constant_evaluated()) { | ||
_LIBCPP_ASSERT(__builtin_constant_p(__begin <= __end), "__begin and __end do not form a range"); | ||
|
||
// If this is not a constant during constant evaluation we know that __ptr is not part of the allocation where | ||
// [__begin, __end) is. | ||
if (!__builtin_constant_p(__begin <= __ptr && __ptr < __end)) | ||
return false; | ||
} | ||
|
||
// Checking this for unrelated pointers is technically UB, but no compiler optimizes based on it (currently). | ||
return !__less<>()(__ptr, __begin) && __less<>()(__ptr, __end); | ||
} | ||
|
||
_LIBCPP_END_NAMESPACE_STD | ||
|
||
#endif // _LIBCPP___UTILITY_IS_POINTER_IN_RANGE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
// ADDITIONAL_COMPILE_FLAGS: -Wno-private-header | ||
|
||
#include <__utility/is_pointer_in_range.h> | ||
#include <cassert> | ||
|
||
#include "test_macros.h" | ||
|
||
template <class T, class U> | ||
TEST_CONSTEXPR_CXX14 void test_cv_quals() { | ||
T i = 0; | ||
U j = 0; | ||
assert(!std::__is_pointer_in_range(&i, &i, &i)); | ||
assert(std::__is_pointer_in_range(&i, &i + 1, &i)); | ||
assert(!std::__is_pointer_in_range(&i, &i + 1, &j)); | ||
|
||
#if TEST_STD_VER >= 20 | ||
{ | ||
T* arr1 = new int[4]{1, 2, 3, 4}; | ||
U* arr2 = new int[4]{5, 6, 7, 8}; | ||
|
||
assert(!std::__is_pointer_in_range(arr1, arr1 + 4, arr2)); | ||
assert(std::__is_pointer_in_range(arr1, arr1 + 4, arr1 + 3)); | ||
assert(!std::__is_pointer_in_range(arr1, arr1, arr1 + 3)); | ||
|
||
delete[] arr1; | ||
delete[] arr2; | ||
} | ||
#endif | ||
} | ||
|
||
TEST_CONSTEXPR_CXX14 bool test() { | ||
test_cv_quals<int, int>(); | ||
test_cv_quals<const int, int>(); | ||
test_cv_quals<int, const int>(); | ||
test_cv_quals<const int, const int>(); | ||
test_cv_quals<volatile int, int>(); | ||
test_cv_quals<int, volatile int>(); | ||
test_cv_quals<volatile int, volatile int>(); | ||
|
||
return true; | ||
} | ||
|
||
int main(int, char**) { | ||
test(); | ||
#if TEST_STD_VER >= 14 | ||
static_assert(test(), ""); | ||
#endif | ||
|
||
return 0; | ||
} |