xref: /llvm-project/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp (revision 9aa3b53ac52167aba6253a52805874948ce40c8f)
19816863dSZiqing Luo // RUN: %clang_cc1 -std=c++20  -Wno-all  -Wunsafe-buffer-usage-in-container -verify %s
29816863dSZiqing Luo 
39816863dSZiqing Luo namespace std {
49816863dSZiqing Luo   template <class T> class span {
59816863dSZiqing Luo   public:
69816863dSZiqing Luo     constexpr span(T *, unsigned){}
79816863dSZiqing Luo 
89816863dSZiqing Luo     template<class Begin, class End>
99816863dSZiqing Luo     constexpr span(Begin first, End last){}
109816863dSZiqing Luo 
119816863dSZiqing Luo     T * data();
129816863dSZiqing Luo 
139816863dSZiqing Luo     constexpr span() {};
149816863dSZiqing Luo 
159816863dSZiqing Luo     constexpr span(const std::span<T> &span) {};
169816863dSZiqing Luo 
179816863dSZiqing Luo     template<class R>
189816863dSZiqing Luo     constexpr span(R && range){};
199816863dSZiqing Luo   };
209816863dSZiqing Luo 
219816863dSZiqing Luo 
229816863dSZiqing Luo   template< class T >
239816863dSZiqing Luo   T&& move( T&& t ) noexcept;
249816863dSZiqing Luo }
259816863dSZiqing Luo 
269816863dSZiqing Luo namespace irrelevant_constructors {
279816863dSZiqing Luo   void non_two_param_constructors() {
289816863dSZiqing Luo     class Array {
299816863dSZiqing Luo     } a;
309816863dSZiqing Luo     std::span<int> S;      // no warn
319816863dSZiqing Luo     std::span<int> S1{};   // no warn
329816863dSZiqing Luo     std::span<int> S2{std::move(a)};  // no warn
339816863dSZiqing Luo     std::span<int> S3{S2};  // no warn
349816863dSZiqing Luo   }
359816863dSZiqing Luo } // irrelevant_constructors
369816863dSZiqing Luo 
379816863dSZiqing Luo namespace construct_wt_ptr_size {
389816863dSZiqing Luo   std::span<int> warnVarInit(int *p) {
399816863dSZiqing Luo     std::span<int> S{p, 10};                     // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
409816863dSZiqing Luo     std::span<int> S1(p, 10);                    // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
419816863dSZiqing Luo     std::span<int> S2 = std::span{p, 10};        // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
429816863dSZiqing Luo     std::span<int> S3 = std::span(p, 10);        // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
439816863dSZiqing Luo     std::span<int> S4 = std::span<int>{p, 10};   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
449816863dSZiqing Luo     std::span<int> S5 = std::span<int>(p, 10);   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
459816863dSZiqing Luo     std::span<int> S6 = {p, 10};                 // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
469816863dSZiqing Luo     auto S7 = std::span<int>{p, 10};             // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
479816863dSZiqing Luo     auto S8 = std::span<int>(p, 10);             // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
489816863dSZiqing Luo     const auto &S9 = std::span<int>{p, 10};      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
499816863dSZiqing Luo     auto &&S10 = std::span<int>(p, 10);          // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
509816863dSZiqing Luo 
519816863dSZiqing Luo #define Ten 10
529816863dSZiqing Luo 
539816863dSZiqing Luo     std::span S11 = std::span<int>{p, Ten};      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
549816863dSZiqing Luo 
559816863dSZiqing Luo     if (auto X = std::span<int>{p, Ten}; S10.data()) { // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
569816863dSZiqing Luo     }
579816863dSZiqing Luo 
589816863dSZiqing Luo     auto X = warnVarInit(p); // function return is fine
599816863dSZiqing Luo     return S;
609816863dSZiqing Luo   }
619816863dSZiqing Luo 
629816863dSZiqing Luo   template<typename T>
639816863dSZiqing Luo   void foo(const T &, const T &&, T);
649816863dSZiqing Luo 
659816863dSZiqing Luo   std::span<int> warnTemp(int *p) {
669816863dSZiqing Luo     foo(std::span<int>{p, 10},                       // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
679816863dSZiqing Luo 	std::move(std::span<int>{p, 10}),            // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
689816863dSZiqing Luo 	std::span<int>{p, 10});                      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
699816863dSZiqing Luo 
709816863dSZiqing Luo     std::span<int> Arr[1] = {std::span<int>{p, 10}}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
719816863dSZiqing Luo 
729816863dSZiqing Luo     if (std::span<int>{p, 10}.data()) {              // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
739816863dSZiqing Luo     }
749816863dSZiqing Luo     return std::span<int>{p, 10};                    // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
759816863dSZiqing Luo   }
769816863dSZiqing Luo 
779816863dSZiqing Luo   void notWarnSafeCases(unsigned n, int *p) {
789816863dSZiqing Luo     int X;
799816863dSZiqing Luo     unsigned Y = 10;
809816863dSZiqing Luo     std::span<int> S = std::span{&X, 1}; // no-warning
819816863dSZiqing Luo     int Arr[10];
82*9aa3b53aSZiqing Luo     typedef int TenInts_t[10];
83*9aa3b53aSZiqing Luo     TenInts_t Arr2;
849816863dSZiqing Luo 
859816863dSZiqing Luo     S = std::span{&X, 2};                // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
869816863dSZiqing Luo     S = std::span{new int[10], 10};      // no-warning
879816863dSZiqing Luo     S = std::span{new int[n], n};        // no-warning
889816863dSZiqing Luo     S = std::span{new int, 1};           // no-warning
899816863dSZiqing Luo     S = std::span{new int, X};           // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
909816863dSZiqing Luo     S = std::span{new int[n--], n--};    // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
919816863dSZiqing Luo     S = std::span{new int[10], 11};      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
929816863dSZiqing Luo     S = std::span{new int[10], 9};       // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}  // not smart enough to tell its safe
939816863dSZiqing Luo     S = std::span{new int[10], Y};       // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}  // not smart enough to tell its safe
949816863dSZiqing Luo     S = std::span{Arr, 10};              // no-warning
95*9aa3b53aSZiqing Luo     S = std::span{Arr2, 10};             // no-warning
969816863dSZiqing Luo     S = std::span{Arr, Y};               // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}  // not smart enough to tell its safe
979816863dSZiqing Luo     S = std::span{p, 0};                 // no-warning
989816863dSZiqing Luo   }
999816863dSZiqing Luo } // namespace construct_wt_ptr_size
1009816863dSZiqing Luo 
1019816863dSZiqing Luo namespace construct_wt_begin_end {
1029816863dSZiqing Luo   class It {};
1039816863dSZiqing Luo 
1049816863dSZiqing Luo   std::span<int> warnVarInit(It &First, It &Last) {
1059816863dSZiqing Luo     std::span<int> S{First, Last};                     // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1069816863dSZiqing Luo     std::span<int> S1(First, Last);                    // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1079816863dSZiqing Luo     std::span<int> S2 = std::span<int>{First, Last};   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1089816863dSZiqing Luo     std::span<int> S3 = std::span<int>(First, Last);   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1099816863dSZiqing Luo     std::span<int> S4 = std::span<int>{First, Last};   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1109816863dSZiqing Luo     std::span<int> S5 = std::span<int>(First, Last);   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1119816863dSZiqing Luo     std::span<int> S6 = {First, Last};                 // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1129816863dSZiqing Luo     auto S7 = std::span<int>{First, Last};             // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1139816863dSZiqing Luo     auto S8 = std::span<int>(First, Last);             // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1149816863dSZiqing Luo     const auto &S9 = std::span<int>{First, Last};      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1159816863dSZiqing Luo     auto &&S10 = std::span<int>(First, Last);          // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1169816863dSZiqing Luo 
1179816863dSZiqing Luo     if (auto X = std::span<int>{First, Last}; S10.data()) { // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1189816863dSZiqing Luo     }
1199816863dSZiqing Luo 
1209816863dSZiqing Luo     auto X = warnVarInit(First, Last); // function return is fine
1219816863dSZiqing Luo     return S;
1229816863dSZiqing Luo   }
1239816863dSZiqing Luo 
1249816863dSZiqing Luo   template<typename T>
1259816863dSZiqing Luo   void foo(const T &, const T &&, T);
1269816863dSZiqing Luo 
1279816863dSZiqing Luo   std::span<int> warnTemp(It &First, It &Last) {
1289816863dSZiqing Luo     foo(std::span<int>{First, Last},                       // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1299816863dSZiqing Luo 	std::move(std::span<int>{First, Last}),            // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1309816863dSZiqing Luo 	std::span<int>{First, Last});                      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1319816863dSZiqing Luo 
1329816863dSZiqing Luo     std::span<int> Arr[1] = {std::span<int>{First, Last}}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1339816863dSZiqing Luo 
1349816863dSZiqing Luo     if (std::span<int>{First, Last}.data()) {              // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1359816863dSZiqing Luo     }
1369816863dSZiqing Luo     return std::span<int>{First, Last};                    // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1379816863dSZiqing Luo   }
1389816863dSZiqing Luo } // namespace construct_wt_begin_end
1399816863dSZiqing Luo 
1409816863dSZiqing Luo namespace test_flag {
1419816863dSZiqing Luo   void f(int *p) {
1429816863dSZiqing Luo #pragma clang diagnostic push
1439816863dSZiqing Luo #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"  // this flag turns off every unsafe-buffer warning
1449816863dSZiqing Luo     std::span<int> S{p, 10};   // no-warning
1459816863dSZiqing Luo     p++;                       // no-warning
1469816863dSZiqing Luo #pragma clang diagnostic pop
1479816863dSZiqing Luo 
1489816863dSZiqing Luo #pragma clang diagnostic push
1499816863dSZiqing Luo #pragma clang diagnostic warning "-Wunsafe-buffer-usage"
1509816863dSZiqing Luo #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container"
1519816863dSZiqing Luo     // turn on all unsafe-buffer warnings except for the ones under `-Wunsafe-buffer-usage-in-container`
1529816863dSZiqing Luo     std::span<int> S2{p, 10};   // no-warning
1539816863dSZiqing Luo 
1549816863dSZiqing Luo     p++; // expected-warning{{unsafe pointer arithmetic}}\
1559816863dSZiqing Luo 	    expected-note{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
1569816863dSZiqing Luo #pragma clang diagnostic pop
1579816863dSZiqing Luo 
1589816863dSZiqing Luo   }
1599816863dSZiqing Luo } //namespace test_flag
160