r200785 - Fix whitespace handling in ## operator

Justin Bogner mail at justinbogner.com
Tue Feb 4 11:18:28 PST 2014


Author: bogner
Date: Tue Feb  4 13:18:28 2014
New Revision: 200785

URL: http://llvm.org/viewvc/llvm-project?rev=200785&view=rev
Log:
Fix whitespace handling in ## operator

In x ## y, where x and y are regular tokens, whitespace between x and ##
is ignored, and whitespace between ## and y is also ignored. When either
x or y is a function argument, whitespace was preserved, but it should
not be. This patch removes the checks for whitespace before ## and
before y, and in the special case where x is an empty macro argument and
y is a regular token, actively removes whitespace before y.

One existing test is affected by that change, but as clang's output now
matches the standard's requirements and that of GCC, I've tweaked the
testcase.

Patch by Harald van Dijk!

Modified:
    cfe/trunk/lib/Lex/TokenLexer.cpp
    cfe/trunk/test/Preprocessor/macro_paste_commaext.c
    cfe/trunk/test/Preprocessor/macro_paste_spacing.c

Modified: cfe/trunk/lib/Lex/TokenLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/TokenLexer.cpp?rev=200785&r1=200784&r2=200785&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/TokenLexer.cpp (original)
+++ cfe/trunk/lib/Lex/TokenLexer.cpp Tue Feb  4 13:18:28 2014
@@ -223,6 +223,13 @@ void TokenLexer::ExpandFunctionArguments
       continue;
     }
 
+    // Find out if there is a paste (##) operator before or after the token.
+    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);
+
     // Otherwise, if this is not an argument token, just add the token to the
     // output buffer.
     IdentifierInfo *II = CurTok.getIdentifierInfo();
@@ -234,7 +241,9 @@ void TokenLexer::ExpandFunctionArguments
       if (NextTokGetsSpace) {
         ResultToks.back().setFlag(Token::LeadingSpace);
         NextTokGetsSpace = false;
-      }
+      } else if (PasteBefore && !NonEmptyPasteBefore)
+        ResultToks.back().clearFlag(Token::LeadingSpace);
+
       continue;
     }
 
@@ -242,13 +251,7 @@ void TokenLexer::ExpandFunctionArguments
     // input.
     MadeChange = true;
 
-    // Otherwise, this is a use of the argument.  Find out if there is a paste
-    // (##) operator before or after the argument.
-    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);
+    // Otherwise, this is a use of the argument.
 
     // In Microsoft mode, remove the comma before __VA_ARGS__ to ensure there
     // are no trailing commas if __VA_ARGS__ is empty.
@@ -358,8 +361,8 @@ void TokenLexer::ExpandFunctionArguments
       // assembler-with-cpp mode, invalid pastes are allowed through: in this
       // case, we do not want the extra whitespace to be added.  For example,
       // we want ". ## foo" -> ".foo" not ". foo".
-      if ((CurTok.hasLeadingSpace() || NextTokGetsSpace) &&
-          !NonEmptyPasteBefore)
+      if ((CurTok.hasLeadingSpace() && !PasteBefore) ||
+          (NextTokGetsSpace && !NonEmptyPasteBefore))
         ResultToks[ResultToks.size()-NumToks].setFlag(Token::LeadingSpace);
 
       NextTokGetsSpace = false;
@@ -370,11 +373,11 @@ void TokenLexer::ExpandFunctionArguments
     // 6.10.3.3p2,3) calls for a bunch of placemarker stuff to occur.  We
     // implement this by eating ## operators when a LHS or RHS expands to
     // empty.
-    NextTokGetsSpace |= CurTok.hasLeadingSpace();
+    if (!PasteBefore)
+      NextTokGetsSpace |= i != 0 && CurTok.hasLeadingSpace();
     if (PasteAfter) {
       // Discard the argument token and skip (don't copy to the expansion
       // buffer) the paste operator after it.
-      NextTokGetsSpace |= Tokens[i+1].hasLeadingSpace();
       ++i;
       continue;
     }
@@ -385,7 +388,7 @@ void TokenLexer::ExpandFunctionArguments
     assert(PasteBefore);
     if (NonEmptyPasteBefore) {
       assert(ResultToks.back().is(tok::hashhash));
-      NextTokGetsSpace |= ResultToks.pop_back_val().hasLeadingSpace();
+      ResultToks.pop_back();
     }
 
     // If this is the __VA_ARGS__ token, and if the argument wasn't provided,

Modified: cfe/trunk/test/Preprocessor/macro_paste_commaext.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/macro_paste_commaext.c?rev=200785&r1=200784&r2=200785&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/macro_paste_commaext.c (original)
+++ cfe/trunk/test/Preprocessor/macro_paste_commaext.c Tue Feb  4 13:18:28 2014
@@ -1,8 +1,8 @@
 // RUN: %clang_cc1 %s -E | grep 'V);'
 // RUN: %clang_cc1 %s -E | grep 'W, 1, 2);'
 // RUN: %clang_cc1 %s -E | grep 'X, 1, 2);'
-// RUN: %clang_cc1 %s -E | grep 'Y, );'
-// RUN: %clang_cc1 %s -E | grep 'Z, );'
+// RUN: %clang_cc1 %s -E | grep 'Y,);'
+// RUN: %clang_cc1 %s -E | grep 'Z,);'
 
 #define debug(format, ...) format, ## __VA_ARGS__)
 debug(V);

Modified: cfe/trunk/test/Preprocessor/macro_paste_spacing.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/macro_paste_spacing.c?rev=200785&r1=200784&r2=200785&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/macro_paste_spacing.c (original)
+++ cfe/trunk/test/Preprocessor/macro_paste_spacing.c Tue Feb  4 13:18:28 2014
@@ -1,7 +1,21 @@
-// RUN: %clang_cc1 %s -E | grep "^xy$"
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
 
 #define A  x ## y
 blah
 
 A
+// CHECK: {{^}}xy{{$}}
 
+#define B(x, y) [v ## w] [ v##w] [v##w ] [w ## x] [ w##x] [w##x ] [x ## y] [ x##y] [x##y ] [y ## z] [ y##z] [y##z ]
+B(x,y)
+// CHECK: [vw] [ vw] [vw ] [wx] [ wx] [wx ] [xy] [ xy] [xy ] [yz] [ yz] [yz ]
+B(x,)
+// CHECK: [vw] [ vw] [vw ] [wx] [ wx] [wx ] [x] [ x] [x ] [z] [ z] [z ]
+B(,y)
+// CHECK: [vw] [ vw] [vw ] [w] [ w] [w ] [y] [ y] [y ] [yz] [ yz] [yz ]
+B(,)
+// CHECK: [vw] [ vw] [vw ] [w] [ w] [w ] [] [ ] [ ] [z] [ z] [z ]
+
+#define C(x, y, z) [x ## y ## z]
+C(,,) C(a,,) C(,b,) C(,,c) C(a,b,) C(a,,c) C(,b,c) C(a,b,c)
+// CHECK: [] [a] [b] [c] [ab] [ac] [bc] [abc]





More information about the cfe-commits mailing list