[MSVC Compat] Accept elided commas in macro function arguments

Summary:
This fixes PR25875.  When the trailing comma in a macro argument list is
elided, we need to treat it similarly to the case where a variadic macro
misses one actual argument.

Reviewers: rnk, rsmith

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D15670

llvm-svn: 258530
This commit is contained in:
Ehsan Akhgari 2016-01-22 19:26:44 +00:00
parent acc43d197d
commit 34461a626e
4 changed files with 32 additions and 7 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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;

View File

@ -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);