https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77723
Bug ID: 77723 Summary: Macro counts each element within brace-initialization as argument to macro Product: gcc Version: 6.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: preprocessor Assignee: unassigned at gcc dot gnu.org Reporter: jamespharvey20 at gmail dot com Target Milestone: --- [test.cpp] ---------- #define MAC(arg) arg class foo { public: foo(int a, int b) { }; }; int main() { foo x = MAC(foo(1,2)); foo y = MAC((foo{1,2})); foo z = MAC(foo{1,2}); } ---------- $ g++ -std=c++11 test.cpp test.cpp:11:25: error: macro "MAC" passed 2 arguments, but takes just 1 foo z = MAC(foo{5, 7}); ^ test.cpp: In function ‘int main()’: test.cpp:11:12: error: ‘MAC’ was not declared in this scope foo z = MAC(foo{5, 7}); ^~~ Note the brace-initialization on y and z. The preprocessor appears to know to not count commas within parentheses, but appears to count them within brace-initialization. Note y compiles because of the additional parentheses that encapsulate the construction. I saw a stackoverflow comment where someone said this is caused because the preprocessor standard was never updated after c++11's brace-initialization, and isn't aware of whether c++ or c++11 is even being used, so this is a standards issue rather than a compiler issue. I write for two reasons. First, I hope that is wrong, or even if correct, that g++ would fix this. The additional parentheses prevents a macro from performing expression decomposition, such as within catch (the unit test framework) or lest (another unit test framework), which uses a macro with an argument of an expression, and is able to output both the text of the expression, and the expression with the values substituted in. With the parentheses, it sees the whole argument as either true or false, not looking inside. Second, if g++ won't fix unless the standard is updated, clang++ gives a helpful note that g++ doesn't, as shown below, which would be nice to add to g++. FWIW, clang++ also compiles x and y, but fails on z. BUT, it at least gives a helpful note that g++ doesn't: $ clang++ -std=c++11 test.cpp test.cpp:11:23: error: too many arguments provided to function-like macro invocation foo z = MAC(foo{5, 7}); ^ test.cpp:1:9: note: macro 'MAC' defined here #define MAC(arg) arg ^ test.cpp:11:12: note: parentheses are required around macro argument containing braced initializer list foo z = MAC(foo{5, 7}); ^ ( )