]> granicus.if.org Git - clang/commitdiff
[MSVC Compat] Accept elided commas in macro function arguments
authorEhsan Akhgari <ehsan.akhgari@gmail.com>
Fri, 22 Jan 2016 19:26:44 +0000 (19:26 +0000)
committerEhsan Akhgari <ehsan.akhgari@gmail.com>
Fri, 22 Jan 2016 19:26:44 +0000 (19:26 +0000)
Summary:
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.

Reviewers: rnk, rsmith

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D15670

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@258530 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 7ba22b2f626c636da3c13cf81890f1812ec8f144..d34f1cf9ee9a7cfeba5ab04067b24f8ea1c9f63c 100644 (file)
@@ -85,6 +85,7 @@ public:
     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 @@ public:
   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)
index 18348df0a39ec0e429702cdbd87e61bdc359f2ff..11b4a0b3d8c3cd2bc61dd993cb8f3b0d59618871 100644 (file)
@@ -723,6 +723,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
   // heap allocations in the common case.
   SmallVector<Token, 64> ArgTokens;
   bool ContainsCodeCompletionTok = false;
+  bool FoundElidedComma = false;
 
   SourceLocation TooManyArgsLoc;
 
@@ -765,6 +766,10 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
         // 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)) {
@@ -909,7 +914,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
       // 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 ed2b8cdabd1c47a9da9afa5f470d9000fb05e0e2..3f66b7f9b76eff12d124ba9eb343b1388292ed03 100644 (file)
@@ -154,12 +154,17 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
   // 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 b03f6775429a3fda356c9f63722e4f30338c4f87..cb3cf4f1537981077bc942ebd4d546d6826fa9e1 100644 (file)
@@ -34,3 +34,12 @@ ACTION_TEMPLATE(InvokeArgument,
 
 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);