ehsan created this revision.
ehsan added reviewers: rnk, rsmith.
ehsan added a subscriber: cfe-commits.

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.

http://reviews.llvm.org/D15670

Files:
  include/clang/Lex/Token.h
  lib/Lex/PPMacroExpansion.cpp
  lib/Lex/TokenLexer.cpp
  test/Preprocessor/microsoft-ext.c

Index: test/Preprocessor/microsoft-ext.c
===================================================================
--- test/Preprocessor/microsoft-ext.c
+++ test/Preprocessor/microsoft-ext.c
@@ -34,3 +34,12 @@
 
 MAKE_FUNC(MAK, ER, int a, _COMMA, 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);
Index: lib/Lex/TokenLexer.cpp
===================================================================
--- lib/Lex/TokenLexer.cpp
+++ lib/Lex/TokenLexer.cpp
@@ -154,12 +154,17 @@
   // Remove the comma.
   ResultToks.pop_back();
 
-  // If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"),
-  // then removal of the comma should produce a placemarker token (in C99
-  // terms) which we model by popping off the previous ##, giving us a plain
-  // "X" when __VA_ARGS__ is empty.
-  if (!ResultToks.empty() && ResultToks.back().is(tok::hashhash))
-    ResultToks.pop_back();
+  if (!ResultToks.empty()) {
+    // If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"),
+    // then removal of the comma should produce a placemarker token (in C99
+    // terms) which we model by popping off the previous ##, giving us a plain
+    // "X" when __VA_ARGS__ is empty.
+    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.
   NextTokGetsSpace = false;
Index: lib/Lex/PPMacroExpansion.cpp
===================================================================
--- lib/Lex/PPMacroExpansion.cpp
+++ lib/Lex/PPMacroExpansion.cpp
@@ -725,6 +725,7 @@
   // heap allocations in the common case.
   SmallVector<Token, 64> ArgTokens;
   bool ContainsCodeCompletionTok = false;
+  bool FoundElidedComma = false;
 
   SourceLocation TooManyArgsLoc;
 
@@ -767,6 +768,10 @@
         // If we found the ) token, the macro arg list is done.
         if (NumParens-- == 0) {
           MacroEnd = Tok.getLocation();
+          if (!ArgTokens.empty() &&
+              ArgTokens.back().commaAfterElided()) {
+            FoundElidedComma = true;
+          }
           break;
         }
       } else if (Tok.is(tok::l_paren)) {
@@ -911,7 +916,7 @@
       // then we have an empty "()" argument empty list.  This is fine, even if
       // the macro expects one argument (the argument is just empty).
       isVarargsElided = MI->isVariadic();
-    } else if (MI->isVariadic() &&
+    } else if ((FoundElidedComma || MI->isVariadic()) &&
                (NumActuals+1 == MinArgsExpected ||  // A(x, ...) -> A(X)
                 (NumActuals == 0 && MinArgsExpected == 2))) {// A(x,...) -> A()
       // Varargs where the named vararg parameter is missing: OK as extension.
Index: include/clang/Lex/Token.h
===================================================================
--- include/clang/Lex/Token.h
+++ include/clang/Lex/Token.h
@@ -85,6 +85,7 @@
     IgnoredComma = 0x80,   // This comma is not a macro argument separator (MS).
     StringifiedInMacro = 0x100, // This string or character literal is formed by
                                 // macro stringizing or charizing operator.
+    CommaAfterElided = 0x200, // The comma following this token was elided (MS).
   };
 
   tok::TokenKind getKind() const { return Kind; }
@@ -297,6 +298,11 @@
   bool stringifiedInMacro() const {
     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)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to