Bug 1814798 - pt 1. Add bool to enable/disable PHC at runtime r=glandium
[gecko.git] / build / clang-plugin / tests / TestMustReturnFromCaller.cpp
blobc935be3cf89383359cc0c68135d058740f7d79a4
1 #include <cstddef>
2 #include <utility>
4 #define MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG __attribute__((annotate("moz_must_return_from_caller_if_this_is_arg")))
5 #define MOZ_MAY_CALL_AFTER_MUST_RETURN __attribute__((annotate("moz_may_call_after_must_return")))
7 struct Thrower {
8 void MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG Throw() {}
9 };
11 void DoAnythingElse();
12 int MakeAnInt();
13 int MOZ_MAY_CALL_AFTER_MUST_RETURN SafeMakeInt();
14 bool Condition();
16 // It might be nicer to #include "mozilla/ScopeExit.h" and use that here -- but
17 // doing so also will #define the two attribute-macros defined above, running a
18 // risk of redefinition errors. Just stick to the normal clang-plugin test
19 // style and use as little external code as possible.
21 template<typename Func>
22 class ScopeExit {
23 Func exitFunction;
24 bool callOnDestruction;
25 public:
26 explicit ScopeExit(Func&& func)
27 : exitFunction(std::move(func))
28 , callOnDestruction(true)
31 ~ScopeExit() {
32 if (callOnDestruction) {
33 exitFunction();
37 void release() { callOnDestruction = false; }
40 template<typename ExitFunction>
41 ScopeExit<ExitFunction>
42 MakeScopeExit(ExitFunction&& func)
44 return ScopeExit<ExitFunction>(std::move(func));
47 class Foo {
48 public:
49 __attribute__((annotate("moz_implicit"))) Foo(std::nullptr_t);
50 Foo();
53 void a1(Thrower& thrower) {
54 thrower.Throw();
57 int a2(Thrower& thrower) {
58 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
59 return MakeAnInt();
62 int a3(Thrower& thrower) {
63 // RAII operations happening after a must-immediately-return are fine.
64 auto atExit = MakeScopeExit([] { DoAnythingElse(); });
65 thrower.Throw();
66 return 5;
69 int a4(Thrower& thrower) {
70 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
71 return Condition() ? MakeAnInt() : MakeAnInt();
74 void a5(Thrower& thrower) {
75 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
76 DoAnythingElse();
79 int a6(Thrower& thrower) {
80 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
81 DoAnythingElse();
82 return MakeAnInt();
85 int a7(Thrower& thrower) {
86 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
87 DoAnythingElse();
88 return Condition() ? MakeAnInt() : MakeAnInt();
91 int a8(Thrower& thrower) {
92 thrower.Throw();
93 return SafeMakeInt();
96 int a9(Thrower& thrower) {
97 if (Condition()) {
98 thrower.Throw();
100 return SafeMakeInt();
103 int a10(Thrower& thrower) {
104 auto atExit = MakeScopeExit([] { DoAnythingElse(); });
106 if (Condition()) {
107 thrower.Throw();
108 return SafeMakeInt();
111 atExit.release();
112 DoAnythingElse();
113 return 5;
116 void b1(Thrower& thrower) {
117 if (Condition()) {
118 thrower.Throw();
122 int b2(Thrower& thrower) {
123 if (Condition()) {
124 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
126 return MakeAnInt();
129 int b3(Thrower& thrower) {
130 if (Condition()) {
131 thrower.Throw();
133 return 5;
136 // Explicit test in orer to also verify the `UnaryOperator` node in the `CFG`
137 int b3a(Thrower& thrower) {
138 if (Condition()) {
139 thrower.Throw();
141 return -1;
144 float b3b(Thrower& thrower) {
145 if (Condition()) {
146 thrower.Throw();
148 return 1.0f;
151 bool b3c(Thrower& thrower) {
152 if (Condition()) {
153 thrower.Throw();
155 return false;
158 int b4(Thrower& thrower) {
159 if (Condition()) {
160 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
162 return Condition() ? MakeAnInt() : MakeAnInt();
165 void b5(Thrower& thrower) {
166 if (Condition()) {
167 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
169 DoAnythingElse();
172 void b6(Thrower& thrower) {
173 if (Condition()) {
174 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
175 DoAnythingElse();
179 void b7(Thrower& thrower) {
180 if (Condition()) {
181 thrower.Throw();
182 return;
184 DoAnythingElse();
187 void b8(Thrower& thrower) {
188 if (Condition()) {
189 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
190 DoAnythingElse();
191 return;
193 DoAnythingElse();
196 void b9(Thrower& thrower) {
197 while (Condition()) {
198 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
202 void b10(Thrower& thrower) {
203 while (Condition()) {
204 thrower.Throw();
205 return;
209 void b11(Thrower& thrower) {
210 thrower.Throw(); // expected-error {{You must immediately return after calling this function}}
211 if (Condition()) {
212 return;
213 } else {
214 return;
218 void b12(Thrower& thrower) {
219 switch (MakeAnInt()) {
220 case 1:
221 break;
222 default:
223 thrower.Throw();
224 return;
228 void b13(Thrower& thrower) {
229 if (Condition()) {
230 thrower.Throw();
232 return;
235 Foo b14(Thrower& thrower) {
236 if (Condition()) {
237 thrower.Throw();
238 return nullptr;
240 return nullptr;
243 Foo b15(Thrower& thrower) {
244 if (Condition()) {
245 thrower.Throw();
247 return nullptr;
250 Foo b16(Thrower& thrower) {
251 if (Condition()) {
252 thrower.Throw();
254 return Foo();
257 void c1() {
258 Thrower thrower;
259 thrower.Throw();
260 DoAnythingElse(); // Should be allowed, since our thrower is not an arg
263 class TestRet {
264 TestRet *b13(Thrower &thrower) {
265 if (Condition()) {
266 thrower.Throw();
268 return this;