[clang] nonblocking/nonallocating attributes: 2nd pass caller/callee analysis (PR #99656)
Doug Wyatt via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 29 11:56:32 PDT 2024
================
@@ -210,24 +210,88 @@ void nb18(void (^block)() [[clang::nonblocking]]) [[clang::nonblocking]]
}
// Builtin functions
-void nb18a() [[clang::nonblocking]] {
+void nb19() [[clang::nonblocking]] {
__builtin_assume(1);
void *ptr = __builtin_malloc(1); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function '__builtin_malloc'}}
__builtin_free(ptr); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function '__builtin_free'}}
+
+ void *p2 = __builtin_operator_new(1); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function '__builtin_operator_new'}}
+ __builtin_operator_delete(p2); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function '__builtin_operator_delete'}}
+}
+
+// Function try-block
+void catches() try {} catch (...) {} // expected-note {{function cannot be inferred 'nonblocking' because it throws or catches exceptions}}
+
+void nb20() [[clang::nonblocking]] {
+ catches(); // expected-warning {{'nonblocking' function must not call non-'nonblocking' function 'catches'}}
+}
+
+struct S {
+ int x;
+ S(int x) try : x(x) {} catch (...) {} // expected-note {{constructor cannot be inferred 'nonblocking' because it throws or catches exceptions}}
+ S(double) : x((throw 3, 3)) {} // expected-note {{member initializer cannot be inferred 'nonblocking' because it throws or catches exceptions}} \
+ expected-note {{in constructor here}}
+};
+
+int badi(); // 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}}
+
+struct A { // expected-note {{in implicit constructor here}}
+ int x = (throw 3, 3); // expected-note {{member initializer cannot be inferred 'nonblocking' because it throws or catches exceptions}}
+};
+
+struct B {
+ int y = badi(); // expected-note {{member initializer cannot be inferred 'nonblocking' because it calls non-'nonblocking' function 'badi'}}
+};
+
+void f() [[clang::nonblocking]] {
+ S s1(3); // expected-warning {{'nonblocking' function must not call non-'nonblocking' constructor 'S::S'}}
+ S s2(3.0); // expected-warning {{'nonblocking' function must not call non-'nonblocking' constructor 'S::S'}}
+ A a; // expected-warning {{'nonblocking' function must not call non-'nonblocking' constructor 'A::A'}}
+ B b; // expected-warning {{'nonblocking' function must not call non-'nonblocking' constructor 'B::B'}}
+}
+
+struct T {
+ int x = badi(); // expected-warning {{'nonblocking' constructor's member initializer must not call non-'nonblocking' function 'badi'}}
+ T() [[clang::nonblocking]] {} // expected-note {{in constructor here}}
+ T(int x) [[clang::nonblocking]] : x(x) {} // OK
+};
+
----------------
dougsonos wrote:
Added one. This revealed a bug: when verifying a destructor, both bases and virtual bases were being traversed but this meant that a virtual base would get visited twice. Fixed that by ignoring the virtual bases.
https://github.com/llvm/llvm-project/pull/99656
More information about the cfe-commits
mailing list