forked from OSchip/llvm-project
951 lines
33 KiB
C++
951 lines
33 KiB
C++
// 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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>18</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>SET_PTR_VAR_TO_NULL</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>ptr =0</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>42</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>ptr =0</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// 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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>73</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>TO_NULL(&ptr)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>setToNull (&ptr )</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>104</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>TO_NULL(&a)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>setToNull (&a )</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>105</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>DEREF(a)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>{int b ;b =5;}print (a );*a </string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// 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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>141</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>WILL_UNDEF_SET_NULL_TO_PTR(ptr)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>ptr =nullptr ;</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>169</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>ptr =nullptr ;</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>200</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>ptr =nullptr ;</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>237</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>TO_NULL_AND_PRINT(a, "Will this , cause a crash?")</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>a =0;print ("Will this , cause a crash?")</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
void macroArgContainsLParenInStringTest() {
|
|
int *a;
|
|
TO_NULL_AND_PRINT(a, "Will this ( cause a crash?");
|
|
*a = 5; // expected-warning{{Dereference of null pointer}}
|
|
}
|
|
|
|
// CHECK: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>257</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>TO_NULL_AND_PRINT(a, "Will this ( cause a crash?")</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>a =0;print ("Will this ( cause a crash?")</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
void macroArgContainsRParenInStringTest() {
|
|
int *a;
|
|
TO_NULL_AND_PRINT(a, "Will this ) cause a crash?");
|
|
*a = 5; // expected-warning{{Dereference of null pointer}}
|
|
}
|
|
|
|
// CHECK: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>277</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>TO_NULL_AND_PRINT(a, "Will this ) cause a crash?")</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>a =0;print ("Will this ) cause a crash?")</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>302</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>CALL_FUNCTION(setToNull(&a))</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>setToNull (&a )</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>327</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>CALL_FUNCTION(setToNullAndPrint(&a, "Hello!"))</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>setToNullAndPrint (&a ,"Hello!")</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>350</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>CALL_FUNCTION_WITH_TWO_PARAMS(setToNullAndPrint, &a, "Hello!")</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>setToNullAndPrint (&a ,"Hello!")</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>376</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>CALL_LAMBDA(([&ptr, str] () mutable { TO_NULL(&ptr); }))</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>([&ptr ,str ]()mutable {setToNull (&ptr );})()</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>376</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>CALL_LAMBDA(([&ptr, str] () mutable { TO_NULL(&ptr); }))</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>([&ptr ,str ]()mutable {setToNull (&ptr );})()</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>408</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>PASTE_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: })</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>{int *ptr =nullptr ;*ptr =5;}</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
// 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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>451</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>POTENTIALLY_EMPTY_PARAM(,ptr)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>;ptr =nullptr </string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>476</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>NESTED_EMPTY_PARAM(, ptr)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>;ptr =nullptr ;</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>499</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(setToNull, &ptr)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>setToNull (&ptr )</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Tests for variadic macro arguments.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
template <typename ...Args>
|
|
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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>530</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>VARIADIC_SET_TO_NULL(ptr, 1, 5, "haha!")</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>ptr =nullptr ;variadicFunc (1,5,"haha!")</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>552</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>VARIADIC_SET_TO_NULL(ptr)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>ptr =nullptr ;variadicFunc ()</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// 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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>580</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>DECLARE_FUNC_AND_SET_TO_NULL(whatever, ptr)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>void generated_whatever ();ptr =nullptr ;</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
void macroArgContainsHashHashInStringTest() {
|
|
int *a;
|
|
TO_NULL_AND_PRINT(a, "Will this ## cause a crash?");
|
|
*a = 5; // expected-warning{{Dereference of null pointer}}
|
|
}
|
|
|
|
// CHECK: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>600</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>TO_NULL_AND_PRINT(a, "Will this ## cause a crash?")</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>a =0;print ("Will this ## cause a crash?")</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>624</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>PRINT_STR(Hello, ptr)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>print ("Hello");ptr =nullptr </string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
void macroArgContainsHashInStringTest() {
|
|
int *a;
|
|
TO_NULL_AND_PRINT(a, "Will this # cause a crash?");
|
|
*a = 5; // expected-warning{{Dereference of null pointer}}
|
|
}
|
|
|
|
// CHECK: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>644</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>TO_NULL_AND_PRINT(a, "Will this # cause a crash?")</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>a =0;print ("Will this # cause a crash?")</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// 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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>698</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>EUCLIDEAN_ALGORITHM(A, B)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>if (A <0){A =-A ;}if (B <0){B =-B ;}return B /(B -B );</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>730</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>YET_ANOTHER_SET_TO_NULL(5, DO_NOTHING2("Remember the Vasa"), ptr)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>print ((void *)5);print ((void *)"Remember the Vasa");ptr =nullptr ;</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>754</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>7</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>value</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>garbage_value </string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>776</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>APPLY_ZERO1(FOO)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>int foo (){return 0;}</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>796</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>APPLY_ZERO2</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>int bar (){return 0;}</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>821</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>DISPATCH(x, "LF1M healer")</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>foo (x ,"LF1M healer");x =0;;</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>846</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>CONCAT_VA_ARGS(x, "You need to construct additional pylons.", 'c', 9)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>variadicCFunction (x ,"You need to construct additional pylons.",'c',9);x =0;</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
void concatVA_ARGSEmpty(void) {
|
|
int x = 1;
|
|
CONCAT_VA_ARGS(x, "You need to construct");
|
|
(void)(10 / x); // expected-warning{{Division by zero}}
|
|
}
|
|
|
|
// CHECK: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>866</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>CONCAT_VA_ARGS(x, "You need to construct")</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>variadicCFunction (x ,"You need to construct");x =0;</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
#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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>889</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>STRINGIFIED_VA_ARGS(x, "Additional supply depots required.", 'a', 10)</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>variadicCFunction (x ,"Additional supply depots required.","'a', 10");x =0;</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
void stringifyVA_ARGSEmpty(void) {
|
|
int x = 1;
|
|
STRINGIFIED_VA_ARGS(x, "Additional supply depots required.");
|
|
(void)(10 / x); // expected-warning{{Division by zero}}
|
|
}
|
|
|
|
// CHECK: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>909</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>STRINGIFIED_VA_ARGS(x, "Additional supply depots required.")</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>variadicCFunction (x ,"Additional supply depots required.","");x =0;</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|
|
|
|
// 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: <key>macro_expansions</key>
|
|
// CHECK-NEXT: <array>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>location</key>
|
|
// CHECK-NEXT: <dict>
|
|
// CHECK-NEXT: <key>line</key><integer>933</integer>
|
|
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
|
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: <key>name</key><string>BZ44493_GNUVA(a, "arg2")</string>
|
|
// CHECK-NEXT: <key>expansion</key><string>--(a );</string>
|
|
// CHECK-NEXT: </dict>
|
|
// CHECK-NEXT: </array>
|