summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Lex/Token.h6
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp7
-rw-r--r--clang/lib/Lex/TokenLexer.cpp17
-rw-r--r--clang/test/Preprocessor/microsoft-ext.c9
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);
OpenPOWER on IntegriCloud