mirror of https://github.com/microsoft/clang.git
[Preprocessor] Prevent expansion of y in x ## y when x is empty
When x is empty, x ## is suppressed, and when y gets expanded, the fact that it follows ## is not available in the macro expansion result. The macro definition can be checked instead, the ## will be available there regardless of what x expands to. Fixes http://llvm.org/PR12767 Patch by Harald van Dijk! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182699 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
45e1f0e3e7
commit
461f2d820f
|
@ -244,9 +244,11 @@ void TokenLexer::ExpandFunctionArguments() {
|
||||||
|
|
||||||
// Otherwise, this is a use of the argument. Find out if there is a paste
|
// Otherwise, this is a use of the argument. Find out if there is a paste
|
||||||
// (##) operator before or after the argument.
|
// (##) operator before or after the argument.
|
||||||
bool PasteBefore =
|
bool NonEmptyPasteBefore =
|
||||||
!ResultToks.empty() && ResultToks.back().is(tok::hashhash);
|
!ResultToks.empty() && ResultToks.back().is(tok::hashhash);
|
||||||
|
bool PasteBefore = i != 0 && Tokens[i-1].is(tok::hashhash);
|
||||||
bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash);
|
bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash);
|
||||||
|
assert(!NonEmptyPasteBefore || PasteBefore);
|
||||||
|
|
||||||
// In Microsoft mode, remove the comma before __VA_ARGS__ to ensure there
|
// In Microsoft mode, remove the comma before __VA_ARGS__ to ensure there
|
||||||
// are no trailing commas if __VA_ARGS__ is empty.
|
// are no trailing commas if __VA_ARGS__ is empty.
|
||||||
|
@ -314,7 +316,7 @@ void TokenLexer::ExpandFunctionArguments() {
|
||||||
// that __VA_ARGS__ expands to multiple tokens, avoid a pasting error when
|
// that __VA_ARGS__ expands to multiple tokens, avoid a pasting error when
|
||||||
// the expander trys to paste ',' with the first token of the __VA_ARGS__
|
// the expander trys to paste ',' with the first token of the __VA_ARGS__
|
||||||
// expansion.
|
// expansion.
|
||||||
if (PasteBefore && ResultToks.size() >= 2 &&
|
if (NonEmptyPasteBefore && ResultToks.size() >= 2 &&
|
||||||
ResultToks[ResultToks.size()-2].is(tok::comma) &&
|
ResultToks[ResultToks.size()-2].is(tok::comma) &&
|
||||||
(unsigned)ArgNo == Macro->getNumArgs()-1 &&
|
(unsigned)ArgNo == Macro->getNumArgs()-1 &&
|
||||||
Macro->isVariadic()) {
|
Macro->isVariadic()) {
|
||||||
|
@ -350,7 +352,7 @@ void TokenLexer::ExpandFunctionArguments() {
|
||||||
// case, we do not want the extra whitespace to be added. For example,
|
// case, we do not want the extra whitespace to be added. For example,
|
||||||
// we want ". ## foo" -> ".foo" not ". foo".
|
// we want ". ## foo" -> ".foo" not ". foo".
|
||||||
if ((CurTok.hasLeadingSpace() || NextTokGetsSpace) &&
|
if ((CurTok.hasLeadingSpace() || NextTokGetsSpace) &&
|
||||||
!PasteBefore)
|
!NonEmptyPasteBefore)
|
||||||
ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace);
|
ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace);
|
||||||
|
|
||||||
NextTokGetsSpace = false;
|
NextTokGetsSpace = false;
|
||||||
|
@ -371,10 +373,14 @@ void TokenLexer::ExpandFunctionArguments() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is on the RHS of a paste operator, we've already copied the
|
// If this is on the RHS of a paste operator, we've already copied the
|
||||||
// paste operator to the ResultToks list. Remove it.
|
// paste operator to the ResultToks list, unless the LHS was empty too.
|
||||||
assert(PasteBefore && ResultToks.back().is(tok::hashhash));
|
// Remove it.
|
||||||
NextTokGetsSpace |= ResultToks.back().hasLeadingSpace();
|
assert(PasteBefore);
|
||||||
ResultToks.pop_back();
|
if (NonEmptyPasteBefore) {
|
||||||
|
assert(ResultToks.back().is(tok::hashhash));
|
||||||
|
NextTokGetsSpace |= ResultToks.back().hasLeadingSpace();
|
||||||
|
ResultToks.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
// If this is the __VA_ARGS__ token, and if the argument wasn't provided,
|
// If this is the __VA_ARGS__ token, and if the argument wasn't provided,
|
||||||
// and if the macro had at least one real argument, and if the token before
|
// and if the macro had at least one real argument, and if the token before
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
// RUN: %clang_cc1 -E %s | grep 'a:Y'
|
// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
|
||||||
// RUN: %clang_cc1 -E %s | grep 'b:Y'
|
|
||||||
// RUN: %clang_cc1 -E %s | grep 'c:YY'
|
|
||||||
|
|
||||||
#define FOO(X) X ## Y
|
#define FOO(X) X ## Y
|
||||||
a:FOO()
|
a:FOO()
|
||||||
|
// CHECK: a:Y
|
||||||
|
|
||||||
#define FOO2(X) Y ## X
|
#define FOO2(X) Y ## X
|
||||||
b:FOO2()
|
b:FOO2()
|
||||||
|
// CHECK: b:Y
|
||||||
|
|
||||||
#define FOO3(X) X ## Y ## X ## Y ## X ## X
|
#define FOO3(X) X ## Y ## X ## Y ## X ## X
|
||||||
c:FOO3()
|
c:FOO3()
|
||||||
|
// CHECK: c:YY
|
||||||
|
|
||||||
|
#define FOO4(X, Y) X ## Y
|
||||||
|
d:FOO4(,FOO4(,))
|
||||||
|
// CHECK: d:FOO4
|
||||||
|
|
Loading…
Reference in New Issue