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});
           ^
               (        )

Reply via email to