Skip to content

Commit 452996c

Browse files
Show more details for invalid ## usage (#256)
1 parent e7d85ea commit 452996c

2 files changed

Lines changed: 48 additions & 20 deletions

File tree

simplecpp.cpp

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,8 +1446,8 @@ namespace simplecpp {
14461446
/** base class for errors */
14471447
struct Error {
14481448
Error(const Location &loc, const std::string &s) : location(loc), what(s) {}
1449-
Location location;
1450-
std::string what;
1449+
const Location location;
1450+
const std::string what;
14511451
};
14521452

14531453
/** Struct that is thrown when macro is expanded with wrong number of parameters */
@@ -1457,7 +1457,24 @@ namespace simplecpp {
14571457

14581458
/** Struct that is thrown when there is invalid ## usage */
14591459
struct invalidHashHash : public Error {
1460-
invalidHashHash(const Location &loc, const std::string &macroName) : Error(loc, "Invalid ## usage when expanding \'" + macroName + "\'.") {}
1460+
static inline std::string format(const std::string &macroName, const std::string &message) {
1461+
return "Invalid ## usage when expanding \'" + macroName + "\': " + message;
1462+
}
1463+
1464+
invalidHashHash(const Location &loc, const std::string &macroName, const std::string &message)
1465+
: Error(loc, format(macroName, message)) { }
1466+
1467+
static inline invalidHashHash unexpectedToken(const Location &loc, const std::string &macroName, const Token *tokenA) {
1468+
return invalidHashHash(loc, macroName, "Unexpected token '"+ tokenA->str()+"'");
1469+
}
1470+
1471+
static inline invalidHashHash cannotCombine(const Location &loc, const std::string &macroName, const Token *tokenA, const Token *tokenB) {
1472+
return invalidHashHash(loc, macroName, "Pasting '"+ tokenA->str()+ "' and '"+ tokenB->str() + "' yields an invalid token.");
1473+
}
1474+
1475+
static inline invalidHashHash unexpectedNewline(const Location &loc, const std::string &macroName) {
1476+
return invalidHashHash(loc, macroName, "Unexpected newline");
1477+
}
14611478
};
14621479
private:
14631480
/** Create new token where Token::macro is set for replaced tokens */
@@ -1681,7 +1698,7 @@ namespace simplecpp {
16811698
// A##B => AB
16821699
if (sameline(tok, tok->next) && tok->next && tok->next->op == '#' && tok->next->next && tok->next->next->op == '#') {
16831700
if (!sameline(tok, tok->next->next->next))
1684-
throw invalidHashHash(tok->location, name());
1701+
throw invalidHashHash::unexpectedNewline(tok->location, name());
16851702
TokenList new_output(files);
16861703
if (!expandArg(&new_output, tok, parametertokens2))
16871704
output->push_back(newMacroToken(tok->str(), loc, isReplaced(expandedmacros), tok));
@@ -1928,26 +1945,26 @@ namespace simplecpp {
19281945
const Token *expandHashHash(TokenList *output, const Location &loc, const Token *tok, const MacroMap &macros, const std::set<TokenString> &expandedmacros, const std::vector<const Token*> &parametertokens) const {
19291946
Token *A = output->back();
19301947
if (!A)
1931-
throw invalidHashHash(tok->location, name());
1948+
throw invalidHashHash(tok->location, name(), "Missing first argument");
19321949
if (!sameline(tok, tok->next) || !sameline(tok, tok->next->next))
1933-
throw invalidHashHash(tok->location, name());
1950+
throw invalidHashHash::unexpectedNewline(tok->location, name());
19341951

19351952
bool canBeConcatenatedWithEqual = A->isOneOf("+-*/%&|^") || A->str() == "<<" || A->str() == ">>";
19361953
bool canBeConcatenatedStringOrChar = isStringLiteral(A->str()) || isCharLiteral(A->str());
19371954
if (!A->name && !A->number && A->op != ',' && !A->str().empty() && !canBeConcatenatedWithEqual && !canBeConcatenatedStringOrChar)
1938-
throw invalidHashHash(tok->location, name());
1955+
throw invalidHashHash::unexpectedToken(tok->location, name(), A);
19391956

19401957
Token *B = tok->next->next;
19411958
if (!B->name && !B->number && B->op && !B->isOneOf("#="))
1942-
throw invalidHashHash(tok->location, name());
1959+
throw invalidHashHash::unexpectedToken(tok->location, name(), B);
19431960

19441961
if ((canBeConcatenatedWithEqual && B->op != '=') ||
19451962
(!canBeConcatenatedWithEqual && B->op == '='))
1946-
throw invalidHashHash(tok->location, name());
1963+
throw invalidHashHash::cannotCombine(tok->location, name(), A, B);
19471964

19481965
// Superficial check; more in-depth would in theory be possible _after_ expandArg
19491966
if (canBeConcatenatedStringOrChar && (B->number || !B->name))
1950-
throw invalidHashHash(tok->location, name());
1967+
throw invalidHashHash::cannotCombine(tok->location, name(), A, B);
19511968

19521969
TokenList tokensB(files);
19531970
const Token *nextTok = B->next;

test.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -846,11 +846,11 @@ static void garbage()
846846

847847
outputList.clear();
848848
ASSERT_EQUALS("", preprocess("#define TEST2() A ##\nTEST2()\n", &outputList));
849-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'TEST2', Invalid ## usage when expanding 'TEST2'.\n", toString(outputList));
849+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'TEST2', Invalid ## usage when expanding 'TEST2': Unexpected newline\n", toString(outputList));
850850

851851
outputList.clear();
852852
ASSERT_EQUALS("", preprocess("#define CON(a,b) a##b##\nCON(1,2)\n", &outputList));
853-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'CON', Invalid ## usage when expanding 'CON'.\n", toString(outputList));
853+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'CON', Invalid ## usage when expanding 'CON': Unexpected newline\n", toString(outputList));
854854
}
855855

856856
static void garbage_endif()
@@ -994,19 +994,19 @@ static void hashhash9()
994994
"A";
995995
outputList.clear();
996996
ASSERT_EQUALS("", preprocess(code, &outputList));
997-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'A', Invalid ## usage when expanding 'A'.\n", toString(outputList));
997+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'A', Invalid ## usage when expanding 'A': Pasting '+' and 'x' yields an invalid token.\n", toString(outputList));
998998

999999
code = "#define A 2##=\n"
10001000
"A";
10011001
outputList.clear();
10021002
ASSERT_EQUALS("", preprocess(code, &outputList));
1003-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'A', Invalid ## usage when expanding 'A'.\n", toString(outputList));
1003+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'A', Invalid ## usage when expanding 'A': Pasting '2' and '=' yields an invalid token.\n", toString(outputList));
10041004

10051005
code = "#define A <<##x\n"
10061006
"A";
10071007
outputList.clear();
10081008
ASSERT_EQUALS("", preprocess(code, &outputList));
1009-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'A', Invalid ## usage when expanding 'A'.\n", toString(outputList));
1009+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'A', Invalid ## usage when expanding 'A': Pasting '<<' and 'x' yields an invalid token.\n", toString(outputList));
10101010
}
10111011

10121012
static void hashhash10()
@@ -1175,25 +1175,35 @@ static void hashhash_invalid_1()
11751175
const char code[] = "#define f(a) (##x)\nf(1)";
11761176
simplecpp::OutputList outputList;
11771177
ASSERT_EQUALS("", preprocess(code, &outputList));
1178-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'f', Invalid ## usage when expanding 'f'.\n", toString(outputList));
1178+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'f', Invalid ## usage when expanding 'f': Unexpected token '('\n", toString(outputList));
11791179
}
11801180

11811181
static void hashhash_invalid_2()
11821182
{
11831183
const char code[] = "#define f(a) (x##)\nf(1)";
11841184
simplecpp::OutputList outputList;
11851185
ASSERT_EQUALS("", preprocess(code, &outputList));
1186-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'f', Invalid ## usage when expanding 'f'.\n", toString(outputList));
1186+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'f', Invalid ## usage when expanding 'f': Unexpected token ')'\n", toString(outputList));
11871187
}
11881188

1189-
static void hashhash_invalid_3()
1189+
static void hashhash_invalid_string_number()
11901190
{
11911191
const char code[] =
11921192
"#define BAD(x) x##12345\nBAD(\"ABC\")";
11931193

11941194
simplecpp::OutputList outputList;
11951195
preprocess(code, simplecpp::DUI(), &outputList);
1196-
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'BAD', Invalid ## usage when expanding 'BAD'.\n", toString(outputList));
1196+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'BAD', Invalid ## usage when expanding 'BAD': Pasting '\"ABC\"' and '12345' yields an invalid token.\n", toString(outputList));
1197+
}
1198+
1199+
static void hashhash_invalid_missing_args()
1200+
{
1201+
const char code[] =
1202+
"#define BAD(x) ##x\nBAD()";
1203+
1204+
simplecpp::OutputList outputList;
1205+
preprocess(code, simplecpp::DUI(), &outputList);
1206+
ASSERT_EQUALS("file0,1,syntax_error,failed to expand 'BAD', Invalid ## usage when expanding 'BAD': Missing first argument\n", toString(outputList));
11971207
}
11981208

11991209
static void has_include_1()
@@ -2427,7 +2437,8 @@ int main(int argc, char **argv)
24272437
TEST_CASE(hashhash_int_literal);
24282438
TEST_CASE(hashhash_invalid_1);
24292439
TEST_CASE(hashhash_invalid_2);
2430-
TEST_CASE(hashhash_invalid_3);
2440+
TEST_CASE(hashhash_invalid_string_number);
2441+
TEST_CASE(hashhash_invalid_missing_args);
24312442

24322443
// c++17 __has_include
24332444
TEST_CASE(has_include_1);

0 commit comments

Comments
 (0)