Skip to content

Commit d4323f7

Browse files
authored
Merge pull request #396 from danmar/fix-395
2 parents bacd5bd + 0b6feab commit d4323f7

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-4
lines changed

simplecpp.cpp

+27-4
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,15 @@ template<class T> static std::string toString(T t)
110110
return ostr.str();
111111
}
112112

113+
#ifdef SIMPLECPP_DEBUG_MACRO_EXPANSION
114+
static std::string locstring(const simplecpp::Location &loc)
115+
{
116+
std::ostringstream ostr;
117+
ostr << '[' << loc.file() << ':' << loc.line << ':' << loc.col << ']';
118+
return ostr.str();
119+
}
120+
#endif
121+
113122
static long long stringToLL(const std::string &s)
114123
{
115124
long long ret;
@@ -1528,6 +1537,10 @@ namespace simplecpp {
15281537
std::vector<std::string> &inputFiles) const {
15291538
std::set<TokenString> expandedmacros;
15301539

1540+
#ifdef SIMPLECPP_DEBUG_MACRO_EXPANSION
1541+
std::cout << "expand " << name() << " " << locstring(rawtok->location) << std::endl;
1542+
#endif
1543+
15311544
TokenList output2(inputFiles);
15321545

15331546
if (functionLike() && rawtok->next && rawtok->next->op == '(') {
@@ -1797,6 +1810,10 @@ namespace simplecpp {
17971810
const Token * expand(TokenList * const output, const Location &loc, const Token * const nameTokInst, const MacroMap &macros, std::set<TokenString> expandedmacros) const {
17981811
expandedmacros.insert(nameTokInst->str());
17991812

1813+
#ifdef SIMPLECPP_DEBUG_MACRO_EXPANSION
1814+
std::cout << " expand " << name() << " " << locstring(defineLocation()) << std::endl;
1815+
#endif
1816+
18001817
usageList.push_back(loc);
18011818

18021819
if (nameTokInst->str() == "__FILE__") {
@@ -2168,8 +2185,7 @@ namespace simplecpp {
21682185

21692186
const bool canBeConcatenatedWithEqual = A->isOneOf("+-*/%&|^") || A->str() == "<<" || A->str() == ">>";
21702187
const bool canBeConcatenatedStringOrChar = isStringLiteral_(A->str()) || isCharLiteral_(A->str());
2171-
if (!A->name && !A->number && A->op != ',' && !A->str().empty() && !canBeConcatenatedWithEqual && !canBeConcatenatedStringOrChar)
2172-
throw invalidHashHash::unexpectedToken(tok->location, name(), A);
2188+
const bool unexpectedA = (!A->name && !A->number && !A->str().empty() && !canBeConcatenatedWithEqual && !canBeConcatenatedStringOrChar);
21732189

21742190
Token * const B = tok->next->next;
21752191
if (!B->name && !B->number && B->op && !B->isOneOf("#="))
@@ -2187,6 +2203,9 @@ namespace simplecpp {
21872203
const Token *nextTok = B->next;
21882204

21892205
if (canBeConcatenatedStringOrChar) {
2206+
if (unexpectedA)
2207+
throw invalidHashHash::unexpectedToken(tok->location, name(), A);
2208+
21902209
// It seems clearer to handle this case separately even though the code is similar-ish, but we don't want to merge here.
21912210
// TODO The question is whether the ## or varargs may still apply, and how to provoke?
21922211
if (expandArg(&tokensB, B, parametertokens)) {
@@ -2205,13 +2224,17 @@ namespace simplecpp {
22052224
if (expandArg(&tokensB, B, parametertokens)) {
22062225
if (tokensB.empty())
22072226
strAB = A->str();
2208-
else if (varargs && A->op == ',') {
2227+
else if (varargs && A->op == ',')
22092228
strAB = ",";
2210-
} else {
2229+
else if (varargs && unexpectedA)
2230+
throw invalidHashHash::unexpectedToken(tok->location, name(), A);
2231+
else {
22112232
strAB = A->str() + tokensB.cfront()->str();
22122233
tokensB.deleteToken(tokensB.front());
22132234
}
22142235
} else {
2236+
if (unexpectedA)
2237+
throw invalidHashHash::unexpectedToken(tok->location, name(), A);
22152238
strAB = A->str() + B->str();
22162239
}
22172240

test.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,17 @@ static void hashhash_null_stmt()
14211421
ASSERT_EQUALS("\n\n\n\n1 ;", preprocess(code, &outputList));
14221422
}
14231423

1424+
static void hashhash_empty_va_args()
1425+
{
1426+
// #395 hash hash with an empty __VA_ARGS__ in a macro
1427+
const char code[] =
1428+
"#define CAT(a, ...) a##__VA_ARGS__\n"
1429+
"#define X(a, ...) CAT(a)\n"
1430+
"#define LEVEL_2 (2)\n"
1431+
"X(LEVEL_2)\n";
1432+
ASSERT_EQUALS("\n\n\n( 2 )", preprocess(code));
1433+
}
1434+
14241435
static void hashhash_universal_character()
14251436
{
14261437
const char code[] =
@@ -3044,6 +3055,7 @@ int main(int argc, char **argv)
30443055
TEST_CASE(hashhash_invalid_string_number);
30453056
TEST_CASE(hashhash_invalid_missing_args);
30463057
TEST_CASE(hashhash_null_stmt);
3058+
TEST_CASE(hashhash_empty_va_args);
30473059
// C standard, 5.1.1.2, paragraph 4:
30483060
// If a character sequence that matches the syntax of a universal
30493061
// character name is produced by token concatenation (6.10.3.3),

0 commit comments

Comments
 (0)