Skip to content

Commit 74a5a63

Browse files
authored
Fix rescanning when a macro expansion result forms a new function-like macro call (#682)
1 parent f420e61 commit 74a5a63

2 files changed

Lines changed: 70 additions & 29 deletions

File tree

simplecpp.cpp

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1707,7 +1707,7 @@ namespace simplecpp {
17071707
if (output2.cfront() != output2.cback() && macro2tok->str() == this->name())
17081708
break;
17091709
const MacroMap::const_iterator macro = macros.find(macro2tok->str());
1710-
if (macro == macros.end() || !macro->second.functionLike())
1710+
if (macro == macros.end() || !macro->second.functionLike() || macro2tok->isExpandedFrom(&macro->second))
17111711
break;
17121712
TokenList rawtokens2(inputFiles);
17131713
const Location loc(macro2tok->location);
@@ -2161,39 +2161,37 @@ namespace simplecpp {
21612161
return functionLike() ? parametertokens2.back()->next : nameTokInst->next;
21622162
}
21632163

2164-
const Token *recursiveExpandToken(TokenList &output, TokenList &temp, const Location &loc, const Token *tok, const MacroMap &macros, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> &parametertokens) const {
2165-
if (!temp.cback() || !temp.cback()->name || !tok->next || tok->next->op != '(') {
2166-
output.takeTokens(temp);
2167-
return tok->next;
2168-
}
2169-
2170-
if (!sameline(tok, tok->next)) {
2171-
output.takeTokens(temp);
2172-
return tok->next;
2173-
}
2174-
2164+
/** Returns the macro to expand when the last token of @p temp is the name of a
2165+
* function-like macro and the tokens after @p tok supply its arguments; nullptr otherwise */
2166+
static const Macro *rescanMacro(const TokenList &temp, const Token *tok, const MacroMap &macros, const std::set<TokenString> &expandedmacros) {
2167+
if (!temp.cback() || !temp.cback()->name || !sameline(tok, tok->next) || tok->next->op != '(')
2168+
return nullptr;
21752169
const MacroMap::const_iterator it = macros.find(temp.cback()->str());
2176-
if (it == macros.end() || expandedmacros.find(temp.cback()->str()) != expandedmacros.end()) {
2177-
output.takeTokens(temp);
2178-
return tok->next;
2179-
}
2170+
if (it == macros.end() || expandedmacros.find(temp.cback()->str()) != expandedmacros.end())
2171+
return nullptr;
2172+
if (!it->second.functionLike() || temp.cback()->isExpandedFrom(&it->second))
2173+
return nullptr;
2174+
return &it->second;
2175+
}
21802176

2181-
const Macro &calledMacro = it->second;
2182-
if (!calledMacro.functionLike()) {
2177+
const Token *recursiveExpandToken(TokenList &output, TokenList &temp, const Location &loc, const Token *tok, const MacroMap &macros, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> &parametertokens) const {
2178+
// Expand while the expansion result ends with the name of a function-like
2179+
// macro whose arguments are supplied by the tokens that follow it. Each round
2180+
// consumes that macro call from the token stream, so tok always advances.
2181+
while (const Macro * const calledMacro = rescanMacro(temp, tok, macros, expandedmacros)) {
2182+
TokenList temp2(files);
2183+
temp2.push_back(new Token(temp.cback()->str(), tok->location));
2184+
2185+
const Token * const tok2 = appendTokens(temp2, loc, tok->next, macros, expandedmacros, parametertokens);
2186+
if (!tok2)
2187+
break;
21832188
output.takeTokens(temp);
2184-
return tok->next;
2189+
output.deleteToken(output.back());
2190+
calledMacro->expand(temp, loc, temp2.cfront(), macros, expandedmacros);
2191+
tok = tok2;
21852192
}
2186-
2187-
TokenList temp2(files);
2188-
temp2.push_back(new Token(temp.cback()->str(), tok->location));
2189-
2190-
const Token * const tok2 = appendTokens(temp2, loc, tok->next, macros, expandedmacros, parametertokens);
2191-
if (!tok2)
2192-
return tok->next;
21932193
output.takeTokens(temp);
2194-
output.deleteToken(output.back());
2195-
calledMacro.expand(output, loc, temp2.cfront(), macros, expandedmacros);
2196-
return tok2->next;
2194+
return tok->next;
21972195
}
21982196

21992197
const Token *expandToken(TokenList &output, const Location &loc, const Token *tok, const MacroMap &macros, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> &parametertokens) const {

test.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,46 @@ static void define23() // #40
949949
"unsigned A , B ;", preprocess(code));
950950
}
951951

952+
static void define24()
953+
{
954+
// an expansion result that is a function-like macro name must be rescanned
955+
// repeatedly against the tokens that follow it
956+
const char code[] = "#define a(b, c) c\n"
957+
"#define d() a\n"
958+
"#define g(e) h(e, ) h(e, )\n"
959+
"#define h(e, b) d()(, e)()\n"
960+
"#define i()\n"
961+
"g(i)\n";
962+
ASSERT_EQUALS("", preprocess(code));
963+
}
964+
965+
static void define25()
966+
{
967+
// a macro name that came from expanding that same macro must not be
968+
// re-expanded when rescanned with the tokens that follow it
969+
const char code[] = "#define f() f\n"
970+
"#define wrap(x) x()\n"
971+
"wrap(f())\n";
972+
ASSERT_EQUALS("\n"
973+
"\n"
974+
"f ( )", preprocess(code));
975+
}
976+
977+
static void define26()
978+
{
979+
// a macro name that came from expanding that same macro must not be
980+
// re-expanded with arguments taken from the raw token stream
981+
const char code[] = "#define f() f\n"
982+
"f()()\n";
983+
ASSERT_EQUALS("\n"
984+
"f ( )", preprocess(code));
985+
986+
const char code2[] = "#define f() f\n"
987+
"f()()()\n";
988+
ASSERT_EQUALS("\n"
989+
"f ( ) ( )", preprocess(code2));
990+
}
991+
952992

953993
static void define_invalid_1()
954994
{
@@ -4520,6 +4560,9 @@ static void runTests(int argc, char **argv, Input input)
45204560
TEST_CASE(define21); // #66
45214561
TEST_CASE(define22); // #40
45224562
TEST_CASE(define23); // #40
4563+
TEST_CASE(define24);
4564+
TEST_CASE(define25);
4565+
TEST_CASE(define26);
45234566
TEST_CASE(define_invalid_1);
45244567
TEST_CASE(define_invalid_2);
45254568
TEST_CASE(define_invalid_3);

0 commit comments

Comments
 (0)