[clang] Implement lifetime analysis for lifetime_capture_by(X) (#115921)
[llvm-project.git] / clang / test / Sema / attr-nonblocking-sema.cpp
blob9056f81f5296b9694def34890ce7c4b7b07bcb0c
1 // RUN: %clang_cc1 -fsyntax-only -fblocks -fcxx-exceptions -verify -Wfunction-effects %s
2 // RUN: %clang_cc1 -fsyntax-only -fblocks -verify -x c -std=c23 -Wfunction-effects %s
4 #if !__has_attribute(nonblocking)
5 #error "the 'nonblocking' attribute is not available"
6 #endif
8 // --- ATTRIBUTE SYNTAX: SUBJECTS ---
10 int nl_var [[clang::nonblocking]]; // expected-warning {{'nonblocking' only applies to function types; type here is 'int'}}
11 struct nl_struct {} [[clang::nonblocking]]; // expected-warning {{attribute 'nonblocking' is ignored, place it after "struct" to apply attribute to type declaration}}
12 struct [[clang::nonblocking]] nl_struct2 {}; // expected-error {{'nonblocking' attribute cannot be applied to a declaration}}
14 // Positive case
15 typedef void (*fo)() [[clang::nonblocking]];
16 void (*read_me_and_weep(
17 int val, void (*func)(int) [[clang::nonblocking]])
18 [[clang::nonblocking]]) (int)
19 [[clang::nonblocking]];
21 // --- ATTRIBUTE SYNTAX: ARGUMENT COUNT ---
22 void nargs_1() [[clang::nonblocking(1, 2)]]; // expected-error {{'nonblocking' attribute takes no more than 1 argument}}
23 void nargs_2() [[clang::nonallocating(1, 2)]]; // expected-error {{'nonallocating' attribute takes no more than 1 argument}}
24 void nargs_3() [[clang::blocking(1)]]; // expected-error {{'blocking' attribute takes no arguments}}
25 void nargs_4() [[clang::allocating(1)]]; // expected-error {{'allocating' attribute takes no arguments}}
27 // --- ATTRIBUTE SYNTAX: COMBINATIONS ---
28 // Check invalid combinations of nonblocking/nonallocating attributes
30 void nl_true_false_1() [[clang::nonblocking(true)]] [[clang::blocking]]; // expected-error {{'blocking' and 'nonblocking' attributes are not compatible}}
31 void nl_true_false_2() [[clang::blocking]] [[clang::nonblocking(true)]]; // expected-error {{'nonblocking' and 'blocking' attributes are not compatible}}
33 void nl_true_false_3() [[clang::nonblocking, clang::blocking]]; // expected-error {{'blocking' and 'nonblocking' attributes are not compatible}}
34 void nl_true_false_4() [[clang::blocking, clang::nonblocking]]; // expected-error {{'nonblocking' and 'blocking' attributes are not compatible}}
36 void na_true_false_1() [[clang::nonallocating(true)]] [[clang::allocating]]; // expected-error {{'allocating' and 'nonallocating' attributes are not compatible}}
37 void na_true_false_2() [[clang::allocating]] [[clang::nonallocating(true)]]; // expected-error {{'nonallocating' and 'allocating' attributes are not compatible}}
39 void na_true_false_3() [[clang::nonallocating, clang::allocating]]; // expected-error {{'allocating' and 'nonallocating' attributes are not compatible}}
40 void na_true_false_4() [[clang::allocating, clang::nonallocating]]; // expected-error {{'nonallocating' and 'allocating' attributes are not compatible}}
42 void nl_true_na_true_1() [[clang::nonblocking]] [[clang::nonallocating]];
43 void nl_true_na_true_2() [[clang::nonallocating]] [[clang::nonblocking]];
45 void nl_true_na_false_1() [[clang::nonblocking]] [[clang::allocating]]; // expected-error {{'allocating' and 'nonblocking' attributes are not compatible}}
46 void nl_true_na_false_2() [[clang::allocating]] [[clang::nonblocking]]; // expected-error {{'nonblocking' and 'allocating' attributes are not compatible}}
48 void nl_false_na_true_1() [[clang::blocking]] [[clang::nonallocating]];
49 void nl_false_na_true_2() [[clang::nonallocating]] [[clang::blocking]];
51 void nl_false_na_false_1() [[clang::blocking]] [[clang::allocating]];
52 void nl_false_na_false_2() [[clang::allocating]] [[clang::blocking]];
54 // --- TYPE CONVERSIONS ---
56 void unannotated();
57 void nonblocking() [[clang::nonblocking]];
58 void nonallocating() [[clang::nonallocating]];
59 void type_conversions()
61 // It's fine to remove a performance constraint.
62 void (*fp_plain)();
64 fp_plain = nullptr;
65 fp_plain = unannotated;
66 fp_plain = nonblocking;
67 fp_plain = nonallocating;
69 // Adding/spoofing nonblocking is unsafe.
70 void (*fp_nonblocking)() [[clang::nonblocking]];
71 fp_nonblocking = nullptr;
72 fp_nonblocking = nonblocking;
73 fp_nonblocking = unannotated; // expected-warning {{attribute 'nonblocking' should not be added via type conversion}}
74 fp_nonblocking = nonallocating; // expected-warning {{attribute 'nonblocking' should not be added via type conversion}}
76 // Adding/spoofing nonallocating is unsafe.
77 void (*fp_nonallocating)() [[clang::nonallocating]];
78 fp_nonallocating = nullptr;
79 fp_nonallocating = nonallocating;
80 fp_nonallocating = nonblocking; // no warning because nonblocking includes nonallocating
81 fp_nonallocating = unannotated; // expected-warning {{attribute 'nonallocating' should not be added via type conversion}}
84 #ifdef __cplusplus
85 struct PTMF {
86 void unannotated();
87 void nonblocking() [[clang::nonblocking]];
88 void nonallocating() [[clang::nonallocating]];
91 void type_conversions_ptmf()
93 // It's fine to remove a performance constraint.
94 void (PTMF::*ptmf_plain)() = nullptr;
96 ptmf_plain = &PTMF::unannotated;
97 ptmf_plain = &PTMF::nonblocking;
98 ptmf_plain = &PTMF::nonallocating;
100 // Adding/spoofing nonblocking is unsafe.
101 void (PTMF::*fp_nonblocking)() [[clang::nonblocking]] = nullptr;
102 fp_nonblocking = &PTMF::nonblocking;
103 fp_nonblocking = &PTMF::unannotated; // expected-warning {{attribute 'nonblocking' should not be added via type conversion}}
104 fp_nonblocking = &PTMF::nonallocating; // expected-warning {{attribute 'nonblocking' should not be added via type conversion}}
106 // Adding/spoofing nonallocating is unsafe.
107 void (PTMF::*fp_nonallocating)() [[clang::nonallocating]] = nullptr;
108 fp_nonallocating = &PTMF::nonallocating;
109 fp_nonallocating = &PTMF::nonblocking; // no warning because nonblocking includes nonallocating fp_nonallocating = unannotated;
110 fp_nonallocating = &PTMF::unannotated; // expected-warning {{attribute 'nonallocating' should not be added via type conversion}}
113 // There was a bug: noexcept and nonblocking could be individually removed in conversion, but not both
114 void type_conversions_2()
116 auto receives_fp = [](void (*fp)()) {
119 auto ne = +[]() noexcept {};
120 auto nl = +[]() [[clang::nonblocking]] {};
121 auto nl_ne = +[]() noexcept [[clang::nonblocking]] {};
123 receives_fp(ne);
124 receives_fp(nl);
125 receives_fp(nl_ne);
127 #endif
129 // --- VIRTUAL METHODS ---
130 // Attributes propagate to overridden methods, so no diagnostics except for conflicts.
131 // Check this in the syntax tests too.
132 #ifdef __cplusplus
133 struct Base {
134 virtual void f1();
135 virtual void nonblocking() noexcept [[clang::nonblocking]];
136 virtual void nonallocating() noexcept [[clang::nonallocating]];
137 virtual void f2() [[clang::nonallocating]]; // expected-note {{previous declaration is here}}
140 struct Derived : public Base {
141 void f1() [[clang::nonblocking]] override;
142 void nonblocking() noexcept override;
143 void nonallocating() noexcept override;
144 void f2() [[clang::allocating]] override; // expected-warning {{effects conflict when merging declarations; kept 'allocating', discarded 'nonallocating'}}
146 #endif // __cplusplus
148 // --- REDECLARATIONS ---
150 void f2();
151 void f2() [[clang::nonblocking]]; // expected-note {{previous declaration is here}}
152 void f2(); // expected-warning {{attribute 'nonblocking' on function does not match previous declaration}}
153 // Note: we verify that the attribute is actually seen during the constraints tests.
155 void f3() [[clang::blocking]]; // expected-note {{previous declaration is here}}
156 void f3() [[clang::nonblocking]]; // expected-warning {{effects conflict when merging declarations; kept 'blocking', discarded 'nonblocking'}}
158 // --- OVERLOADS ---
159 #ifdef __cplusplus
160 struct S {
161 void foo(); // expected-note {{previous declaration is here}}
162 void foo() [[clang::nonblocking]]; // expected-error {{class member cannot be redeclared}}
164 #endif // __cplusplus
166 // --- COMPUTED NONBLOCKING ---
167 void f4() [[clang::nonblocking(__builtin_memset)]] {} // expected-error {{nonblocking attribute requires an integer constant}}
169 #ifdef __cplusplus
170 // Unexpanded parameter pack
171 template <bool ...val>
172 void f5() [[clang::nonblocking(val /* NO ... here */)]] {} // expected-error {{expression contains unexpanded parameter pack 'val'}}
174 void f6() { f5<true, false>(); }
176 template <bool B>
177 void ambiguous() [[clang::nonblocking(B)]] [[clang::blocking]]; // expected-note {{candidate template ignored: substitution failure [with B = true]: 'blocking' and 'nonblocking' attributes are not compatible}}
179 void f7() {
180 ambiguous<true>(); // expected-error {{no matching function for call to 'ambiguous'}}
181 ambiguous<false>();
183 #endif // __cplusplus