[PATCH] Prevent macro argument expansion when the LHS of concatenation is empty
Harald van Dijk
harald at gigawatt.nl
Wed Apr 10 13:36:32 PDT 2013
Hi all,
As mentioned in http://llvm.org/bugs/show_bug.cgi?id=12767, and what I
again reported as http://llvm.org/bugs/show_bug.cgi?id=15661, when
concatenating x ## y, argument expansion for y should be suppressed even
when x is empty. Does this approach look okay? All preprocessor tests
pass, a few other tests were already failing for me and continue to fail
the same way, there are no new failures.
This is my first contribution to clang, I am not yet familiar with the
process. I should not need to do more than send this patch to the list,
correct?
Cheers,
Harald
-------------- next part --------------
Author: Harald van Dijk <harald at gigawatt.nl>
Date: Wed Apr 10 22:03:15 2013 +0200
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.
PR12767
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index 5b41fe9..580d211 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -244,9 +244,11 @@ void TokenLexer::ExpandFunctionArguments() {
// Otherwise, this is a use of the argument. Find out if there is a paste
// (##) operator before or after the argument.
- bool PasteBefore =
+ bool NonEmptyPasteBefore =
!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);
+ assert(!NonEmptyPasteBefore || PasteBefore);
// In Microsoft mode, remove the comma before __VA_ARGS__ to ensure there
// 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
// the expander trys to paste ',' with the first token of the __VA_ARGS__
// expansion.
- if (PasteBefore && ResultToks.size() >= 2 &&
+ if (NonEmptyPasteBefore && ResultToks.size() >= 2 &&
ResultToks[ResultToks.size()-2].is(tok::comma) &&
(unsigned)ArgNo == Macro->getNumArgs()-1 &&
Macro->isVariadic()) {
@@ -350,7 +352,7 @@ void TokenLexer::ExpandFunctionArguments() {
// case, we do not want the extra whitespace to be added. For example,
// we want ". ## foo" -> ".foo" not ". foo".
if ((CurTok.hasLeadingSpace() || NextTokGetsSpace) &&
- !PasteBefore)
+ !NonEmptyPasteBefore)
ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace);
NextTokGetsSpace = false;
@@ -371,10 +373,14 @@ void TokenLexer::ExpandFunctionArguments() {
}
// If this is on the RHS of a paste operator, we've already copied the
- // paste operator to the ResultToks list. Remove it.
- assert(PasteBefore && ResultToks.back().is(tok::hashhash));
- NextTokGetsSpace |= ResultToks.back().hasLeadingSpace();
- ResultToks.pop_back();
+ // paste operator to the ResultToks list, unless the LHS was empty too.
+ // Remove it.
+ assert(PasteBefore);
+ 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,
// and if the macro had at least one real argument, and if the token before
diff --git a/test/Preprocessor/macro_paste_empty.c b/test/Preprocessor/macro_paste_empty.c
index 2e26f14..78feb19 100644
--- a/test/Preprocessor/macro_paste_empty.c
+++ b/test/Preprocessor/macro_paste_empty.c
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -E %s | grep 'a:Y'
// RUN: %clang_cc1 -E %s | grep 'b:Y'
// RUN: %clang_cc1 -E %s | grep 'c:YY'
+// RUN: %clang_cc1 -E %s | grep 'd:FOO4'
#define FOO(X) X ## Y
a:FOO()
@@ -11,3 +12,5 @@ b:FOO2()
#define FOO3(X) X ## Y ## X ## Y ## X ## X
c:FOO3()
+#define FOO4(X, Y) X ## Y
+d:FOO4(,FOO4(,))
More information about the cfe-commits
mailing list