GCC awkwardly preprocesses the following code: #define FOO()FOO FOO()() #define CAT1(X,Y,...)__VA_OPT__(X)##__VA_OPT__(Y) CAT1(FOO(),,,)() #define CAT2(X,Y,...)__VA_OPT__(X)##__VA_OPT__() CAT2(FOO(),,,)() #define CAT3(X,Y,...)__VA_OPT__(X)##Y CAT3(FOO(),,,)() #define CAT4(X,Y,...)__VA_OPT__(X)##__VA_OPT__(Y##Y) CAT4(FOO(),,,)() #define CAT5(X,Y,...)__VA_OPT__(X)##__VA_OPT__(Y Y) CAT5(FOO(),,,)() Consider the first case FOO()(), the result is clear here. FOO() gets expanded to FOO but since that identifier appeared inside of the replacement list of FOO it is not available for future macro expansion. Therefore FOO()() becomes FOO(). The second case CAT1(FOO(),,,)() is similar but after expanding FOO() it then concatenates the resulting identifier FOO with a placemarker token. GCC considers this sufficient under the "The resulting preprocessing token is available for further macro replacement" wording to allow for it to be expanded again. Therefore CAT1(FOO(),,,)() becomes FOO. The same also applies to the fifth case CAT5(FOO(),,,)(). For the cases two through for however GCC does not consider it sufficient, so CAT2(FOO(),,,)() becomes FOO(). The same also applies to CAT3(FOO(),,,)() and CAT4(FOO(),,,)(). Here is the same example but with object like macros: #define FOO !FOO FOO//!FOO with GCC #define CAT1(X,Y,...)__VA_OPT__(X)##__VA_OPT__(Y) CAT1(FOO,,,)//!!FOO with GCC #define CAT2(X,Y,...)__VA_OPT__(X)##__VA_OPT__() CAT2(FOO,,,)//!FOO with GCC #define CAT3(X,Y,...)__VA_OPT__(X)##Y CAT3(FOO,,,)//!FOO with GCC #define CAT4(X,Y,...)__VA_OPT__(X)##__VA_OPT__(Y##Y) CAT4(FOO,,,)//!FOO with GCC #define CAT5(X,Y,...)__VA_OPT__(X)##__VA_OPT__(Y Y) CAT5(FOO,,,)//!!FOO with GCC So from examining the current behavior: concatenating with an empty argument ##E does not allow for further expansion, concatenation with ##__VA_OPT__() does not allow for further expansion, and concatenation with ##__VA_OPT__(pp-tokens) where the pp-tokens cause the hypothetical argument to be empty does allow for further expansion unless the pp-tokens contain a concatenation inside of them. This behavior is very inconsistent, so I think the behavior should be normalized. The intended behavior as far as I understand is that concatenating with a placemarker token should not allow further macro expansions, that is it should have no effect on the other token (with two placemarkers the behavior is obvious). Clang and MSVC implement this, though EDG does the opposite.