Skip to content

Commit

Permalink
Merge pull request #396 from danmar/fix-395
Browse files Browse the repository at this point in the history
  • Loading branch information
danmar authored Dec 11, 2024
2 parents bacd5bd + 0b6feab commit d4323f7
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 4 deletions.
31 changes: 27 additions & 4 deletions simplecpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,15 @@ template<class T> static std::string toString(T t)
return ostr.str();
}

#ifdef SIMPLECPP_DEBUG_MACRO_EXPANSION
static std::string locstring(const simplecpp::Location &loc)
{
std::ostringstream ostr;
ostr << '[' << loc.file() << ':' << loc.line << ':' << loc.col << ']';
return ostr.str();
}
#endif

static long long stringToLL(const std::string &s)
{
long long ret;
Expand Down Expand Up @@ -1528,6 +1537,10 @@ namespace simplecpp {
std::vector<std::string> &inputFiles) const {
std::set<TokenString> expandedmacros;

#ifdef SIMPLECPP_DEBUG_MACRO_EXPANSION
std::cout << "expand " << name() << " " << locstring(rawtok->location) << std::endl;
#endif

TokenList output2(inputFiles);

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

#ifdef SIMPLECPP_DEBUG_MACRO_EXPANSION
std::cout << " expand " << name() << " " << locstring(defineLocation()) << std::endl;
#endif

usageList.push_back(loc);

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

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

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

if (canBeConcatenatedStringOrChar) {
if (unexpectedA)
throw invalidHashHash::unexpectedToken(tok->location, name(), A);

// It seems clearer to handle this case separately even though the code is similar-ish, but we don't want to merge here.
// TODO The question is whether the ## or varargs may still apply, and how to provoke?
if (expandArg(&tokensB, B, parametertokens)) {
Expand All @@ -2205,13 +2224,17 @@ namespace simplecpp {
if (expandArg(&tokensB, B, parametertokens)) {
if (tokensB.empty())
strAB = A->str();
else if (varargs && A->op == ',') {
else if (varargs && A->op == ',')
strAB = ",";
} else {
else if (varargs && unexpectedA)
throw invalidHashHash::unexpectedToken(tok->location, name(), A);
else {
strAB = A->str() + tokensB.cfront()->str();
tokensB.deleteToken(tokensB.front());
}
} else {
if (unexpectedA)
throw invalidHashHash::unexpectedToken(tok->location, name(), A);
strAB = A->str() + B->str();
}

Expand Down
12 changes: 12 additions & 0 deletions test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,17 @@ static void hashhash_null_stmt()
ASSERT_EQUALS("\n\n\n\n1 ;", preprocess(code, &outputList));
}

static void hashhash_empty_va_args()
{
// #395 hash hash with an empty __VA_ARGS__ in a macro
const char code[] =
"#define CAT(a, ...) a##__VA_ARGS__\n"
"#define X(a, ...) CAT(a)\n"
"#define LEVEL_2 (2)\n"
"X(LEVEL_2)\n";
ASSERT_EQUALS("\n\n\n( 2 )", preprocess(code));
}

static void hashhash_universal_character()
{
const char code[] =
Expand Down Expand Up @@ -3044,6 +3055,7 @@ int main(int argc, char **argv)
TEST_CASE(hashhash_invalid_string_number);
TEST_CASE(hashhash_invalid_missing_args);
TEST_CASE(hashhash_null_stmt);
TEST_CASE(hashhash_empty_va_args);
// C standard, 5.1.1.2, paragraph 4:
// If a character sequence that matches the syntax of a universal
// character name is produced by token concatenation (6.10.3.3),
Expand Down

0 comments on commit d4323f7

Please sign in to comment.