mirror of https://github.com/microsoft/clang.git
[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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@258530 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2e0dd42050
commit
dc46911de2
|
@ -85,6 +85,7 @@ public:
|
||||||
IgnoredComma = 0x80, // This comma is not a macro argument separator (MS).
|
IgnoredComma = 0x80, // This comma is not a macro argument separator (MS).
|
||||||
StringifiedInMacro = 0x100, // This string or character literal is formed by
|
StringifiedInMacro = 0x100, // This string or character literal is formed by
|
||||||
// macro stringizing or charizing operator.
|
// macro stringizing or charizing operator.
|
||||||
|
CommaAfterElided = 0x200, // The comma following this token was elided (MS).
|
||||||
};
|
};
|
||||||
|
|
||||||
tok::TokenKind getKind() const { return Kind; }
|
tok::TokenKind getKind() const { return Kind; }
|
||||||
|
@ -297,6 +298,11 @@ public:
|
||||||
bool stringifiedInMacro() const {
|
bool stringifiedInMacro() const {
|
||||||
return (Flags & StringifiedInMacro) ? true : false;
|
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)
|
/// \brief Information about the conditional stack (\#if directives)
|
||||||
|
|
|
@ -723,6 +723,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
|
||||||
// heap allocations in the common case.
|
// heap allocations in the common case.
|
||||||
SmallVector<Token, 64> ArgTokens;
|
SmallVector<Token, 64> ArgTokens;
|
||||||
bool ContainsCodeCompletionTok = false;
|
bool ContainsCodeCompletionTok = false;
|
||||||
|
bool FoundElidedComma = false;
|
||||||
|
|
||||||
SourceLocation TooManyArgsLoc;
|
SourceLocation TooManyArgsLoc;
|
||||||
|
|
||||||
|
@ -765,6 +766,10 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
|
||||||
// If we found the ) token, the macro arg list is done.
|
// If we found the ) token, the macro arg list is done.
|
||||||
if (NumParens-- == 0) {
|
if (NumParens-- == 0) {
|
||||||
MacroEnd = Tok.getLocation();
|
MacroEnd = Tok.getLocation();
|
||||||
|
if (!ArgTokens.empty() &&
|
||||||
|
ArgTokens.back().commaAfterElided()) {
|
||||||
|
FoundElidedComma = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (Tok.is(tok::l_paren)) {
|
} 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
|
// then we have an empty "()" argument empty list. This is fine, even if
|
||||||
// the macro expects one argument (the argument is just empty).
|
// the macro expects one argument (the argument is just empty).
|
||||||
isVarargsElided = MI->isVariadic();
|
isVarargsElided = MI->isVariadic();
|
||||||
} else if (MI->isVariadic() &&
|
} else if ((FoundElidedComma || MI->isVariadic()) &&
|
||||||
(NumActuals+1 == MinArgsExpected || // A(x, ...) -> A(X)
|
(NumActuals+1 == MinArgsExpected || // A(x, ...) -> A(X)
|
||||||
(NumActuals == 0 && MinArgsExpected == 2))) {// A(x,...) -> A()
|
(NumActuals == 0 && MinArgsExpected == 2))) {// A(x,...) -> A()
|
||||||
// Varargs where the named vararg parameter is missing: OK as extension.
|
// Varargs where the named vararg parameter is missing: OK as extension.
|
||||||
|
|
|
@ -154,12 +154,17 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
|
||||||
// Remove the comma.
|
// Remove the comma.
|
||||||
ResultToks.pop_back();
|
ResultToks.pop_back();
|
||||||
|
|
||||||
// If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"),
|
if (!ResultToks.empty()) {
|
||||||
// then removal of the comma should produce a placemarker token (in C99
|
// If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"),
|
||||||
// terms) which we model by popping off the previous ##, giving us a plain
|
// then removal of the comma should produce a placemarker token (in C99
|
||||||
// "X" when __VA_ARGS__ is empty.
|
// terms) which we model by popping off the previous ##, giving us a plain
|
||||||
if (!ResultToks.empty() && ResultToks.back().is(tok::hashhash))
|
// "X" when __VA_ARGS__ is empty.
|
||||||
ResultToks.pop_back();
|
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.
|
// Never add a space, even if the comma, ##, or arg had a space.
|
||||||
NextTokGetsSpace = false;
|
NextTokGetsSpace = false;
|
||||||
|
|
|
@ -34,3 +34,12 @@ ACTION_TEMPLATE(InvokeArgument,
|
||||||
|
|
||||||
MAKE_FUNC(MAK, ER, int a, _COMMA, int b);
|
MAKE_FUNC(MAK, ER, int a, _COMMA, int b);
|
||||||
// CHECK: void func(int a , 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);
|
||||||
|
|
Loading…
Reference in New Issue