brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.4 KiB · 012c017 Raw
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