r200786 - Fix whitespace handling in empty macro arguments

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


Author: bogner
Date: Tue Feb  4 13:18:32 2014
New Revision: 200786

URL: http://llvm.org/viewvc/llvm-project?rev=200786&view=rev
Log:
Fix whitespace handling in empty macro arguments

When a function-like macro definition ends with one of the macro's
parameters, and the argument is empty, any whitespace before the
parameter name in the macro definition needs to be preserved. Promoting
the existing NextTokGetsSpace to a preserved bit-field and checking it
at the end of the macro expansion allows it to be moved to the first
token following the macro expansion result.

Patch by Harald van Dijk!

Added:
    cfe/trunk/test/Preprocessor/macro_arg_empty.c
Modified:
    cfe/trunk/include/clang/Lex/TokenLexer.h
    cfe/trunk/lib/Lex/TokenLexer.cpp

Modified: cfe/trunk/include/clang/Lex/TokenLexer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/TokenLexer.h?rev=200786&r1=200785&r2=200786&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/TokenLexer.h (original)
+++ cfe/trunk/include/clang/Lex/TokenLexer.h Tue Feb  4 13:18:32 2014
@@ -81,6 +81,14 @@ class TokenLexer {
   bool AtStartOfLine : 1;
   bool HasLeadingSpace : 1;
 
+  // NextTokGetsSpace - When this is true, the next token appended to the
+  // output list during function argument expansion will get a leading space,
+  // regardless of whether it had one to begin with or not. This is used for
+  // placemarker support. If still true after function argument expansion, the
+  // leading space will be applied to the first token following the macro
+  // expansion.
+  bool NextTokGetsSpace : 1;
+
   /// OwnsTokens - This is true if this TokenLexer allocated the Tokens
   /// array, and thus needs to free it when destroyed.  For simple object-like
   /// macros (for example) we just point into the token buffer of the macro
@@ -182,6 +190,13 @@ private:
   void updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc,
                                   Token *begin_tokens, Token *end_tokens);
 
+  /// Remove comma ahead of __VA_ARGS__, if present, according to compiler
+  /// dialect settings.  Returns true if the comma is removed.
+  bool MaybeRemoveCommaBeforeVaArgs(SmallVectorImpl<Token> &ResultToks,
+                                    bool HasPasteOperator,
+                                    MacroInfo *Macro, unsigned MacroArgNo,
+                                    Preprocessor &PP);
+
   void PropagateLineStartLeadingSpaceInfo(Token &Result);
 };
 

