Index: cfe/trunk/include/clang/Lex/Token.h =================================================================== --- cfe/trunk/include/clang/Lex/Token.h +++ cfe/trunk/include/clang/Lex/Token.h @@ -85,6 +85,7 @@ IgnoredComma = 0x80, // This comma is not a macro argument separator (MS). StringifiedInMacro = 0x100, // This string or character literal is formed by // macro stringizing or charizing operator. + CommaAfterElided = 0x200, // The comma following this token was elided (MS). }; tok::TokenKind getKind() const { return Kind; } @@ -297,6 +298,11 @@ bool stringifiedInMacro() const { return (Flags & StringifiedInMacro) ? true : false; } + + /// Returns true if the comma after this token was elided. + bool commaAfterElided() const { + return (Flags & CommaAfterElided) ? true : false; + } }; /// \brief Information about the conditional stack (\#if directives) Index: cfe/trunk/lib/Lex/PPMacroExpansion.cpp =================================================================== --- cfe/trunk/lib/Lex/PPMacroExpansion.cpp +++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp @@ -723,6 +723,7 @@ // heap allocations in the common case. SmallVector ArgTokens; bool ContainsCodeCompletionTok = false; + bool FoundElidedComma = false; SourceLocation TooManyArgsLoc; @@ -765,6 +766,10 @@ // If we found the ) token, the macro arg list is done. if (NumParens-- == 0) { MacroEnd = Tok.getLocation(); + if (!ArgTokens.empty() && + ArgTokens.back().commaAfterElided()) { + FoundElidedComma = true; + } break; } } else if (Tok.is(tok::l_paren)) { @@ -909,7 +914,7 @@ // then we have an empty "()" argument empty list. This is fine, even if // the macro expects one argument (the argument is just empty). isVarargsElided = MI->isVariadic(); - } else if (MI->isVariadic() && + } else if ((FoundElidedComma || MI->isVariadic()) && (NumActuals+1 == MinArgsExpected || // A(x, ...) -> A(X) (NumActuals == 0 && MinArgsExpected == 2))) {// A(x,...) -> A() // Varargs where the named vararg parameter is missing: OK as extension. Index: cfe/trunk/lib/Lex/TokenLexer.cpp =================================================================== --- cfe/trunk/lib/Lex/TokenLexer.cpp +++ cfe/trunk/lib/Lex/TokenLexer.cpp @@ -154,12 +154,17 @@ // Remove the comma. ResultToks.pop_back(); - // If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"), - // then removal of the comma should produce a placemarker token (in C99 - // terms) which we model by popping off the previous ##, giving us a plain - // "X" when __VA_ARGS__ is empty. - if (!ResultToks.empty() && ResultToks.back().is(tok::hashhash)) - ResultToks.pop_back(); + if (!ResultToks.empty()) { + // If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"), + // then removal of the comma should produce a placemarker token (in C99 + // terms) which we model by popping off the previous ##, giving us a plain + // "X" when __VA_ARGS__ is empty. + if (ResultToks.back().is(tok::hashhash)) + ResultToks.pop_back(); + + // Remember that this comma was elided. + ResultToks.back().setFlag(Token::CommaAfterElided); + } // Never add a space, even if the comma, ##, or arg had a space. NextTokGetsSpace = false; Index: cfe/trunk/test/Preprocessor/microsoft-ext.c =================================================================== --- cfe/trunk/test/Preprocessor/microsoft-ext.c +++ cfe/trunk/test/Preprocessor/microsoft-ext.c @@ -34,3 +34,12 @@ MAKE_FUNC(MAK, ER, int a, _COMMA, int b); // CHECK: void func(int a , int b) {} + +#define macro(a, b) (a - b) +void function(int a); +#define COMMA_ELIDER(...) \ + macro(x, __VA_ARGS__); \ + function(x, __VA_ARGS__); +COMMA_ELIDER(); +// CHECK: (x - ); +// CHECK: function(x);