diff options
-rw-r--r-- | clang/include/clang/Lex/Token.h | 6 | ||||
-rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Lex/TokenLexer.cpp | 17 | ||||
-rw-r--r-- | clang/test/Preprocessor/microsoft-ext.c | 9 |
4 files changed, 32 insertions, 7 deletions
diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h index 7ba22b2f626..d34f1cf9ee9 100644 --- a/clang/include/clang/Lex/Token.h +++ b/clang/include/clang/Lex/Token.h @@ -85,6 +85,7 @@ public: 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 @@ public: 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) diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 18348df0a39..11b4a0b3d8c 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -723,6 +723,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, // heap allocations in the common case. SmallVector<Token, 64> ArgTokens; bool ContainsCodeCompletionTok = false; + bool FoundElidedComma = false; SourceLocation TooManyArgsLoc; @@ -765,6 +766,10 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, // 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 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, // 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. diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp index ed2b8cdabd1..3f66b7f9b76 100644 --- a/clang/lib/Lex/TokenLexer.cpp +++ b/clang/lib/Lex/TokenLexer.cpp @@ -154,12 +154,17 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs( // 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; diff --git a/clang/test/Preprocessor/microsoft-ext.c b/clang/test/Preprocessor/microsoft-ext.c index b03f6775429..cb3cf4f1537 100644 --- a/clang/test/Preprocessor/microsoft-ext.c +++ b/clang/test/Preprocessor/microsoft-ext.c @@ -34,3 +34,12 @@ ACTION_TEMPLATE(InvokeArgument, 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); |