Skip to content

Commit e941a2e

Browse files
authored
Added support for __VA_OPT__ expansion (#329)
1 parent edb7b86 commit e941a2e

2 files changed

Lines changed: 105 additions & 0 deletions

File tree

simplecpp.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,24 @@ namespace simplecpp {
19591959
// Macro parameter..
19601960
{
19611961
TokenList temp(files);
1962+
if (tok->str() == "__VA_OPT__") {
1963+
if (sameline(tok, tok->next) && tok->next->str() == "(") {
1964+
tok = tok->next;
1965+
int paren = 1;
1966+
while (sameline(tok, tok->next)) {
1967+
if (tok->next->str() == "(")
1968+
++paren;
1969+
else if (tok->next->str() == ")")
1970+
--paren;
1971+
if (paren == 0)
1972+
return tok->next->next;
1973+
tok = tok->next;
1974+
if (parametertokens.front()->next->str() != ")" && parametertokens.size() > args.size())
1975+
tok = expandToken(output, loc, tok, macros, expandedmacros, parametertokens)->previous;
1976+
}
1977+
}
1978+
throw Error(tok->location, "Missing parenthesis for __VA_OPT__(content)");
1979+
}
19621980
if (expandArg(&temp, tok, loc, macros, expandedmacros, parametertokens)) {
19631981
if (tok->str() == "__VA_ARGS__" && temp.empty() && output->cback() && output->cback()->str() == "," &&
19641982
tok->nextSkipComments() && tok->nextSkipComments()->str() == ")")

test.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,88 @@ static void define_va_args_4() // cppcheck trac #9754
820820
ASSERT_EQUALS("\nprintf ( 1 , 2 )", preprocess(code));
821821
}
822822

823+
static void define_va_opt_1()
824+
{
825+
const char code[] = "#define p1(fmt, args...) printf(fmt __VA_OPT__(,) args)\n"
826+
"p1(\"hello\");\n"
827+
"p1(\"%s\", \"hello\");\n";
828+
829+
ASSERT_EQUALS("\nprintf ( \"hello\" ) ;\n"
830+
"printf ( \"%s\" , \"hello\" ) ;",
831+
preprocess(code));
832+
}
833+
834+
static void define_va_opt_2()
835+
{
836+
const char code[] = "#define err(...)\\\n"
837+
"__VA_OPT__(\\\n"
838+
"printf(__VA_ARGS__);\\\n"
839+
")\n"
840+
"#define err2(something, ...) __VA_OPT__(err(__VA_ARGS__))\n"
841+
"err2(test)\n"
842+
"err2(test, \"%d\", 2)\n";
843+
844+
ASSERT_EQUALS("\n\n\n\n\n\nprintf ( \"%d\" , 2 ) ;", preprocess(code));
845+
}
846+
847+
static void define_va_opt_3()
848+
{
849+
// non-escaped newline without closing parenthesis
850+
const char code1[] = "#define err(...) __VA_OPT__(printf( __VA_ARGS__);\n"
851+
")\n"
852+
"err()";
853+
854+
simplecpp::OutputList outputList;
855+
ASSERT_EQUALS("", preprocess(code1, &outputList));
856+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'err', Missing parenthesis for __VA_OPT__(content)\n",
857+
toString(outputList));
858+
859+
outputList.clear();
860+
861+
// non-escaped newline without open parenthesis
862+
const char code2[] = "#define err(...) __VA_OPT__\n"
863+
"(something)\n"
864+
"err()";
865+
866+
ASSERT_EQUALS("", preprocess(code2, &outputList));
867+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'err', Missing parenthesis for __VA_OPT__(content)\n",
868+
toString(outputList));
869+
}
870+
871+
static void define_va_opt_4()
872+
{
873+
// missing parenthesis
874+
const char code1[] = "#define err(...) __VA_OPT__ something\n"
875+
"err()";
876+
877+
simplecpp::OutputList outputList;
878+
ASSERT_EQUALS("", preprocess(code1, &outputList));
879+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'err', Missing parenthesis for __VA_OPT__(content)\n",
880+
toString(outputList));
881+
882+
outputList.clear();
883+
884+
// missing open parenthesis
885+
const char code2[] = "#define err(...) __VA_OPT__ something)\n"
886+
"err()";
887+
888+
ASSERT_EQUALS("", preprocess(code2, &outputList));
889+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'err', Missing parenthesis for __VA_OPT__(content)\n",
890+
toString(outputList));
891+
}
892+
893+
static void define_va_opt_5()
894+
{
895+
// parenthesis not directly proceeding __VA_OPT__
896+
const char code[] = "#define err(...) __VA_OPT__ something (something)\n"
897+
"err()";
898+
899+
simplecpp::OutputList outputList;
900+
ASSERT_EQUALS("", preprocess(code, &outputList));
901+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'err', Missing parenthesis for __VA_OPT__(content)\n",
902+
toString(outputList));
903+
}
904+
823905
static void define_ifdef()
824906
{
825907
const char code[] = "#define A(X) X\n"
@@ -2694,6 +2776,11 @@ int main(int argc, char **argv)
26942776
TEST_CASE(define_va_args_2);
26952777
TEST_CASE(define_va_args_3);
26962778
TEST_CASE(define_va_args_4);
2779+
TEST_CASE(define_va_opt_1);
2780+
TEST_CASE(define_va_opt_2);
2781+
TEST_CASE(define_va_opt_3);
2782+
TEST_CASE(define_va_opt_4);
2783+
TEST_CASE(define_va_opt_5);
26972784

26982785
// UB: #ifdef as macro parameter
26992786
TEST_CASE(define_ifdef);

0 commit comments

Comments
 (0)