Skip to content

[libc++] Disallow character types being index types of extents #105832

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 27, 2024

Conversation

frederick-vs-ja
Copy link
Contributor

@frederick-vs-ja frederick-vs-ja commented Aug 23, 2024

#78086 provided the IMO exact approach - __libcpp_integer - for this. Fixes #73715.

In some libcxx/containers/views/mdspan tests, improper uses of char are replaced with signed char.

@frederick-vs-ja frederick-vs-ja requested a review from a team as a code owner August 23, 2024 13:45
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Aug 23, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 23, 2024

@llvm/pr-subscribers-libcxx

Author: A. Jiang (frederick-vs-ja)

Changes

#78086 provided the IMO exact approach - __libcpp_integer - for this. Fixes #73715.


Full diff: https://github.com/llvm/llvm-project/pull/105832.diff

2 Files Affected:

  • (modified) libcxx/include/__mdspan/extents.h (+2-2)
  • (added) libcxx/test/std/containers/views/mdspan/extents/index_type.verify.cpp (+51)
diff --git a/libcxx/include/__mdspan/extents.h b/libcxx/include/__mdspan/extents.h
index 95082ef3d11ac9..54577f2c581dff 100644
--- a/libcxx/include/__mdspan/extents.h
+++ b/libcxx/include/__mdspan/extents.h
@@ -19,6 +19,7 @@
 
 #include <__assert>
 #include <__config>
+#include <__concepts/arithmetic.h>
 #include <__type_traits/common_type.h>
 #include <__type_traits/is_convertible.h>
 #include <__type_traits/is_nothrow_constructible.h>
@@ -282,8 +283,7 @@ class extents {
   using size_type  = make_unsigned_t<index_type>;
   using rank_type  = size_t;
 
-  static_assert(is_integral<index_type>::value && !is_same<index_type, bool>::value,
-                "extents::index_type must be a signed or unsigned integer type");
+  static_assert(__libcpp_integer<index_type>, "extents::index_type must be a signed or unsigned integer type");
   static_assert(((__mdspan_detail::__is_representable_as<index_type>(_Extents) || (_Extents == dynamic_extent)) && ...),
                 "extents ctor: arguments must be representable as index_type and nonnegative");
 
diff --git a/libcxx/test/std/containers/views/mdspan/extents/index_type.verify.cpp b/libcxx/test/std/containers/views/mdspan/extents/index_type.verify.cpp
new file mode 100644
index 00000000000000..ef28c456925df8
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/extents/index_type.verify.cpp
@@ -0,0 +1,51 @@
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class IndexType, size_t... Extents>
+//  class extents;
+//
+// Mandates:
+//   - IndexType is a signed or unsigned integer type, and
+//   - each element of Extents is either equal to dynamic_extent, or is representable as a value of type IndexType.
+
+#include <cstddef>
+#include <climits>
+#include <mdspan>
+
+void invalid_index_types() {
+  // expected-error-re@*:* {{static assertion failed {{.*}}extents::index_type must be a signed or unsigned integer type}}
+  [[maybe_unused]] std::extents<bool, true> eb;
+  // expected-error-re@*:* {{static assertion failed {{.*}}extents::index_type must be a signed or unsigned integer type}}
+  [[maybe_unused]] std::extents<char, '*'> ec;
+#ifndef TEST_HAS_NO_CHAR8_T
+  // expected-error-re@*:* {{static assertion failed {{.*}}extents::index_type must be a signed or unsigned integer type}}
+  [[maybe_unused]] std::extents<char8_t, u8'*'> ec8;
+#endif
+  // expected-error-re@*:* {{static assertion failed {{.*}}extents::index_type must be a signed or unsigned integer type}}
+  [[maybe_unused]] std::extents<char16_t, u'*'> ec16;
+  // expected-error-re@*:* {{static assertion failed {{.*}}extents::index_type must be a signed or unsigned integer type}}
+  [[maybe_unused]] std::extents<char32_t, U'*'> ec32;
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  // expected-error-re@*:* {{static assertion failed {{.*}}extents::index_type must be a signed or unsigned integer type}}
+  [[maybe_unused]] std::extents<wchar_t, L'*'> ewc;
+#endif
+}
+
+void invalid_extent_values() {
+  // expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
+  [[maybe_unused]] std::extents<signed char, static_cast<std::size_t>(SCHAR_MAX) + 1> esc1;
+  // expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
+  [[maybe_unused]] std::extents<signed char, std::dynamic_extent - 1> esc2;
+  // expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
+  [[maybe_unused]] std::extents<unsigned char, static_cast<std::size_t>(UCHAR_MAX) + 1> euc1;
+  // expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
+  [[maybe_unused]] std::extents<unsigned char, std::dynamic_extent - 1> euc2;
+}

Copy link

github-actions bot commented Aug 23, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@frederick-vs-ja

This comment was marked as resolved.

@crtrott
Copy link
Contributor

crtrott commented Aug 23, 2024

Sorry I lost track of this. Its fine i don't need to do the work if soneone else takes the initiative ;-). I can review though.

PR 78086 (bddd8f4) provided the IMO
exact approach - `__libcpp_integer` - for this.
Copy link
Contributor

@crtrott crtrott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine too me, I do not understand why on some builds the verification test fails. The expected and observed message seem to me to match, and this seems to look like what we did in other places?


void invalid_index_types() {
// expected-error-re@*:* {{static assertion failed {{.*}}extents::index_type must be a signed or unsigned integer type}}
[[maybe_unused]] std::extents<char, '*'> ec;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd just add the appropriate -Wno-whatever flag to avoid the [[maybe_unused]]. They are quite noisy IMO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd still like to see this addressed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I might have merged a bit too hastily. @frederick-vs-ja do you think you can make a follow-up PR?

Comment on lines +41 to +48
// expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
[[maybe_unused]] std::extents<signed char, static_cast<std::size_t>(SCHAR_MAX) + 1> esc1;
// expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
[[maybe_unused]] std::extents<signed char, std::dynamic_extent - 1> esc2;
// expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
[[maybe_unused]] std::extents<unsigned char, static_cast<std::size_t>(UCHAR_MAX) + 1> euc1;
// expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
[[maybe_unused]] std::extents<unsigned char, std::dynamic_extent - 1> euc2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
[[maybe_unused]] std::extents<signed char, static_cast<std::size_t>(SCHAR_MAX) + 1> esc1;
// expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
[[maybe_unused]] std::extents<signed char, std::dynamic_extent - 1> esc2;
// expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
[[maybe_unused]] std::extents<unsigned char, static_cast<std::size_t>(UCHAR_MAX) + 1> euc1;
// expected-error-re@*:* {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
[[maybe_unused]] std::extents<unsigned char, std::dynamic_extent - 1> euc2;
// expected-error-re@*:* 4 {{static assertion failed {{.*}}extents ctor: arguments must be representable as index_type and nonnegative}}
[[maybe_unused]] std::extents<signed char, static_cast<std::size_t>(SCHAR_MAX) + 1> esc1;
[[maybe_unused]] std::extents<signed char, std::dynamic_extent - 1> esc2;
[[maybe_unused]] std::extents<unsigned char, static_cast<std::size_t>(UCHAR_MAX) + 1> euc1;
[[maybe_unused]] std::extents<unsigned char, std::dynamic_extent - 1> euc2;

I don't know whether this is actually better. Just a thought.

@ldionne ldionne merged commit 74e70ba into llvm:main Aug 27, 2024
55 checks passed
@frederick-vs-ja frederick-vs-ja deleted the extents-mandates branch August 28, 2024 07:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[libc++] Add a static_assert for the Mandates in extents for char
5 participants