1 // RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=core %s  \
2 // RUN:   -analyzer-output=plist -o %t.plist \
3 // RUN:   -analyzer-config expand-macros=true
4 //
5 // Check the actual plist output.
6 //   RUN: %normalize_plist <%t.plist | diff -ub \
7 //   RUN:   %S/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist -
8 //
9 // Check the macro expansions from the plist output here, to make the test more
10 // understandable.
11 //   RUN: FileCheck --input-file=%t.plist %s
12 
13 void print(const void*);
14 
15 //===----------------------------------------------------------------------===//
16 // Tests for non-function-like macro expansions.
17 //===----------------------------------------------------------------------===//
18 
19 #define SET_PTR_VAR_TO_NULL \
20   ptr = 0
21 
nonFunctionLikeMacroTest()22 void nonFunctionLikeMacroTest() {
23   int *ptr;
24   SET_PTR_VAR_TO_NULL;
25   *ptr = 5; // expected-warning{{Dereference of null pointer}}
26 }
27 
28 // CHECK: <key>name</key><string>SET_PTR_VAR_TO_NULL</string>
29 // CHECK-NEXT: <key>expansion</key><string>ptr = 0</string>
30 
31 #define NULL 0
32 #define SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO \
33   ptr = NULL
34 
nonFunctionLikeNestedMacroTest()35 void nonFunctionLikeNestedMacroTest() {
36   int *ptr;
37   SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO;
38   *ptr = 5; // expected-warning{{Dereference of null pointer}}
39 }
40 
41 // CHECK: <key>name</key><string>SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO</string>
42 // CHECK-NEXT: <key>expansion</key><string>ptr =0</string>
43 
44 //===----------------------------------------------------------------------===//
45 // Tests for function-like macro expansions.
46 //===----------------------------------------------------------------------===//
47 
setToNull(int ** vptr)48 void setToNull(int **vptr) {
49   *vptr = nullptr;
50 }
51 
52 #define TO_NULL(x) \
53   setToNull(x)
54 
functionLikeMacroTest()55 void functionLikeMacroTest() {
56   int *ptr;
57   TO_NULL(&ptr);
58   *ptr = 5; // expected-warning{{Dereference of null pointer}}
59 }
60 
61 // CHECK: <key>name</key><string>TO_NULL</string>
62 // CHECK-NEXT: <key>expansion</key><string>setToNull(&amp;ptr)</string>
63 
64 #define DOES_NOTHING(x) \
65   {                     \
66     int b;              \
67     b = 5;              \
68   }                     \
69   print(x)
70 
71 #define DEREF(x)   \
72   DOES_NOTHING(x); \
73   *x
74 
functionLikeNestedMacroTest()75 void functionLikeNestedMacroTest() {
76   int *a;
77   TO_NULL(&a);
78   DEREF(a) = 5; // expected-warning{{Dereference of null pointer}}
79 }
80 
81 // CHECK: <key>name</key><string>TO_NULL</string>
82 // CHECK-NEXT: <key>expansion</key><string>setToNull(&amp;a)</string>
83 
84 // CHECK: <key>name</key><string>DEREF</string>
85 // CHECK-NEXT: <key>expansion</key><string>{ int b; b = 5; } print(a); *a</string>
86 
87 //===----------------------------------------------------------------------===//
88 // Tests for undefining and/or redifining macros.
89 //===----------------------------------------------------------------------===//
90 
91 #define WILL_UNDEF_SET_NULL_TO_PTR(ptr) \
92   ptr = nullptr;
93 
undefinedMacroByTheEndOfParsingTest()94 void undefinedMacroByTheEndOfParsingTest() {
95   int *ptr;
96   WILL_UNDEF_SET_NULL_TO_PTR(ptr);
97   *ptr = 5; // expected-warning{{Dereference of null pointer}}
98 }
99 
100 #undef WILL_UNDEF_SET_NULL_TO_PTR
101 
102 // CHECK: <key>name</key><string>WILL_UNDEF_SET_NULL_TO_PTR</string>
103 // CHECK-NEXT: <key>expansion</key><string>ptr = nullptr;</string>
104 
105 #define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \
106   /* Nothing */
107 #undef WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL
108 #define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \
109   ptr = nullptr;
110 
macroRedefinedMultipleTimesTest()111 void macroRedefinedMultipleTimesTest() {
112   int *ptr;
113   WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr)
114   *ptr = 5; // expected-warning{{Dereference of null pointer}}
115 }
116 
117 #undef WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL
118 #define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr)                      \
119   print("This string shouldn't be in the plist file at all. Or anywhere, " \
120         "but here.");
121 
122 // CHECK: <key>name</key><string>WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL</string>
123 // CHECK-NEXT: <key>expansion</key><string>ptr = nullptr;</string>
124 
125 #define WILL_UNDEF_SET_NULL_TO_PTR_2(ptr) \
126   ptr = nullptr;
127 
128 #define PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr) \
129   WILL_UNDEF_SET_NULL_TO_PTR_2(ptr)
130 
undefinedMacroInsideAnotherMacroTest()131 void undefinedMacroInsideAnotherMacroTest() {
132   int *ptr;
133   PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr);
134   *ptr = 5; // expected-warning{{Dereference of null pointer}}
135 }
136 
137 // TODO: Expand arguments.
138 // CHECK: <key>name</key><string>PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD</string>
139 // CHECK-NEXT: <key>expansion</key><string>ptr = nullptr;</string>
140 
141 #undef WILL_UNDEF_SET_NULL_TO_PTR_2
142 
143 //===----------------------------------------------------------------------===//
144 // Tests for macro arguments containing commas and parantheses.
145 //
146 // As of writing these tests, the algorithm expands macro arguments by lexing
147 // the macro's expansion location, and relies on finding tok::comma and
148 // tok::l_paren/tok::r_paren.
149 //===----------------------------------------------------------------------===//
150 
151 // Note that this commas, parantheses in strings aren't parsed as tok::comma or
152 // tok::l_paren/tok::r_paren, but why not test them.
153 
154 #define TO_NULL_AND_PRINT(x, str) \
155   x = 0; \
156   print(str)
157 
macroArgContainsCommaInStringTest()158 void macroArgContainsCommaInStringTest() {
159   int *a;
160   TO_NULL_AND_PRINT(a, "Will this , cause a crash?");
161   *a = 5; // expected-warning{{Dereference of null pointer}}
162 }
163 
164 // CHECK: <key>name</key><string>TO_NULL_AND_PRINT</string>
165 // CHECK-NEXT: <key>expansion</key><string>a = 0; print( &quot;Will this , cause a crash?&quot;)</string>
166 
macroArgContainsLParenInStringTest()167 void macroArgContainsLParenInStringTest() {
168   int *a;
169   TO_NULL_AND_PRINT(a, "Will this ( cause a crash?");
170   *a = 5; // expected-warning{{Dereference of null pointer}}
171 }
172 
173 // CHECK: <key>name</key><string>TO_NULL_AND_PRINT</string>
174 // CHECK-NEXT: <key>expansion</key><string>a = 0; print( &quot;Will this ( cause a crash?&quot;)</string>
175 
macroArgContainsRParenInStringTest()176 void macroArgContainsRParenInStringTest() {
177   int *a;
178   TO_NULL_AND_PRINT(a, "Will this ) cause a crash?");
179   *a = 5; // expected-warning{{Dereference of null pointer}}
180 }
181 
182 // CHECK: <key>name</key><string>TO_NULL_AND_PRINT</string>
183 // CHECK-NEXT: <key>expansion</key><string>a = 0; print( &quot;Will this ) cause a crash?&quot;)</string>
184 
185 #define CALL_FUNCTION(funcCall)   \
186   funcCall
187 
188 // Function calls do contain both tok::comma and tok::l_paren/tok::r_paren.
189 
macroArgContainsLParenRParenTest()190 void macroArgContainsLParenRParenTest() {
191   int *a;
192   CALL_FUNCTION(setToNull(&a));
193   *a = 5; // expected-warning{{Dereference of null pointer}}
194 }
195 
196 // CHECK: <key>name</key><string>CALL_FUNCTION</string>
197 // CHECK-NEXT: <key>expansion</key><string>setToNull(&amp;a)</string>
198 
setToNullAndPrint(int ** vptr,const char * str)199 void setToNullAndPrint(int **vptr, const char *str) {
200   setToNull(vptr);
201   print(str);
202 }
203 
macroArgContainsCommaLParenRParenTest()204 void macroArgContainsCommaLParenRParenTest() {
205   int *a;
206   CALL_FUNCTION(setToNullAndPrint(&a, "Hello!"));
207   *a = 5; // expected-warning{{Dereference of null pointer}}
208 }
209 
210 // CHECK: <key>name</key><string>CALL_FUNCTION</string>
211 // CHECK-NEXT: <key>expansion</key><string>setToNullAndPrint(&amp;a, &quot;Hello!&quot;)</string>
212 
213 #define CALL_FUNCTION_WITH_TWO_PARAMS(funcCall, param1, param2) \
214   funcCall(param1, param2)
215 
macroArgContainsCommaLParenRParenTest2()216 void macroArgContainsCommaLParenRParenTest2() {
217   int *a;
218   CALL_FUNCTION_WITH_TWO_PARAMS(setToNullAndPrint, &a, "Hello!");
219   *a = 5; // expected-warning{{Dereference of null pointer}}
220 }
221 
222 // CHECK: <key>name</key><string>CALL_FUNCTION_WITH_TWO_PARAMS</string>
223 // CHECK-NEXT: <key>expansion</key><string>setToNullAndPrint( &amp;a, &quot;Hello!&quot;)</string>
224 
225 #define CALL_LAMBDA(l) \
226   l()
227 
commaInBracketsTest()228 void commaInBracketsTest() {
229   int *ptr;
230   const char str[] = "Hello!";
231   // You need to add parantheses around a lambda expression to compile this,
232   // else the comma in the capture will be parsed as divider of macro args.
233   CALL_LAMBDA(([&ptr, str] () mutable { TO_NULL(&ptr); }));
234   *ptr = 5; // expected-warning{{Dereference of null pointer}}
235 }
236 
237 // CHECK: <key>name</key><string>CALL_LAMBDA</string>
238 // CHECK-NEXT: <key>expansion</key><string>([&amp;ptr, str] () mutable { setToNull(&amp;ptr); })()</string>
239 
240 #define PASTE_CODE(code) \
241   code
242 
commaInBracesTest()243 void commaInBracesTest() {
244   PASTE_CODE({ // expected-warning{{Dereference of null pointer}}
245     // NOTE: If we were to add a new variable here after a comma, we'd get a
246     // compilation error, so this test is mainly here to show that this was also
247     // investigated.
248 
249     // int *ptr = nullptr, a;
250     int *ptr = nullptr;
251     *ptr = 5;
252   })
253 }
254 
255 // CHECK: <key>name</key><string>PASTE_CODE</string>
256 // CHECK-NEXT: <key>expansion</key><string>{ int *ptr = nullptr; *ptr = 5; }</string>
257 
258 // Example taken from
259 // https://gcc.gnu.org/onlinedocs/cpp/Macro-Arguments.html#Macro-Arguments.
260 
261 #define POTENTIALLY_EMPTY_PARAM(x, y) \
262   x;                                  \
263   y = nullptr
264 
emptyParamTest()265 void emptyParamTest() {
266   int *ptr;
267 
268   POTENTIALLY_EMPTY_PARAM(,ptr);
269   *ptr = 5; // expected-warning{{Dereference of null pointer}}
270 }
271 
272 // CHECK: <key>name</key><string>POTENTIALLY_EMPTY_PARAM</string>
273 // CHECK-NEXT: <key>expansion</key><string>;ptr = nullptr</string>
274 
275 #define NESTED_EMPTY_PARAM(a, b) \
276   POTENTIALLY_EMPTY_PARAM(a, b);
277 
278 
nestedEmptyParamTest()279 void nestedEmptyParamTest() {
280   int *ptr;
281 
282   NESTED_EMPTY_PARAM(, ptr);
283   *ptr = 5; // expected-warning{{Dereference of null pointer}}
284 }
285 
286 // CHECK: <key>name</key><string>NESTED_EMPTY_PARAM</string>
287 // CHECK-NEXT: <key>expansion</key><string>; ptr = nullptr;</string>
288 
289 #define CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(func, param) \
290   CALL_FUNCTION(func(param))
291 
lParenRParenInNestedMacro()292 void lParenRParenInNestedMacro() {
293   int *ptr;
294   CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(setToNull, &ptr);
295   *ptr = 5; // expected-warning{{Dereference of null pointer}}
296 }
297 
298 // CHECK: <key>name</key><string>CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO</string>
299 // CHECK-NEXT: <key>expansion</key><string>setToNull( &amp;ptr)</string>
300 
301 //===----------------------------------------------------------------------===//
302 // Tests for variadic macro arguments.
303 //===----------------------------------------------------------------------===//
304 
305 template <typename ...Args>
306 void variadicFunc(Args ...args);
307 
308 #define VARIADIC_SET_TO_NULL(ptr, ...) \
309   ptr = nullptr;                       \
310   variadicFunc(__VA_ARGS__)
311 
variadicMacroArgumentTest()312 void variadicMacroArgumentTest() {
313   int *ptr;
314   VARIADIC_SET_TO_NULL(ptr, 1, 5, "haha!");
315   *ptr = 5; // expected-warning{{Dereference of null pointer}}
316 }
317 
318 // CHECK: <key>name</key><string>VARIADIC_SET_TO_NULL</string>
319 // CHECK-NEXT: <key>expansion</key><string>ptr = nullptr; variadicFunc( 1, 5, &quot;haha!&quot;)</string>
320 
variadicMacroArgumentWithoutAnyArgumentTest()321 void variadicMacroArgumentWithoutAnyArgumentTest() {
322   int *ptr;
323   // Not adding a single parameter to ... is silly (and also causes a
324   // preprocessor warning), but is not an excuse to crash on it.
325   VARIADIC_SET_TO_NULL(ptr);
326   *ptr = 5; // expected-warning{{Dereference of null pointer}}
327 }
328 
329 // CHECK: <key>name</key><string>VARIADIC_SET_TO_NULL</string>
330 // CHECK-NEXT: <key>expansion</key><string>ptr = nullptr; variadicFunc()</string>
331 
332 //===----------------------------------------------------------------------===//
333 // Tests for # and ##.
334 //===----------------------------------------------------------------------===//
335 
336 #define DECLARE_FUNC_AND_SET_TO_NULL(funcName, ptr) \
337   void generated_##funcName();                      \
338   ptr = nullptr;
339 
hashHashOperatorTest()340 void hashHashOperatorTest() {
341   int *ptr;
342   DECLARE_FUNC_AND_SET_TO_NULL(whatever, ptr);
343   *ptr = 5; // expected-warning{{Dereference of null pointer}}
344 }
345 
346 // CHECK: <key>name</key><string>DECLARE_FUNC_AND_SET_TO_NULL</string>
347 // CHECK-NEXT: <key>expansion</key><string>void generated_whatever(); ptr = nullptr;</string>
348 
macroArgContainsHashHashInStringTest()349 void macroArgContainsHashHashInStringTest() {
350   int *a;
351   TO_NULL_AND_PRINT(a, "Will this ## cause a crash?");
352   *a = 5; // expected-warning{{Dereference of null pointer}}
353 }
354 
355 // CHECK: <key>name</key><string>TO_NULL_AND_PRINT</string>
356 // CHECK-NEXT: <key>expansion</key><string>a = 0; print( &quot;Will this ## cause a crash?&quot;)</string>
357 
358 #define PRINT_STR(str, ptr) \
359   print(#str);              \
360   ptr = nullptr
361 
hashOperatorTest()362 void hashOperatorTest() {
363   int *ptr;
364   PRINT_STR(Hello, ptr);
365   *ptr = 5; // expected-warning{{Dereference of null pointer}}
366 }
367 
368 // CHECK: <key>name</key><string>PRINT_STR</string>
369 // CHECK-NEXT: <key>expansion</key><string>print(&quot;Hello&quot;); ptr = nullptr</string>
370 
macroArgContainsHashInStringTest()371 void macroArgContainsHashInStringTest() {
372   int *a;
373   TO_NULL_AND_PRINT(a, "Will this # cause a crash?");
374   *a = 5; // expected-warning{{Dereference of null pointer}}
375 }
376 
377 // CHECK: <key>name</key><string>TO_NULL_AND_PRINT</string>
378 // CHECK-NEXT: <key>expansion</key><string>a = 0; print( &quot;Will this # cause a crash?&quot;)</string>
379 
380 //===----------------------------------------------------------------------===//
381 // Tests for more complex macro expansions.
382 //
383 // We won't cover anything that wasn't covered up to this point, but rather
384 // show more complex, macros with deeper nesting, more arguments (some unused)
385 // and so on.
386 //===----------------------------------------------------------------------===//
387 
388 #define IF(Condition) \
389   if ( Condition )
390 
391 #define L_BRACE {
392 #define R_BRACE }
393 #define LESS <
394 #define GREATER >
395 #define EQUALS =
396 #define SEMICOLON ;
397 #define NEGATIVE -
398 #define RETURN return
399 #define ZERO 0
400 
401 #define EUCLIDEAN_ALGORITHM(A, B)                                              \
402   IF(A LESS ZERO) L_BRACE                                                      \
403     A EQUALS NEGATIVE A SEMICOLON                                              \
404   R_BRACE                                                                      \
405   IF(B LESS ZERO) L_BRACE                                                      \
406     B EQUALS NEGATIVE B SEMICOLON                                              \
407   R_BRACE                                                                      \
408                                                                                \
409   /* This is where a while loop would be, but that seems to be too complex */  \
410   /* for the analyzer just yet. Let's just pretend that this algorithm     */  \
411   /* works.                                                                */  \
412                                                                                \
413   RETURN B / (B - B) SEMICOLON
414 
getLowestCommonDenominator(int A,int B)415 int getLowestCommonDenominator(int A, int B) {
416   EUCLIDEAN_ALGORITHM(A, B) // expected-warning{{Division by zero}}
417 }
418 
testVeryComplexAlgorithm()419 void testVeryComplexAlgorithm() {
420   int tmp = 8 / (getLowestCommonDenominator(5, 7) - 1);
421   print(&tmp);
422 }
423 // CHECK: <key>name</key><string>EUCLIDEAN_ALGORITHM</string>
424 // CHECK-NEXT: <key>expansion</key><string>if (A&lt;0 ){A=-A;} if ( B&lt;0 ){ B=- B;}return B / ( B - B);</string>
425 
426 #define YET_ANOTHER_SET_TO_NULL(x, y, z)   \
427   print((void *) x);                       \
428   print((void *) y);                       \
429   z = nullptr;
430 
431 #define DO_NOTHING(str) str
432 #define DO_NOTHING2(str2) DO_NOTHING(str2)
433 
test()434 void test() {
435   int *ptr;
436   YET_ANOTHER_SET_TO_NULL(5, DO_NOTHING2("Remember the Vasa"), ptr);
437   *ptr = 5; // expected-warning{{Dereference of null pointer}}
438 }
439 // CHECK: <key>name</key><string>YET_ANOTHER_SET_TO_NULL</string>
440 // CHECK-NEXT: <key>expansion</key><string>print((void *)5); print((void *)&quot;Remember the Vasa&quot;); ptr = nullptr;</string>
441 
442 int garbage_value;
443 
444 #define REC_MACRO_FUNC(REC_MACRO_PARAM) garbage_##REC_MACRO_PARAM
445 #define value REC_MACRO_FUNC(value)
446 
recursiveMacroUser()447 void recursiveMacroUser() {
448   if (value == 0)
449     1 / value; // expected-warning{{Division by zero}}
450                // expected-warning@-1{{expression result unused}}
451 }
452 
453 // CHECK: <key>name</key><string>value</string>
454 // CHECK-NEXT: <key>expansion</key><string>garbage_</string>
455 
456 #define FOO(x) int foo() { return x; }
457 #define APPLY_ZERO1(function) function(0)
458 
APPLY_ZERO1(FOO)459 APPLY_ZERO1(FOO)
460 void useZeroApplier1() { (void)(1 / foo()); } // expected-warning{{Division by zero}}
461 
462 // CHECK: <key>name</key><string>APPLY_ZERO1</string>
463 // CHECK-NEXT: <key>expansion</key><string>int foo() { return x; }(0)</string>
464 
465 #define BAR(x) int bar() { return x; }
466 #define APPLY_ZERO2 BAR(0)
467 
468 APPLY_ZERO2
useZeroApplier2()469 void useZeroApplier2() { (void)(1 / bar()); } // expected-warning{{Division by zero}}
470 
471 // CHECK: <key>name</key><string>APPLY_ZERO2</string>
472 // CHECK-NEXT: <key>expansion</key><string>int bar() { return 0; }</string>
473 
474 void foo(int &x, const char *str);
475 
476 #define PARAMS_RESOLVE_TO_VA_ARGS(i, fmt) foo(i, fmt); \
477   i = 0;
478 #define DISPATCH(...) PARAMS_RESOLVE_TO_VA_ARGS(__VA_ARGS__);
479 
mulitpleParamsResolveToVA_ARGS(void)480 void mulitpleParamsResolveToVA_ARGS(void) {
481   int x = 1;
482   DISPATCH(x, "LF1M healer");
483   (void)(10 / x); // expected-warning{{Division by zero}}
484 }
485 // CHECK: <key>name</key><string>DISPATCH</string>
486 // CHECK-NEXT: <key>expansion</key><string>foo(x, &quot;LF1M healer&quot;);x = 0;;</string>
487 
488 void variadicCFunction(int &x, const char *str, ...);
489 
490 #define CONCAT_VA_ARGS(i, fmt, ...) variadicCFunction(i, fmt, ##__VA_ARGS__); \
491   i = 0;
492 
concatVA_ARGS(void)493 void concatVA_ARGS(void) {
494   int x = 1;
495   CONCAT_VA_ARGS(x, "You need to construct additional pylons.", 'c', 9);
496   (void)(10 / x); // expected-warning{{Division by zero}}
497 }
498 // CHECK: <key>name</key><string>CONCAT_VA_ARGS</string>
499 // CHECK-NEXT: <key>expansion</key><string>variadicCFunction(x, &quot;You need to construct additional pylons.&quot;,&apos;c&apos;, 9);x = 0;</string>
500 
concatVA_ARGSEmpty(void)501 void concatVA_ARGSEmpty(void) {
502   int x = 1;
503   CONCAT_VA_ARGS(x, "You need to construct");
504   (void)(10 / x); // expected-warning{{Division by zero}}
505 }
506 // FIXME: The comma shouldn't be present after the last argument.
507 // CHECK: <key>name</key><string>CONCAT_VA_ARGS</string>
508 // CHECK-NEXT: <key>expansion</key><string>variadicCFunction(x, &quot;You need to construct&quot;,);x = 0;</string>
509 
510 #define STRINGIFIED_VA_ARGS(i, fmt, ...) variadicCFunction(i, fmt, #__VA_ARGS__); \
511   i = 0;
512 
stringifyVA_ARGS(void)513 void stringifyVA_ARGS(void) {
514   int x = 1;
515   STRINGIFIED_VA_ARGS(x, "Additional supply depots required.", 'a', 10);
516   (void)(10 / x); // expected-warning{{Division by zero}}
517 }
518 
519 // FIXME: Stringify and escape __VA_ARGS__ correctly.
520 // CHECK: <key>name</key><string>STRINGIFIED_VA_ARGS</string>
521 // CHECK-NEXT: <key>expansion</key><string>variadicCFunction(x, &quot;Additional supply depots required.&quot;,  &quot;&apos;a&apos;&quot;, 10);x = 0;</string>
522 
stringifyVA_ARGSEmpty(void)523 void stringifyVA_ARGSEmpty(void) {
524   int x = 1;
525   STRINGIFIED_VA_ARGS(x, "Additional supply depots required.");
526   (void)(10 / x); // expected-warning{{Division by zero}}
527 }
528 
529 // FIXME: Stringify and escape __VA_ARGS__ correctly.
530 // CHECK: <key>name</key><string>STRINGIFIED_VA_ARGS</string>
531 // CHECK-NEXT: <key>expansion</key><string>variadicCFunction(x, &quot;Additional supply depots required.&quot;, &quot;)&quot;;x = 0;</string>
532 
533 // bz44493: Support GNU-style named variadic arguments in plister
534 #define BZ44493_GNUVA(i, args...)  --(i);
535 
bz44493(void)536 int bz44493(void) {
537   int a = 2;
538   BZ44493_GNUVA(a);
539   BZ44493_GNUVA(a, "arg2");
540   (void)(10 / a); // expected-warning{{Division by zero}}
541   return 0;
542 }
543 
544 // CHECK: <key>name</key><string>BZ44493_GNUVA</string>
545 // CHECK-NEXT: <key>expansion</key><string>--(a);</string>
546