[llvm-branch-commits] [libcxx] 9f9ea70 - [libc++] No longer support ranges::begin(x) when x is an array of incomplete type.
Arthur O'Dwyer via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Feb 4 13:13:17 PST 2022
Author: Arthur O'Dwyer
Date: 2022-02-04T16:12:35-05:00
New Revision: 9f9ea707d0c6f2839a52a7045a35ea3356d851be
URL: https://github.com/llvm/llvm-project/commit/9f9ea707d0c6f2839a52a7045a35ea3356d851be
DIFF: https://github.com/llvm/llvm-project/commit/9f9ea707d0c6f2839a52a7045a35ea3356d851be.diff
LOG: [libc++] No longer support ranges::begin(x) when x is an array of incomplete type.
var-const points out that `ranges::begin` is (non-normatively
but explicitly) always supposed to return a `std::input_or_output_iterator`,
and `Incomplete*` is not a `std::input_or_output_iterator` because it
has no `operator++`. Therefore, we should never return `Incomplete*`
from `ranges::begin(x)`, even when `x` is `Incomplete(&)[]`. Instead,
just SFINAE away.
Differential Revision: https://reviews.llvm.org/D118963
(cherry picked from commit cc1d02ba2d177e0d31561934337f5412167f6954)
Added:
Modified:
libcxx/include/__ranges/access.h
libcxx/test/std/ranges/range.access/begin.pass.cpp
Removed:
libcxx/test/libcxx/ranges/range.access/begin.incomplete_type.sh.cpp
################################################################################
diff --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h
index 67c6c57bd81e4..07a92d7834755 100644
--- a/libcxx/include/__ranges/access.h
+++ b/libcxx/include/__ranges/access.h
@@ -59,10 +59,17 @@ namespace __begin {
struct __fn {
template <class _Tp>
- requires is_array_v<remove_cv_t<_Tp>>
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp& __t) const noexcept
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[]) const noexcept
+ requires (sizeof(_Tp) != 0) // Disallow incomplete element types.
{
- return __t;
+ return __t + 0;
+ }
+
+ template <class _Tp, size_t _Np>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept
+ requires (sizeof(_Tp) != 0) // Disallow incomplete element types.
+ {
+ return __t + 0;
}
template <class _Tp>
@@ -127,7 +134,7 @@ namespace __end {
public:
template <class _Tp, size_t _Np>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept
- requires (sizeof(*__t) != 0) // Disallow incomplete element types.
+ requires (sizeof(_Tp) != 0) // Disallow incomplete element types.
{
return __t + _Np;
}
diff --git a/libcxx/test/libcxx/ranges/range.access/begin.incomplete_type.sh.cpp b/libcxx/test/libcxx/ranges/range.access/begin.incomplete_type.sh.cpp
deleted file mode 100644
index cc27789c04f3d..0000000000000
--- a/libcxx/test/libcxx/ranges/range.access/begin.incomplete_type.sh.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// RUN: %{cxx} %{flags} %{compile_flags} -c %s -o %t.tu1.o -DTU1
-// RUN: %{cxx} %{flags} %{compile_flags} -c %s -o %t.tu2.o -DTU2
-// RUN: %{cxx} %t.tu1.o %t.tu2.o %{flags} %{link_flags} -o %t.exe
-// RUN: %{exec} %t.exe
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-// UNSUPPORTED: libcpp-no-concepts
-// UNSUPPORTED: libcpp-has-no-incomplete-ranges
-
-// Test the libc++-specific behavior that we handle the IFNDR case for ranges::begin
-// by returning the beginning of the array-of-incomplete-type.
-// Use two translation units so that `Incomplete` really is never completed
-// at any point within TU2, but the array `bounded` is still given a definition
-// (in TU1) to avoid an "undefined reference" error from the linker.
-// All of the actually interesting stuff takes place within TU2.
-
-#include <ranges>
-#include <cassert>
-
-#include "test_macros.h"
-
-#if defined(TU1)
-
-struct Incomplete {};
-Incomplete bounded[10];
-Incomplete unbounded[10];
-
-#else // defined(TU1)
-
-struct Incomplete;
-
-constexpr bool test()
-{
- {
- extern Incomplete bounded[10];
- assert(std::ranges::begin(bounded) == bounded);
- assert(std::ranges::cbegin(bounded) == bounded);
- assert(std::ranges::begin(std::as_const(bounded)) == bounded);
- assert(std::ranges::cbegin(std::as_const(bounded)) == bounded);
- ASSERT_SAME_TYPE(decltype(std::ranges::begin(bounded)), Incomplete*);
- ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(bounded)), const Incomplete*);
- ASSERT_SAME_TYPE(decltype(std::ranges::begin(std::as_const(bounded))), const Incomplete*);
- ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(std::as_const(bounded))), const Incomplete*);
- }
- {
- extern Incomplete unbounded[];
- assert(std::ranges::begin(unbounded) == unbounded);
- assert(std::ranges::cbegin(unbounded) == unbounded);
- assert(std::ranges::begin(std::as_const(unbounded)) == unbounded);
- assert(std::ranges::cbegin(std::as_const(unbounded)) == unbounded);
- ASSERT_SAME_TYPE(decltype(std::ranges::begin(unbounded)), Incomplete*);
- ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(unbounded)), const Incomplete*);
- ASSERT_SAME_TYPE(decltype(std::ranges::begin(std::as_const(unbounded))), const Incomplete*);
- ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(std::as_const(unbounded))), const Incomplete*);
- }
-
- return true;
-}
-
-int main(int, char**)
-{
- test();
- static_assert(test());
- return 0;
-}
-
-#endif // defined(TU1)
diff --git a/libcxx/test/std/ranges/range.access/begin.pass.cpp b/libcxx/test/std/ranges/range.access/begin.pass.cpp
index 07b1a3b89a7f1..7014681ccabf9 100644
--- a/libcxx/test/std/ranges/range.access/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/begin.pass.cpp
@@ -31,9 +31,26 @@ static_assert( std::is_invocable_v<RangeBeginT, int (&)[]>);
struct Incomplete;
static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[]>);
-static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[42]>);
+static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[]>);
static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[]>);
-static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[42]>);
+static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[]>);
+
+static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[10]>);
+static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[10]>);
+static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[10]>);
+
+// This case is IFNDR; we handle it SFINAE-friendly.
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[]>);
+
+// This case is IFNDR; we handle it SFINAE-friendly.
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[10]>);
+LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[10]>);
struct BeginMember {
int x;
More information about the llvm-branch-commits
mailing list