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