1 // RUN: %clang_cc1 -fsyntax-only -fblocks -fcxx-exceptions -std=c++20 -verify -Wfunction-effects -Wno-vla-extension %s 2 // These are in a separate file because errors (e.g. incompatible attributes) currently prevent 3 // the FXAnalysis pass from running at all. 4 5 // This diagnostic is re-enabled and exercised in isolation later in this file. 6 #pragma clang diagnostic ignored "-Wperf-constraint-implies-noexcept" 7 8 // --- CONSTRAINTS --- 9 10 void nb1() [[clang::nonblocking]] 11 { 12 int *pInt = new int; // expected-warning {{function with 'nonblocking' attribute must not allocate or deallocate memory}} 13 delete pInt; // expected-warning {{function with 'nonblocking' attribute must not allocate or deallocate memory}} 14 } 15 16 void nb2() [[clang::nonblocking]] 17 { 18 static int global; // expected-warning {{function with 'nonblocking' attribute must not have static local variables}} 19 } 20 21 void nb3() [[clang::nonblocking]] 22 { 23 try { 24 throw 42; // expected-warning {{function with 'nonblocking' attribute must not throw or catch exceptions}} 25 } 26 catch (...) { // expected-warning {{function with 'nonblocking' attribute must not throw or catch exceptions}} 27 } 28 } 29 30 void nb4_inline() {} 31 void nb4_not_inline(); // expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} 32 33 void nb4() [[clang::nonblocking]] 34 { 35 nb4_inline(); // OK 36 nb4_not_inline(); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function}} 37 } 38 39 40 struct HasVirtual { 41 virtual void unsafe(); // expected-note {{virtual method cannot be inferred 'nonblocking'}} 42 }; 43 44 void nb5() [[clang::nonblocking]] 45 { 46 HasVirtual hv; 47 hv.unsafe(); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function}} 48 } 49 50 void nb6_unsafe(); // expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} 51 void nb6_transitively_unsafe() 52 { 53 nb6_unsafe(); // expected-note {{function cannot be inferred 'nonblocking' because it calls non-'nonblocking' function}} 54 } 55 56 void nb6() [[clang::nonblocking]] 57 { 58 nb6_transitively_unsafe(); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function}} 59 } 60 61 thread_local int tl_var{ 42 }; 62 63 bool tl_test() [[clang::nonblocking]] 64 { 65 return tl_var > 0; // expected-warning {{function with 'nonblocking' attribute must not use thread-local variables}} 66 } 67 68 void nb7() 69 { 70 // Make sure we verify blocks 71 auto blk = ^() [[clang::nonblocking]] { 72 throw 42; // expected-warning {{block with 'nonblocking' attribute must not throw or catch exceptions}} 73 }; 74 } 75 76 void nb8() 77 { 78 // Make sure we verify lambdas 79 auto lambda = []() [[clang::nonblocking]] { 80 throw 42; // expected-warning {{lambda with 'nonblocking' attribute must not throw or catch exceptions}} 81 }; 82 } 83 84 void nb8a() [[clang::nonblocking]] 85 { 86 // A blocking lambda shouldn't make the outer function unsafe. 87 auto unsafeLambda = []() { 88 throw 42; 89 }; 90 } 91 92 void nb8b() [[clang::nonblocking]] 93 { 94 // An unsafe lambda capture makes the outer function unsafe. 95 auto unsafeCapture = [foo = new int]() { // expected-warning {{function with 'nonblocking' attribute must not allocate or deallocate memory}} 96 delete foo; 97 }; 98 } 99 100 void nb8c() 101 { 102 // An unsafe lambda capture does not make the lambda unsafe. 103 auto unsafeCapture = [foo = new int]() [[clang::nonblocking]] { 104 }; 105 } 106 107 // Make sure template expansions are found and verified. 108 template <typename T> 109 struct Adder { 110 static T add_explicit(T x, T y) [[clang::nonblocking]] 111 { 112 return x + y; // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function}} 113 } 114 static T add_implicit(T x, T y) 115 { 116 return x + y; // expected-note {{function cannot be inferred 'nonblocking' because it calls non-'nonblocking' function}} 117 } 118 }; 119 120 struct Stringy { 121 friend Stringy operator+(const Stringy& x, const Stringy& y) 122 { 123 // Do something inferably unsafe 124 auto* z = new char[42]; // expected-note {{function cannot be inferred 'nonblocking' because it allocates or deallocates memory}} 125 return {}; 126 } 127 }; 128 129 struct Stringy2 { 130 friend Stringy2 operator+(const Stringy2& x, const Stringy2& y) 131 { 132 // Do something inferably unsafe 133 throw 42; // expected-note {{function cannot be inferred 'nonblocking' because it throws or catches exceptions}} 134 } 135 }; 136 137 void nb9() [[clang::nonblocking]] 138 { 139 Adder<int>::add_explicit(1, 2); 140 Adder<int>::add_implicit(1, 2); 141 142 Adder<Stringy>::add_explicit({}, {}); // expected-note {{in template expansion here}} 143 Adder<Stringy2>::add_implicit({}, {}); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function}} \ 144 expected-note {{in template expansion here}} 145 } 146 147 // Make sure we verify lambdas produced from template expansions. 148 struct HasTemplatedLambda { 149 void (*fptr)() [[clang::nonblocking]]; 150 151 template <typename C> 152 HasTemplatedLambda(const C&) 153 : fptr{ []() [[clang::nonblocking]] { 154 auto* y = new int; // expected-warning {{lambda with 'nonblocking' attribute must not allocate or deallocate memory}} 155 } } 156 {} 157 }; 158 159 void nb9a() 160 { 161 HasTemplatedLambda bad(42); 162 } 163 164 // Templated function and lambda. 165 template <typename T> 166 void TemplatedFunc(T x) [[clang::nonblocking]] { 167 auto* ptr = new T; // expected-warning {{function with 'nonblocking' attribute must not allocate or deallocate memory}} 168 } 169 170 void nb9b() [[clang::nonblocking]] { 171 TemplatedFunc(42); // expected-note {{in template expansion here}} 172 173 auto foo = [](auto x) [[clang::nonblocking]] { 174 auto* ptr = new int; // expected-warning {{lambda with 'nonblocking' attribute must not allocate or deallocate memory}} 175 return x; 176 }; 177 178 // Note that foo() won't be validated unless instantiated. 179 foo(42); 180 } 181 182 void nb10( 183 void (*fp1)(), // expected-note {{function pointer cannot be inferred 'nonblocking'}} 184 void (*fp2)() [[clang::nonblocking]] 185 ) [[clang::nonblocking]] 186 { 187 fp1(); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function}} 188 fp2(); 189 190 // When there's a cast, there's a separate diagnostic. 191 static_cast<void (*)()>(fp1)(); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' expression}} 192 } 193 194 // Expression involving indirection 195 int nb10a() [[clang::nonblocking]]; 196 int nb10b() [[clang::nonblocking]]; 197 int blocking(); 198 199 int nb10c(bool x) [[clang::nonblocking]] 200 { 201 int y = (x ? nb10a : blocking)(); // expected-warning {{attribute 'nonblocking' should not be added via type conversion}} 202 return (x ? nb10a : nb10b)(); // No diagnostic. 203 } 204 205 // Interactions with nonblocking(false) 206 void nb11_no_inference_1() [[clang::nonblocking(false)]] // expected-note {{function does not permit inference of 'nonblocking'}} 207 { 208 } 209 void nb11_no_inference_2() [[clang::nonblocking(false)]]; // expected-note {{function does not permit inference of 'nonblocking'}} 210 211 template <bool V> 212 struct ComputedNB { 213 void method() [[clang::nonblocking(V)]]; // expected-note {{function does not permit inference of 'nonblocking' because it is declared 'blocking'}} 214 }; 215 216 void nb11() [[clang::nonblocking]] 217 { 218 nb11_no_inference_1(); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function}} 219 nb11_no_inference_2(); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function}} 220 221 ComputedNB<true> CNB_true; 222 CNB_true.method(); 223 224 ComputedNB<false> CNB_false; 225 CNB_false.method(); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function}} 226 } 227 228 // Verify that when attached to a redeclaration, the attribute successfully attaches. 229 void nb12() { 230 static int x; // expected-warning {{function with 'nonblocking' attribute must not have static local variables}} 231 } 232 void nb12() [[clang::nonblocking]]; 233 void nb13() [[clang::nonblocking]] { nb12(); } 234 235 // C++ member function pointers 236 struct PTMFTester { 237 typedef void (PTMFTester::*ConvertFunction)() [[clang::nonblocking]]; 238 239 void convert() [[clang::nonblocking]]; 240 241 ConvertFunction mConvertFunc; 242 }; 243 244 void PTMFTester::convert() [[clang::nonblocking]] 245 { 246 (this->*mConvertFunc)(); 247 } 248 249 // Allow implicit conversion from array to pointer. 250 void nb14(unsigned idx) [[clang::nonblocking]] 251 { 252 using FP = void (*)() [[clang::nonblocking]]; 253 using FPArray = FP[2]; 254 auto nb = +[]() [[clang::nonblocking]] {}; 255 256 FPArray src{ nb, nullptr }; 257 FP f = src[idx]; // This should not generate a warning. 258 259 FP twoDim[2][2] = {}; 260 FP g = twoDim[1][1]; 261 262 FP vla[idx]; 263 FP h = vla[0]; 264 } 265 266 // Block variables 267 void nb17(void (^blk)() [[clang::nonblocking]]) [[clang::nonblocking]] { 268 blk(); 269 } 270 271 // References to blocks 272 void nb18(void (^block)() [[clang::nonblocking]]) [[clang::nonblocking]] 273 { 274 auto &ref = block; 275 ref(); 276 } 277 278 // Builtin functions 279 void nb19() [[clang::nonblocking]] { 280 __builtin_assume(1); 281 void *ptr = __builtin_malloc(1); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function '__builtin_malloc'}} 282 __builtin_free(ptr); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function '__builtin_free'}} 283 284 void *p2 = __builtin_operator_new(1); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function '__builtin_operator_new'}} 285 __builtin_operator_delete(p2); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function '__builtin_operator_delete'}} 286 } 287 288 // Function try-block 289 void catches() try {} catch (...) {} // expected-note {{function cannot be inferred 'nonblocking' because it throws or catches exceptions}} 290 291 void nb20() [[clang::nonblocking]] { 292 catches(); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function 'catches'}} 293 } 294 295 struct S { 296 int x; 297 S(int x) try : x(x) {} catch (...) {} // expected-note {{constructor cannot be inferred 'nonblocking' because it throws or catches exceptions}} 298 S(double) : x((throw 3, 3)) {} // expected-note {{member initializer cannot be inferred 'nonblocking' because it throws or catches exceptions}} \ 299 expected-note {{in constructor here}} 300 }; 301 302 int badi(); // expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} \ 303 // expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} 304 305 struct A { // expected-note {{in implicit constructor here}} 306 int x = (throw 3, 3); // expected-note {{member initializer cannot be inferred 'nonblocking' because it throws or catches exceptions}} 307 }; 308 309 struct B { 310 int y = badi(); // expected-note {{member initializer cannot be inferred 'nonblocking' because it calls non-'nonblocking' function 'badi'}} 311 }; 312 313 void f() [[clang::nonblocking]] { 314 S s1(3); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' constructor 'S::S'}} 315 S s2(3.0); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' constructor 'S::S'}} 316 A a; // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' constructor 'A::A'}} 317 B b; // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' constructor 'B::B'}} 318 } 319 320 struct T { 321 int x = badi(); // expected-warning {{member initializer of constructor with 'nonblocking' attribute must not call non-'nonblocking' function 'badi'}} 322 T() [[clang::nonblocking]] {} // expected-note {{in constructor here}} 323 T(int x) [[clang::nonblocking]] : x(x) {} // OK 324 }; 325 326 // Default arguments 327 int badForDefaultArg(); // expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} \ 328 expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} \ 329 expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} 330 331 void hasDefaultArg(int param = badForDefaultArg()) { // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function 'badForDefaultArg'}} \ 332 expected-note {{function cannot be inferred 'nonblocking' because it calls non-'nonblocking' function 'badForDefaultArg'}} 333 } 334 335 void nb21() [[clang::nonblocking]] { 336 hasDefaultArg(); // expected-note {{in evaluating default argument here}} \ 337 expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function 'hasDefaultArg'}} 338 } 339 340 void nb22(int param = badForDefaultArg()) [[clang::nonblocking]] { // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' function 'badForDefaultArg'}} 341 } 342 343 // Verify traversal of implicit code paths - constructors and destructors. 344 struct Unsafe { 345 static void problem1(); // expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} 346 static void problem2(); // expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} 347 348 Unsafe() { problem1(); } // expected-note {{constructor cannot be inferred 'nonblocking' because it calls non-'nonblocking' function 'Unsafe::problem1'}} 349 ~Unsafe() { problem2(); } // expected-note {{destructor cannot be inferred 'nonblocking' because it calls non-'nonblocking' function 'Unsafe::problem2'}} 350 351 Unsafe(int x); // expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} expected-note {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} 352 353 // Delegating initializer. 354 Unsafe(float y) [[clang::nonblocking]] : Unsafe(int(y)) {} // expected-warning {{constructor with 'nonblocking' attribute must not call non-'nonblocking' constructor 'Unsafe::Unsafe'}} 355 }; 356 357 struct DerivedFromUnsafe : public Unsafe { 358 DerivedFromUnsafe() [[clang::nonblocking]] {} // expected-warning {{constructor with 'nonblocking' attribute must not call non-'nonblocking' constructor 'Unsafe::Unsafe'}} 359 DerivedFromUnsafe(int x) [[clang::nonblocking]] : Unsafe(x) {} // expected-warning {{constructor with 'nonblocking' attribute must not call non-'nonblocking' constructor 'Unsafe::Unsafe'}} 360 ~DerivedFromUnsafe() [[clang::nonblocking]] {} // expected-warning {{destructor with 'nonblocking' attribute must not call non-'nonblocking' destructor 'Unsafe::~Unsafe'}} 361 }; 362 363 // Don't try to follow a deleted destructor, as with std::optional<T>. 364 struct HasDtor { 365 ~HasDtor() {} 366 }; 367 368 template <typename T> 369 struct Optional { 370 union { 371 char __null_state_; 372 T __val_; 373 }; 374 bool engaged = false; 375 376 ~Optional() { 377 if (engaged) 378 __val_.~T(); 379 } 380 }; 381 382 void nb_opt() [[clang::nonblocking]] { 383 Optional<HasDtor> x; 384 } 385 386 // Virtual inheritance 387 struct VBase { 388 int *Ptr; 389 390 VBase() { Ptr = new int; } // expected-note {{constructor cannot be inferred 'nonblocking' because it allocates or deallocates memory}} 391 virtual ~VBase() { delete Ptr; } // expected-note {{virtual method cannot be inferred 'nonblocking'}} 392 }; 393 394 struct VDerived : virtual VBase { 395 VDerived() [[clang::nonblocking]] {} // expected-warning {{constructor with 'nonblocking' attribute must not call non-'nonblocking' constructor 'VBase::VBase'}} 396 397 ~VDerived() [[clang::nonblocking]] {} // expected-warning {{destructor with 'nonblocking' attribute must not call non-'nonblocking' destructor 'VBase::~VBase'}} 398 }; 399 400 // Contexts where there is no function call, no diagnostic. 401 bool bad(); 402 403 template <bool> 404 requires requires { bad(); } 405 void g() [[clang::nonblocking]] {} 406 407 void g() [[clang::nonblocking]] { 408 decltype(bad()) a; // doesn't generate a call so, OK 409 [[maybe_unused]] auto b = noexcept(bad()); 410 [[maybe_unused]] auto c = sizeof(bad()); 411 #pragma clang diagnostic push 412 #pragma clang diagnostic ignored "-Wassume" 413 [[assume(bad())]]; // never evaluated, but maybe still semantically questionable? 414 #pragma clang diagnostic pop 415 } 416 417 // Make sure we are skipping concept requirements -- they can trigger an unexpected 418 // warning involving use of a function pointer (e.g. std::reverse_iterator::operator== 419 struct HasFoo { int foo() const { return 0; } }; 420 421 template <class A, class B> 422 inline bool compare(const A& a, const B& b) 423 requires requires { 424 a.foo(); 425 } 426 { 427 return a.foo() == b.foo(); 428 } 429 430 void nb25() [[clang::nonblocking]] { 431 HasFoo a, b; 432 compare(a, b); 433 } 434 435 // If the callee is both noreturn and noexcept, it presumably terminates. 436 // Ignore it for the purposes of effect analysis. 437 [[noreturn]] void abort_wrapper() noexcept; 438 439 void nb26() [[clang::nonblocking]] { 440 abort_wrapper(); // no diagnostic 441 } 442 443 // --- Make sure we don't traverse requires and noexcept clauses. --- 444 445 // Apparently some requires clauses are able to be collapsed into a constant before the nonblocking 446 // analysis sees any function calls. This example (extracted from a real-world case where 447 // `operator&&` in <valarray>, preceding the inclusion of <expected>) is sufficiently complex 448 // to look like it contains function calls. There may be simpler examples. 449 450 namespace ExpectedTest { 451 452 template <class _Tp> 453 inline constexpr bool is_copy_constructible_v = __is_constructible(_Tp, _Tp&); 454 455 template <bool, class _Tp = void> 456 struct enable_if {}; 457 template <class _Tp> 458 struct enable_if<true, _Tp> { 459 typedef _Tp type; 460 }; 461 462 template <bool _Bp, class _Tp = void> 463 using enable_if_t = typename enable_if<_Bp, _Tp>::type; 464 465 // Doesn't seem to matter whether the enable_if is true or false. 466 template <class E1, class E2, enable_if_t<is_copy_constructible_v<E1>> = 0> 467 inline bool operator&&(const E1& x, const E2& y); 468 469 template <class _Tp, class _Err> 470 class expected { 471 public: 472 constexpr expected() 473 {} 474 475 // This is a deliberate corruption of the real implementation for simplicity. 476 constexpr expected(const expected&) 477 requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err>) 478 = default; 479 }; 480 481 void test() [[clang::nonblocking]] 482 { 483 expected<int, int> a; 484 auto b = a; // Copy constructor. 485 } 486 487 } // namespace ExpectedTest 488 489 // Make sure a function call in a noexcept() clause is ignored. 490 constexpr bool foo() [[clang::nonblocking(false)]] { return true; } 491 void nb27() noexcept(foo()) [[clang::nonblocking]] {} 492 493 // Make sure that simple type traits don't cause violations. 494 void nb28() [[clang::nonblocking]] { 495 bool x = __is_constructible(int, const int&); 496 } 497 498 // --- nonblocking implies noexcept --- 499 #pragma clang diagnostic warning "-Wperf-constraint-implies-noexcept" 500 501 void needs_noexcept() [[clang::nonblocking]] // expected-warning {{function with 'nonblocking' attribute should be declared noexcept}} 502 { 503 auto lambda = []() [[clang::nonblocking]] {}; // expected-warning {{lambda with 'nonblocking' attribute should be declared noexcept}} 504 } 505