================
@@ -0,0 +1,163 @@
+// clang-format off
+// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-container 
-verify %s
+// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage 
-Wno-unsafe-buffer-usage-in-container -verify=nowarn %s
+
+typedef unsigned long size_t;
+
+namespace custom {
+template <typename T>
+class MyVector {
+public:
+  T* data() noexcept;
+  size_t size() const noexcept;
+  T* begin() noexcept;
+  T* end() noexcept;
+};
+} // namespace custom
+
+template <typename T>
+class CustomSpan {
+public:
+  [[clang::unsafe_buffer_usage("container")]]
+  CustomSpan(T* ptr, size_t size);
+
+  template <typename It>
+  [[clang::unsafe_buffer_usage("container")]]
+  CustomSpan(It first, It last);
+};
+
+template <typename T>
+[[clang::unsafe_buffer_usage("container")]]
+CustomSpan<T> MakeCustomSpan(T* ptr, size_t size) {
+  return CustomSpan<T>(ptr, size);
+}
+
+template <typename T>
+[[clang::unsafe_buffer_usage("container")]]
+CustomSpan<T> MakeCustomSpan(T* first, T* last) {
+  return CustomSpan<T>(first, last);
+}
+
+void test_constructor(int* p, size_t n, custom::MyVector<int>& vec,
+                      custom::MyVector<int>& vec2) {
+  // Unsafe: decoupled pointer and size
+  CustomSpan<int> s1(p, n); // expected-warning{{the two-parameter CustomSpan 
construction is unsafe as it can introduce mismatch between buffer size and the 
bound information}}
+  CustomSpan<int> s2(p, 10); // expected-warning{{the two-parameter CustomSpan 
construction is unsafe as it can introduce mismatch between buffer size and the 
bound information}}
+
+  // Unsafe: duck typing approach with .data() and .size() called on different 
custom container objects
+  CustomSpan<int> s_bad_data_size(vec.data(), vec2.size()); // 
expected-warning{{the two-parameter CustomSpan construction is unsafe as it can 
introduce mismatch between buffer size and the bound information}}
+
+  // Unsafe: mismatched or reversed .begin() and .end()
+  CustomSpan<int> s_bad_iter1(vec.begin(), vec2.end()); // 
expected-warning{{the two-parameter CustomSpan construction is unsafe as it can 
introduce mismatch between buffer size and the bound information}}
+  CustomSpan<int> s_bad_iter2(vec.end(), vec.begin()); // 
expected-warning{{the two-parameter CustomSpan construction is unsafe as it can 
introduce mismatch between buffer size and the bound information}}
+
+  // Safe: duck typing approach with .data() and .size() called on the same 
custom container object
+  CustomSpan<int> s3(vec.data(), vec.size()); // no-warning
+
+  // Safe: .begin() and .end() called on the same custom container object
+  CustomSpan<int> s4(vec.begin(), vec.end()); // no-warning
+
+  // Safe: single element address
+  int x;
+  CustomSpan<int> s5(&x, 1); // no-warning
+
+  // Safe: zero size
+  CustomSpan<int> s6(p, 0); // no-warning
+
+  // Safe: constant array
+  int arr[10];
+  CustomSpan<int> s7(arr, 10); // no-warning
+
+  // Safe: new expression
+  CustomSpan<int> s8(new int[10], 10); // no-warning
+  CustomSpan<int> s9(new int[n], n); // no-warning
+}
+
+void test_factory(int* p, size_t n, custom::MyVector<int>& vec,
+                  custom::MyVector<int>& vec2) {
+  // Unsafe: decoupled pointer and size
+  auto s1 = MakeCustomSpan(p, n); // expected-warning{{the two-parameter 
MakeCustomSpan construction is unsafe as it can introduce mismatch between 
buffer size and the bound information}}
+  auto s2 = MakeCustomSpan(p, 10); // expected-warning{{the two-parameter 
MakeCustomSpan construction is unsafe as it can introduce mismatch between 
buffer size and the bound information}}
+
+  // Unsafe: duck typing approach with .data() and .size() called on different 
custom container objects
+  auto s_bad_data_size = MakeCustomSpan(vec.data(), vec2.size()); // 
expected-warning{{the two-parameter MakeCustomSpan construction is unsafe as it 
can introduce mismatch between buffer size and the bound information}}
+
+  // Unsafe: mismatched or reversed .begin() and .end()
+  auto s_bad_iter1 = MakeCustomSpan(vec.begin(), vec2.end()); // 
expected-warning{{the two-parameter MakeCustomSpan construction is unsafe as it 
can introduce mismatch between buffer size and the bound information}}
+  auto s_bad_iter2 = MakeCustomSpan(vec.end(), vec.begin()); // 
expected-warning{{the two-parameter MakeCustomSpan construction is unsafe as it 
can introduce mismatch between buffer size and the bound information}}
+
+  // Safe: duck typing approach with .data() and .size() called on the same 
custom container object
+  auto s3 = MakeCustomSpan(vec.data(), vec.size()); // no-warning
+
+  // Safe: .begin() and .end() called on the same custom container object
+  auto s4 = MakeCustomSpan(vec.begin(), vec.end()); // no-warning
+
+  // Safe: single element address
+  int x;
+  auto s5 = MakeCustomSpan(&x, 1); // no-warning
+
+  // Safe: zero size
+  auto s6 = MakeCustomSpan(p, 0); // no-warning
+
+  // Safe: constant array
+  int arr[10];
+  auto s7 = MakeCustomSpan(arr, 10); // no-warning
+}
+
+void test_pragma_suppression(int* p, size_t n) {
+#pragma clang unsafe_buffer_usage begin
+  CustomSpan<int> s1(p, n); // no-warning
+  auto s2 = MakeCustomSpan(p, n); // no-warning
+#pragma clang unsafe_buffer_usage end
+}
+
+template <typename T>
+class CustomSpanAlt {
----------------
ymand wrote:

I take it these are testing for the "...in_container" spelling? If so, I'd 
comment that here, before the tests. Also, I suggest minimal cases in 
`test_in_container_spelling`. Even just 1-2 is enough to verify that this 
spelling is triggering the same machinery.

https://github.com/llvm/llvm-project/pull/227108
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to