Modified: cfe/trunk/lib/Lex/TokenLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/TokenLexer.cpp?rev=200786&r1=200785&r2=200786&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/TokenLexer.cpp (original)
+++ cfe/trunk/lib/Lex/TokenLexer.cpp Tue Feb  4 13:18:32 2014
@@ -37,6 +37,7 @@ void TokenLexer::Init(Token &Tok, Source
   ExpandLocEnd = ELEnd;
   AtStartOfLine = Tok.isAtStartOfLine();
   HasLeadingSpace = Tok.hasLeadingSpace();
+  NextTokGetsSpace = false;
   Tokens = &*Macro->tokens_begin();
   OwnsTokens = false;
   DisableMacroExpansion = false;
@@ -95,6 +96,7 @@ void TokenLexer::Init(const Token *TokAr
   ExpandLocStart = ExpandLocEnd = SourceLocation();
   AtStartOfLine = false;
   HasLeadingSpace = false;
+  NextTokGetsSpace = false;
   MacroExpansionStart = SourceLocation();
 
   // Set HasLeadingSpace/AtStartOfLine so that the first token will be
@@ -119,13 +121,10 @@ void TokenLexer::destroy() {
   if (ActualArgs) ActualArgs->destroy(PP);
 }
 
-/// Remove comma ahead of __VA_ARGS__, if present, according to compiler dialect
-/// settings.  Returns true if the comma is removed.
-static bool MaybeRemoveCommaBeforeVaArgs(SmallVectorImpl<Token> &ResultToks,
-                                         bool &NextTokGetsSpace,
-                                         bool HasPasteOperator,
-                                         MacroInfo *Macro, unsigned MacroArgNo,
-                                         Preprocessor &PP) {
+bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(SmallVectorImpl<Token> &ResultToks,
+                                              bool HasPasteOperator,
+                                              MacroInfo *Macro, unsigned MacroArgNo,
+                                              Preprocessor &PP) {
   // Is the macro argument __VA_ARGS__?
   if (!Macro->isVariadic() || MacroArgNo != Macro->getNumArgs()-1)
     return false;
@@ -179,11 +178,6 @@ void TokenLexer::ExpandFunctionArguments
   // we install the newly expanded sequence as the new 'Tokens' list.
   bool MadeChange = false;
 
-  // NextTokGetsSpace - When this is true, the next token appended to the
-  // output list will get a leading space, regardless of whether it had one to
-  // begin with or not.  This is used for placemarker support.
-  bool NextTokGetsSpace = false;
-
   for (unsigned i = 0, e = NumTokens; i != e; ++i) {
     // If we found the stringify operator, get the argument stringified.  The
     // preprocessor already verified that the following token is a macro name
@@ -256,7 +250,7 @@ void TokenLexer::ExpandFunctionArguments
     // In Microsoft mode, remove the comma before __VA_ARGS__ to ensure there
     // are no trailing commas if __VA_ARGS__ is empty.
     if (!PasteBefore && ActualArgs->isVarargsElidedUse() &&
-        MaybeRemoveCommaBeforeVaArgs(ResultToks, NextTokGetsSpace,
+        MaybeRemoveCommaBeforeVaArgs(ResultToks,
                                      /*HasPasteOperator=*/false,
                                      Macro, ArgNo, PP))
       continue;
@@ -311,9 +305,10 @@ void TokenLexer::ExpandFunctionArguments
                                              NextTokGetsSpace);
         NextTokGetsSpace = false;
       } else {
-        // If this is an empty argument, and if there was whitespace before the
-        // formal token, make sure the next token gets whitespace before it.
-        NextTokGetsSpace = CurTok.hasLeadingSpace();
+        // If this is an empty argument, if there was whitespace before the
+        // formal token, and this is not the first token in the macro
+        // definition, make sure the next token gets whitespace before it.
+        NextTokGetsSpace |= i != 0 && CurTok.hasLeadingSpace();
       }
       continue;
     }
@@ -396,7 +391,7 @@ void TokenLexer::ExpandFunctionArguments
     // the ## was a comma, remove the comma.  This is a GCC extension which is
     // disabled when using -std=c99.
     if (ActualArgs->isVarargsElidedUse())
-      MaybeRemoveCommaBeforeVaArgs(ResultToks, NextTokGetsSpace,
+      MaybeRemoveCommaBeforeVaArgs(ResultToks,
                                    /*HasPasteOperator=*/true,
                                    Macro, ArgNo, PP);
 
@@ -428,7 +423,7 @@ bool TokenLexer::Lex(Token &Tok) {
 
     Tok.startToken();
     Tok.setFlagValue(Token::StartOfLine , AtStartOfLine);
-    Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
+    Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace || NextTokGetsSpace);
     if (CurToken == 0)
       Tok.setFlag(Token::LeadingEmptyMacro);
     return PP.HandleEndOfTokenLexer(Tok);

Added: cfe/trunk/test/Preprocessor/macro_arg_empty.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/macro_arg_empty.c?rev=200786&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/macro_arg_empty.c (added)
+++ cfe/trunk/test/Preprocessor/macro_arg_empty.c Tue Feb  4 13:18:32 2014
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
+
+#define FOO(x) x
+#define BAR(x) x x
+#define BAZ(x) [x] [ x] [x ]
+[FOO()] [ FOO()] [FOO() ] [BAR()] [ BAR()] [BAR() ] BAZ()
+// CHECK: [] [ ] [ ] [ ] [ ] [ ] [] [ ] [ ]





More information about the cfe-commits mailing list