// RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=core %s \ // RUN: -analyzer-output=plist -o %t.plist \ // RUN: -analyzer-config expand-macros=true -verify // // RUN: FileCheck --input-file=%t.plist %s void print(const void*); //===----------------------------------------------------------------------===// // Tests for non-function-like macro expansions. //===----------------------------------------------------------------------===// #define SET_PTR_VAR_TO_NULL \ ptr = 0 void nonFunctionLikeMacroTest() { int *ptr; SET_PTR_VAR_TO_NULL; *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line18 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameSET_PTR_VAR_TO_NULL // CHECK-NEXT: expansionptr =0 // CHECK-NEXT: // CHECK-NEXT: #define NULL 0 #define SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO \ ptr = NULL void nonFunctionLikeNestedMacroTest() { int *ptr; SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO; *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line42 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameSET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO // CHECK-NEXT: expansionptr =0 // CHECK-NEXT: // CHECK-NEXT: //===----------------------------------------------------------------------===// // Tests for function-like macro expansions. //===----------------------------------------------------------------------===// void setToNull(int **vptr) { *vptr = nullptr; } #define TO_NULL(x) \ setToNull(x) void functionLikeMacroTest() { int *ptr; TO_NULL(&ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line73 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameTO_NULL(&ptr) // CHECK-NEXT: expansionsetToNull (&ptr ) // CHECK-NEXT: // CHECK-NEXT: #define DOES_NOTHING(x) \ { \ int b; \ b = 5; \ } \ print(x) #define DEREF(x) \ DOES_NOTHING(x); \ *x void functionLikeNestedMacroTest() { int *a; TO_NULL(&a); DEREF(a) = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line104 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameTO_NULL(&a) // CHECK-NEXT: expansionsetToNull (&a ) // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line105 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameDEREF(a) // CHECK-NEXT: expansion{int b ;b =5;}print (a );*a // CHECK-NEXT: // CHECK-NEXT: //===----------------------------------------------------------------------===// // Tests for undefining and/or redifining macros. //===----------------------------------------------------------------------===// #define WILL_UNDEF_SET_NULL_TO_PTR(ptr) \ ptr = nullptr; void undefinedMacroByTheEndOfParsingTest() { int *ptr; WILL_UNDEF_SET_NULL_TO_PTR(ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } #undef WILL_UNDEF_SET_NULL_TO_PTR // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line141 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameWILL_UNDEF_SET_NULL_TO_PTR(ptr) // CHECK-NEXT: expansionptr =nullptr ; // CHECK-NEXT: // CHECK-NEXT: #define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \ /* Nothing */ #undef WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL #define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \ ptr = nullptr; void macroRedefinedMultipleTimesTest() { int *ptr; WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) *ptr = 5; // expected-warning{{Dereference of null pointer}} } #undef WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL #define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \ print("This string shouldn't be in the plist file at all. Or anywhere, " \ "but here."); // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line169 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameWILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) // CHECK-NEXT: expansionptr =nullptr ; // CHECK-NEXT: // CHECK-NEXT: #define WILL_UNDEF_SET_NULL_TO_PTR_2(ptr) \ ptr = nullptr; #define PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr) \ WILL_UNDEF_SET_NULL_TO_PTR_2(ptr) void undefinedMacroInsideAnotherMacroTest() { int *ptr; PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line200 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: namePASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr) // CHECK-NEXT: expansionptr =nullptr ; // CHECK-NEXT: // CHECK-NEXT: #undef WILL_UNDEF_SET_NULL_TO_PTR_2 //===----------------------------------------------------------------------===// // Tests for macro arguments containing commas and parantheses. // // As of writing these tests, the algorithm expands macro arguments by lexing // the macro's expansion location, and relies on finding tok::comma and // tok::l_paren/tok::r_paren. //===----------------------------------------------------------------------===// // Note that this commas, parantheses in strings aren't parsed as tok::comma or // tok::l_paren/tok::r_paren, but why not test them. #define TO_NULL_AND_PRINT(x, str) \ x = 0; \ print(str) void macroArgContainsCommaInStringTest() { int *a; TO_NULL_AND_PRINT(a, "Will this , cause a crash?"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line237 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameTO_NULL_AND_PRINT(a, "Will this , cause a crash?") // CHECK-NEXT: expansiona =0;print ("Will this , cause a crash?") // CHECK-NEXT: // CHECK-NEXT: void macroArgContainsLParenInStringTest() { int *a; TO_NULL_AND_PRINT(a, "Will this ( cause a crash?"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line257 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameTO_NULL_AND_PRINT(a, "Will this ( cause a crash?") // CHECK-NEXT: expansiona =0;print ("Will this ( cause a crash?") // CHECK-NEXT: // CHECK-NEXT: void macroArgContainsRParenInStringTest() { int *a; TO_NULL_AND_PRINT(a, "Will this ) cause a crash?"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line277 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameTO_NULL_AND_PRINT(a, "Will this ) cause a crash?") // CHECK-NEXT: expansiona =0;print ("Will this ) cause a crash?") // CHECK-NEXT: // CHECK-NEXT: #define CALL_FUNCTION(funcCall) \ funcCall // Function calls do contain both tok::comma and tok::l_paren/tok::r_paren. void macroArgContainsLParenRParenTest() { int *a; CALL_FUNCTION(setToNull(&a)); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line302 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameCALL_FUNCTION(setToNull(&a)) // CHECK-NEXT: expansionsetToNull (&a ) // CHECK-NEXT: // CHECK-NEXT: void setToNullAndPrint(int **vptr, const char *str) { setToNull(vptr); print(str); } void macroArgContainsCommaLParenRParenTest() { int *a; CALL_FUNCTION(setToNullAndPrint(&a, "Hello!")); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line327 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameCALL_FUNCTION(setToNullAndPrint(&a, "Hello!")) // CHECK-NEXT: expansionsetToNullAndPrint (&a ,"Hello!") // CHECK-NEXT: // CHECK-NEXT: #define CALL_FUNCTION_WITH_TWO_PARAMS(funcCall, param1, param2) \ funcCall(param1, param2) void macroArgContainsCommaLParenRParenTest2() { int *a; CALL_FUNCTION_WITH_TWO_PARAMS(setToNullAndPrint, &a, "Hello!"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line350 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameCALL_FUNCTION_WITH_TWO_PARAMS(setToNullAndPrint, &a, "Hello!") // CHECK-NEXT: expansionsetToNullAndPrint (&a ,"Hello!") // CHECK-NEXT: // CHECK-NEXT: #define CALL_LAMBDA(l) \ l() void commaInBracketsTest() { int *ptr; const char str[] = "Hello!"; // You need to add parantheses around a lambda expression to compile this, // else the comma in the capture will be parsed as divider of macro args. CALL_LAMBDA(([&ptr, str] () mutable { TO_NULL(&ptr); })); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // FIXME: Why does the expansion appear twice? // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line376 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameCALL_LAMBDA(([&ptr, str] () mutable { TO_NULL(&ptr); })) // CHECK-NEXT: expansion([&ptr ,str ]()mutable {setToNull (&ptr );})() // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line376 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameCALL_LAMBDA(([&ptr, str] () mutable { TO_NULL(&ptr); })) // CHECK-NEXT: expansion([&ptr ,str ]()mutable {setToNull (&ptr );})() // CHECK-NEXT: // CHECK-NEXT: #define PASTE_CODE(code) \ code void commaInBracesTest() { PASTE_CODE({ // expected-warning{{Dereference of null pointer}} // NOTE: If we were to add a new variable here after a comma, we'd get a // compilation error, so this test is mainly here to show that this was also // investigated. // // int *ptr = nullptr, a; int *ptr = nullptr; *ptr = 5; }) } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line408 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: namePASTE_CODE({ // expected- // CHECK-NEXT: // NOTE: If we were to add a new variable here after a comma, we'd get a // CHECK-NEXT: // compilation error, so this test is mainly here to show that this was also // CHECK-NEXT: // investigated. // CHECK-NEXT: // // CHECK-NEXT: // int *ptr = nullptr, a; // CHECK-NEXT: int *ptr = nullptr; // CHECK-NEXT: *ptr = 5; // CHECK-NEXT: }) // CHECK-NEXT: expansion{int *ptr =nullptr ;*ptr =5;} // CHECK-NEXT: // CHECK-NEXT: // Example taken from // https://gcc.gnu.org/onlinedocs/cpp/Macro-Arguments.html#Macro-Arguments. #define POTENTIALLY_EMPTY_PARAM(x, y) \ x; \ y = nullptr void emptyParamTest() { int *ptr; POTENTIALLY_EMPTY_PARAM(,ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line451 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: namePOTENTIALLY_EMPTY_PARAM(,ptr) // CHECK-NEXT: expansion;ptr =nullptr // CHECK-NEXT: // CHECK-NEXT: #define NESTED_EMPTY_PARAM(a, b) \ POTENTIALLY_EMPTY_PARAM(a, b); void nestedEmptyParamTest() { int *ptr; NESTED_EMPTY_PARAM(, ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line476 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameNESTED_EMPTY_PARAM(, ptr) // CHECK-NEXT: expansion;ptr =nullptr ; // CHECK-NEXT: // CHECK-NEXT: #define CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(func, param) \ CALL_FUNCTION(func(param)) void lParenRParenInNestedMacro() { int *ptr; CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(setToNull, &ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line499 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameCALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(setToNull, &ptr) // CHECK-NEXT: expansionsetToNull (&ptr ) // CHECK-NEXT: // CHECK-NEXT: //===----------------------------------------------------------------------===// // Tests for variadic macro arguments. //===----------------------------------------------------------------------===// template void variadicFunc(Args ...args); #define VARIADIC_SET_TO_NULL(ptr, ...) \ ptr = nullptr; \ variadicFunc(__VA_ARGS__) void variadicMacroArgumentTest() { int *ptr; VARIADIC_SET_TO_NULL(ptr, 1, 5, "haha!"); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line530 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameVARIADIC_SET_TO_NULL(ptr, 1, 5, "haha!") // CHECK-NEXT: expansionptr =nullptr ;variadicFunc (1,5,"haha!") // CHECK-NEXT: // CHECK-NEXT: void variadicMacroArgumentWithoutAnyArgumentTest() { int *ptr; // Not adding a single parameter to ... is silly (and also causes a // preprocessor warning), but is not an excuse to crash on it. VARIADIC_SET_TO_NULL(ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line552 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameVARIADIC_SET_TO_NULL(ptr) // CHECK-NEXT: expansionptr =nullptr ;variadicFunc () // CHECK-NEXT: // CHECK-NEXT: //===----------------------------------------------------------------------===// // Tests for # and ##. //===----------------------------------------------------------------------===// #define DECLARE_FUNC_AND_SET_TO_NULL(funcName, ptr) \ void generated_##funcName(); \ ptr = nullptr; void hashHashOperatorTest() { int *ptr; DECLARE_FUNC_AND_SET_TO_NULL(whatever, ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line580 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameDECLARE_FUNC_AND_SET_TO_NULL(whatever, ptr) // CHECK-NEXT: expansionvoid generated_whatever ();ptr =nullptr ; // CHECK-NEXT: // CHECK-NEXT: void macroArgContainsHashHashInStringTest() { int *a; TO_NULL_AND_PRINT(a, "Will this ## cause a crash?"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line600 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameTO_NULL_AND_PRINT(a, "Will this ## cause a crash?") // CHECK-NEXT: expansiona =0;print ("Will this ## cause a crash?") // CHECK-NEXT: // CHECK-NEXT: #define PRINT_STR(str, ptr) \ print(#str); \ ptr = nullptr void hashOperatorTest() { int *ptr; PRINT_STR(Hello, ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line624 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: namePRINT_STR(Hello, ptr) // CHECK-NEXT: expansionprint ("Hello");ptr =nullptr // CHECK-NEXT: // CHECK-NEXT: void macroArgContainsHashInStringTest() { int *a; TO_NULL_AND_PRINT(a, "Will this # cause a crash?"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line644 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameTO_NULL_AND_PRINT(a, "Will this # cause a crash?") // CHECK-NEXT: expansiona =0;print ("Will this # cause a crash?") // CHECK-NEXT: // CHECK-NEXT: //===----------------------------------------------------------------------===// // Tests for more complex macro expansions. // // We won't cover anything that wasn't covered up to this point, but rather // show more complex, macros with deeper nesting, more arguments (some unused) // and so on. //===----------------------------------------------------------------------===// #define IF(Condition) \ if ( Condition ) #define L_BRACE { #define R_BRACE } #define LESS < #define GREATER > #define EQUALS = #define SEMICOLON ; #define NEGATIVE - #define RETURN return #define ZERO 0 #define EUCLIDEAN_ALGORITHM(A, B) \ IF(A LESS ZERO) L_BRACE \ A EQUALS NEGATIVE A SEMICOLON \ R_BRACE \ IF(B LESS ZERO) L_BRACE \ B EQUALS NEGATIVE B SEMICOLON \ R_BRACE \ \ /* This is where a while loop would be, but that seems to be too complex */ \ /* for the analyzer just yet. Let's just pretend that this algorithm */ \ /* works. */ \ \ RETURN B / (B - B) SEMICOLON int getLowestCommonDenominator(int A, int B) { EUCLIDEAN_ALGORITHM(A, B) // expected-warning{{Division by zero}} } void testVeryComplexAlgorithm() { int tmp = 8 / (getLowestCommonDenominator(5, 7) - 1); print(&tmp); } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line698 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameEUCLIDEAN_ALGORITHM(A, B) // CHECK-NEXT: expansionif (A <0){A =-A ;}if (B <0){B =-B ;}return B /(B -B ); // CHECK-NEXT: // CHECK-NEXT: #define YET_ANOTHER_SET_TO_NULL(x, y, z) \ print((void *) x); \ print((void *) y); \ z = nullptr; #define DO_NOTHING(str) str #define DO_NOTHING2(str2) DO_NOTHING(str2) void test() { int *ptr; YET_ANOTHER_SET_TO_NULL(5, DO_NOTHING2("Remember the Vasa"), ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line730 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameYET_ANOTHER_SET_TO_NULL(5, DO_NOTHING2("Remember the Vasa"), ptr) // CHECK-NEXT: expansionprint ((void *)5);print ((void *)"Remember the Vasa");ptr =nullptr ; // CHECK-NEXT: // CHECK-NEXT: int garbage_value; #define REC_MACRO_FUNC(REC_MACRO_PARAM) garbage_##REC_MACRO_PARAM #define value REC_MACRO_FUNC(value) void recursiveMacroUser() { if (value == 0) 1 / value; // expected-warning{{Division by zero}} // expected-warning@-1{{expression result unused}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line754 // CHECK-NEXT: col7 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: namevalue // CHECK-NEXT: expansiongarbage_value // CHECK-NEXT: // CHECK-NEXT: #define FOO(x) int foo() { return x; } #define APPLY_ZERO1(function) function(0) APPLY_ZERO1(FOO) void useZeroApplier1() { (void)(1 / foo()); } // expected-warning{{Division by zero}} // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line776 // CHECK-NEXT: col1 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameAPPLY_ZERO1(FOO) // CHECK-NEXT: expansionint foo (){return 0;} // CHECK-NEXT: // CHECK-NEXT: #define BAR(x) int bar() { return x; } #define APPLY_ZERO2 BAR(0) APPLY_ZERO2 void useZeroApplier2() { (void)(1 / bar()); } // expected-warning{{Division by zero}} // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line796 // CHECK-NEXT: col1 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameAPPLY_ZERO2 // CHECK-NEXT: expansionint bar (){return 0;} // CHECK-NEXT: // CHECK-NEXT: void foo(int &x, const char *str); #define PARAMS_RESOLVE_TO_VA_ARGS(i, fmt) foo(i, fmt); \ i = 0; #define DISPATCH(...) PARAMS_RESOLVE_TO_VA_ARGS(__VA_ARGS__); void mulitpleParamsResolveToVA_ARGS(void) { int x = 1; DISPATCH(x, "LF1M healer"); (void)(10 / x); // expected-warning{{Division by zero}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line821 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameDISPATCH(x, "LF1M healer") // CHECK-NEXT: expansionfoo (x ,"LF1M healer");x =0;; // CHECK-NEXT: // CHECK-NEXT: void variadicCFunction(int &x, const char *str, ...); #define CONCAT_VA_ARGS(i, fmt, ...) variadicCFunction(i, fmt, ##__VA_ARGS__); \ i = 0; void concatVA_ARGS(void) { int x = 1; CONCAT_VA_ARGS(x, "You need to construct additional pylons.", 'c', 9); (void)(10 / x); // expected-warning{{Division by zero}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line846 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameCONCAT_VA_ARGS(x, "You need to construct additional pylons.", 'c', 9) // CHECK-NEXT: expansionvariadicCFunction (x ,"You need to construct additional pylons.",'c',9);x =0; // CHECK-NEXT: // CHECK-NEXT: void concatVA_ARGSEmpty(void) { int x = 1; CONCAT_VA_ARGS(x, "You need to construct"); (void)(10 / x); // expected-warning{{Division by zero}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line866 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameCONCAT_VA_ARGS(x, "You need to construct") // CHECK-NEXT: expansionvariadicCFunction (x ,"You need to construct");x =0; // CHECK-NEXT: // CHECK-NEXT: #define STRINGIFIED_VA_ARGS(i, fmt, ...) variadicCFunction(i, fmt, #__VA_ARGS__); \ i = 0; void stringifyVA_ARGS(void) { int x = 1; STRINGIFIED_VA_ARGS(x, "Additional supply depots required.", 'a', 10); (void)(10 / x); // expected-warning{{Division by zero}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line889 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameSTRINGIFIED_VA_ARGS(x, "Additional supply depots required.", 'a', 10) // CHECK-NEXT: expansionvariadicCFunction (x ,"Additional supply depots required.","'a', 10");x =0; // CHECK-NEXT: // CHECK-NEXT: void stringifyVA_ARGSEmpty(void) { int x = 1; STRINGIFIED_VA_ARGS(x, "Additional supply depots required."); (void)(10 / x); // expected-warning{{Division by zero}} } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line909 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameSTRINGIFIED_VA_ARGS(x, "Additional supply depots required.") // CHECK-NEXT: expansionvariadicCFunction (x ,"Additional supply depots required.","");x =0; // CHECK-NEXT: // CHECK-NEXT: // bz44493: Support GNU-style named variadic arguments in plister #define BZ44493_GNUVA(i, args...) --(i); int bz44493(void) { int a = 2; BZ44493_GNUVA(a); BZ44493_GNUVA(a, "arg2"); (void)(10 / a); // expected-warning{{Division by zero}} return 0; } // CHECK: macro_expansions // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line933 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: nameBZ44493_GNUVA(a, "arg2") // CHECK-NEXT: expansion--(a ); // CHECK-NEXT: // CHECK-NEXT: