Bug 1368932 - Allow MOZ_PASTE_PREFIX_AND_ARG_COUNT to work with 0 arguments. r=froydnj
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 25 May 2017 15:47:21 +0900
changeset 361705 2265602a89551359f9a31fee81887bd9a6360d53
parent 361704 80496d55346d35f5d14d656acfafff60e0c1870e
child 361706 899d3cbc450c37b27b7f3def83cc6836a61df09c
push id31939
push usercbook@mozilla.com
push dateThu, 01 Jun 2017 11:49:28 +0000
treeherdermozilla-central@d96110d76619 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1368932
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1368932 - Allow MOZ_PASTE_PREFIX_AND_ARG_COUNT to work with 0 arguments. r=froydnj At the same time, remove the MOZ_STATIC_ASSERT_VALID_ARG_COUNT, which doesn't actually work for more than 50 arguments(*), and which is now not useful to detect 0 arguments. (*) the build fails, but not directly thanks to the static_assert it expands to.
mfbt/Assertions.h
mfbt/MacroArgs.h
mfbt/MacroForEach.h
mfbt/tests/TestMacroArgs.cpp
xpcom/base/nsCycleCollectionParticipant.h
xpcom/base/nsIClassInfoImpl.h
xpcom/base/nsISupportsImpl.h
--- a/mfbt/Assertions.h
+++ b/mfbt/Assertions.h
@@ -309,17 +309,16 @@ MOZ_CrashPrintf(const char* aFilename, i
  * information is desired than a string literal can supply. The caller provides
  * a printf-style format string, which must be a string literal and between
  * 1 and 4 additional arguments. A regular MOZ_CRASH() is preferred wherever
  * possible, as passing arbitrary strings to printf from a potentially
  * compromised process is not without risk.
  */
 #define MOZ_CRASH_UNSAFE_PRINTF(format, ...) \
    do { \
-     MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \
      static_assert( \
        MOZ_PASTE_PREFIX_AND_ARG_COUNT(, __VA_ARGS__) <= sPrintfMaxArgs, \
        "Only up to 4 additional arguments are allowed!"); \
      static_assert(sizeof(format) <= sPrintfCrashReasonSize, \
        "The supplied format string is too long!"); \
      MOZ_CALL_CRASH_PRINTF("" format, __VA_ARGS__); \
    } while (0)
 
--- a/mfbt/MacroArgs.h
+++ b/mfbt/MacroArgs.h
@@ -16,87 +16,62 @@
 #define MOZ_CONCAT(x, y) MOZ_CONCAT2(x, y)
 
 /*
  * MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic
  * arguments and prefixes it with |aPrefix|. For example:
  *
  *   MOZ_PASTE_PREFIX_AND_ARG_COUNT(, foo, 42) expands to 2
  *   MOZ_PASTE_PREFIX_AND_ARG_COUNT(A, foo, 42, bar) expands to A3
+ *   MOZ_PASTE_PREFIX_AND_ARG_COUNT(A) expands to A0
+ *   MOZ_PASTE_PREFIX_AND_ARG_COUNT() expands to 0, but MSVC warns there
+ *   aren't enough arguments given.
  *
- * You must pass in between 1 and 50 (inclusive) variadic arguments, past
- * |aPrefix|. It is not legal to do
- *
- *   MOZ_PASTE_PREFIX_AND_ARG_COUNT(prefix)
+ * You must pass in between 0 and 50 (inclusive) variadic arguments, past
+ * |aPrefix|.
  *
- * (that is, pass in 0 variadic arguments). To ensure that a compile-time
- * error occurs when these constraints are violated, use the
- * MOZ_STATIC_ASSERT_VALID_ARG_COUNT macro with the same variaidc arguments
- * wherever this macro is used.
+ * The `##__VA_ARGS__` form is a GCC extension that removes the comma if
+ * __VA_ARGS__ is empty. It is supported by Clang too. MSVC ignores ##,
+ * and its default behavior is already to strip the comma when __VA_ARGS__
+ * is empty.
  *
- * Passing (__VA_ARGS__, <rest of arguments>) rather than simply calling
- * MOZ_MACROARGS_ARG_COUNT_HELPER2(__VA_ARGS__, <rest of arguments>) very
- * carefully tiptoes around a MSVC bug where it improperly expands __VA_ARGS__
- * as a single token in argument lists. For details, see:
- *
- *   http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement
- *   http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644
+ * So MOZ_MACROARGS_ARG_COUNT_HELPER(prefix) expands to
+ *   (_, prefix50, prefix49, ...)
+ * MOZ_MACROARGS_ARG_COUNT_HELPER(prefix, a) expands to
+ *   (_, a, prefix50, prefix49, ...)
+ * etc.
  */
 #define MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) \
-  MOZ_MACROARGS_ARG_COUNT_HELPER((__VA_ARGS__, \
+  MOZ_MACROARGS_ARG_COUNT_HELPER2( \
+    MOZ_MACROARGS_ARG_COUNT_HELPER(aPrefix, ##__VA_ARGS__))
+
+#define MOZ_MACROARGS_ARG_COUNT_HELPER(aPrefix, ...) (_, ##__VA_ARGS__, \
     aPrefix##50, aPrefix##49, aPrefix##48, aPrefix##47, aPrefix##46, \
     aPrefix##45, aPrefix##44, aPrefix##43, aPrefix##42, aPrefix##41, \
     aPrefix##40, aPrefix##39, aPrefix##38, aPrefix##37, aPrefix##36, \
     aPrefix##35, aPrefix##34, aPrefix##33, aPrefix##32, aPrefix##31, \
     aPrefix##30, aPrefix##29, aPrefix##28, aPrefix##27, aPrefix##26, \
     aPrefix##25, aPrefix##24, aPrefix##23, aPrefix##22, aPrefix##21, \
     aPrefix##20, aPrefix##19, aPrefix##18, aPrefix##17, aPrefix##16, \
     aPrefix##15, aPrefix##14, aPrefix##13, aPrefix##12, aPrefix##11, \
     aPrefix##10, aPrefix##9,  aPrefix##8,  aPrefix##7,  aPrefix##6,  \
-    aPrefix##5,  aPrefix##4,  aPrefix##3,  aPrefix##2,  aPrefix##1, aPrefix##0))
+    aPrefix##5,  aPrefix##4,  aPrefix##3,  aPrefix##2,  aPrefix##1, aPrefix##0)
 
-#define MOZ_MACROARGS_ARG_COUNT_HELPER(aArgs) \
-  MOZ_MACROARGS_ARG_COUNT_HELPER2 aArgs
+#define MOZ_MACROARGS_ARG_COUNT_HELPER2(aArgs) \
+  MOZ_MACROARGS_ARG_COUNT_HELPER3 aArgs
 
-#define MOZ_MACROARGS_ARG_COUNT_HELPER2( \
+#define MOZ_MACROARGS_ARG_COUNT_HELPER3(a0, \
    a1,  a2,  a3,  a4,  a5,  a6,  a7,  a8,  a9, a10, \
   a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, \
   a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, \
   a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, \
   a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, \
   a51, ...) a51
 
 /*
- * MOZ_STATIC_ASSERT_VALID_ARG_COUNT ensures that a compile-time error occurs
- * when the argument count constraints of MOZ_PASTE_PREFIX_AND_ARG_COUNT are
- * violated. Use this macro wherever MOZ_PASTE_PREFIX_AND_ARG_COUNT is used
- * and pass it the same variadic arguments.
- *
- * This macro employs a few dirty tricks to function. To detect the zero
- * argument case, |(__VA_ARGS__)| is stringified, sizeof-ed, and compared to
- * what it should be in the absence of arguments.
- *
- * Detecting too many arguments is a little trickier. With a valid argument
- * count and a prefix of 1, MOZ_PASTE_PREFIX_AND_ARG_COUNT expands to e.g. 14.
- * With a prefix of 0.0, it expands to e.g. 0.04. If there are too many
- * arguments, it expands to the first argument over the limit. If this
- * exceeding argument is a number, the assertion will fail as there is no
- * number than can simultaneously be both > 10 and == 0. If the exceeding
- * argument is not a number, a compile-time error should still occur due to
- * the operations performed on it.
- */
-#define MOZ_MACROARGS_STRINGIFY_HELPER(x) #x
-#define MOZ_STATIC_ASSERT_VALID_ARG_COUNT(...) \
-  static_assert( \
-    sizeof(MOZ_MACROARGS_STRINGIFY_HELPER((__VA_ARGS__))) != sizeof("()") && \
-      (MOZ_PASTE_PREFIX_AND_ARG_COUNT(1, __VA_ARGS__)) > 10 && \
-      (int)(MOZ_PASTE_PREFIX_AND_ARG_COUNT(0.0, __VA_ARGS__)) == 0, \
-    "MOZ_STATIC_ASSERT_VALID_ARG_COUNT requires 1 to 50 arguments") /* ; */
-
-/*
  * MOZ_ARGS_AFTER_N expands to its arguments excluding the first |N|
  * arguments. For example:
  *
  *   MOZ_ARGS_AFTER_2(a, b, c, d) expands to: c, d
  */
 #define MOZ_ARGS_AFTER_1(a1, ...) __VA_ARGS__
 #define MOZ_ARGS_AFTER_2(a1, a2, ...) __VA_ARGS__
 
--- a/mfbt/MacroForEach.h
+++ b/mfbt/MacroForEach.h
@@ -45,19 +45,17 @@
  *
  *   #define MACRO_B(t, n) t n
  *   void test(MOZ_FOR_EACH_SEPARATED(MACRO_B, (,), (int,), (a, b)));
  *   // Expands to: void test(MACRO_B(int, a) , MACRO_B(int, b));
  *   // And further to: void test(int a , int b);
  *
  * If the |aFixedArgs| list is not empty, a trailing comma must be included.
  *
- * The |aArgs| list must be not be empty and may be up to 50 items long. Use
- * MOZ_STATIC_ASSERT_VALID_ARG_COUNT to ensure that violating this constraint
- * results in a compile-time error.
+ * The |aArgs| list may be up to 50 items long.
  */
 #define MOZ_FOR_EACH_EXPAND_HELPER(...) __VA_ARGS__
 #define MOZ_FOR_EACH_GLUE(a, b) a b
 #define MOZ_FOR_EACH_SEPARATED(aMacro, aSeparator, aFixedArgs, aArgs) \
   MOZ_FOR_EACH_GLUE( \
     MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_FOR_EACH_, \
                                    MOZ_FOR_EACH_EXPAND_HELPER aArgs), \
     (aMacro, aSeparator, aFixedArgs, aArgs))
@@ -65,16 +63,17 @@
   MOZ_FOR_EACH_SEPARATED(aMacro, (), aFixedArgs, aArgs)
 
 #define MOZ_FOR_EACH_HELPER_GLUE(a, b) a b
 #define MOZ_FOR_EACH_HELPER(aMacro, aFixedArgs, aArgs) \
   MOZ_FOR_EACH_HELPER_GLUE( \
     aMacro, \
     (MOZ_FOR_EACH_EXPAND_HELPER aFixedArgs MOZ_ARG_1 aArgs))
 
+#define MOZ_FOR_EACH_0(m, s, fa, a)
 #define MOZ_FOR_EACH_1(m, s, fa, a) \
   MOZ_FOR_EACH_HELPER(m, fa, a)
 #define MOZ_FOR_EACH_2(m, s, fa, a) \
   MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_EXPAND_HELPER s \
   MOZ_FOR_EACH_1(m, s, fa, (MOZ_ARGS_AFTER_1 a))
 #define MOZ_FOR_EACH_3(m, s, fa, a) \
   MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_EXPAND_HELPER s \
   MOZ_FOR_EACH_2(m, s, fa, (MOZ_ARGS_AFTER_1 a))
--- a/mfbt/tests/TestMacroArgs.cpp
+++ b/mfbt/tests/TestMacroArgs.cpp
@@ -1,19 +1,19 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/MacroArgs.h"
 
-MOZ_STATIC_ASSERT_VALID_ARG_COUNT(1);
-MOZ_STATIC_ASSERT_VALID_ARG_COUNT(1, 2);
-
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100) == 1000, "");
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100, a) == 1001, "");
+static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100, a, b) == 1002, "");
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(100, a, b, c) == 1003, "");
 
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, a, b, c) == 3, "");
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, a) == 1, "");
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, !a) == 1, "");
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, (a, b)) == 1, "");
 
 static_assert(MOZ_PASTE_PREFIX_AND_ARG_COUNT(, MOZ_ARGS_AFTER_1(a, b, c)) == 2,
--- a/xpcom/base/nsCycleCollectionParticipant.h
+++ b/xpcom/base/nsCycleCollectionParticipant.h
@@ -437,17 +437,16 @@ DowncastCCParticipant(void* aPtr)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                                \
     nsISupports *s = static_cast<nsISupports*>(p);                             \
     NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Unlink(s);
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_HELPER(_field)                        \
   ImplCycleCollectionUnlink(tmp->_field);
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK(...)                                   \
-  MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__);                              \
   MOZ_FOR_EACH(NS_IMPL_CYCLE_COLLECTION_UNLINK_HELPER, (), (__VA_ARGS__))
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                    \
     (void)tmp;                                                                 \
   }
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(_base_class)             \
     nsISupports *s = static_cast<nsISupports*>(p);                             \
@@ -489,17 +488,16 @@ DowncastCCParticipant(void* aPtr)
         == NS_SUCCESS_INTERRUPTED_TRAVERSE) {                                  \
       return NS_SUCCESS_INTERRUPTED_TRAVERSE;                                  \
     }
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_HELPER(_field)                       \
   ImplCycleCollectionTraverse(cb, tmp->_field, #_field, 0);
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE(...)                                 \
-  MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__);                              \
   MOZ_FOR_EACH(NS_IMPL_CYCLE_COLLECTION_TRAVERSE_HELPER, (), (__VA_ARGS__))
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(_field)                       \
   CycleCollectionNoteChild(cb, tmp->_field, #_field);
 
 #define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                                  \
     (void)tmp;                                                                 \
     return NS_OK;                                                              \
--- a/xpcom/base/nsIClassInfoImpl.h
+++ b/xpcom/base/nsIClassInfoImpl.h
@@ -151,25 +151,23 @@ NS_CI_INTERFACE_GETTER_NAME(_class)(uint
                                             sizeof(nsIID));
 
 #define NS_CLASSINFO_HELPER_END                                               \
     MOZ_ASSERT(i == *count, "Incorrent number of entries");                   \
     return NS_OK;                                                             \
 }
 
 #define NS_IMPL_CI_INTERFACE_GETTER(aClass, ...)                              \
-  MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__);                             \
   NS_CLASSINFO_HELPER_BEGIN(aClass,                                           \
                             MOZ_PASTE_PREFIX_AND_ARG_COUNT(/* No prefix */,   \
                                                            __VA_ARGS__))      \
     MOZ_FOR_EACH(NS_CLASSINFO_HELPER_ENTRY, (), (__VA_ARGS__))                \
   NS_CLASSINFO_HELPER_END
 
 #define NS_IMPL_QUERY_INTERFACE_CI(aClass, ...)                               \
-  MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__);                             \
   NS_INTERFACE_MAP_BEGIN(aClass)                                              \
     MOZ_FOR_EACH(NS_INTERFACE_MAP_ENTRY, (), (__VA_ARGS__))                   \
     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, MOZ_ARG_1(__VA_ARGS__))     \
     NS_IMPL_QUERY_CLASSINFO(aClass)                                           \
   NS_INTERFACE_MAP_END
 
 #define NS_IMPL_ISUPPORTS_CI(aClass, ...)                                     \
   NS_IMPL_ADDREF(aClass)                                                      \
--- a/xpcom/base/nsISupportsImpl.h
+++ b/xpcom/base/nsISupportsImpl.h
@@ -955,17 +955,16 @@ NS_IMETHODIMP _class::QueryInterface(REF
   NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator)
 
 #define NS_INTERFACE_TABLE0(_class)                                           \
   NS_INTERFACE_TABLE_BEGIN                                                    \
     NS_INTERFACE_TABLE_ENTRY(_class, nsISupports)                             \
   NS_INTERFACE_TABLE_END
 
 #define NS_INTERFACE_TABLE(aClass, ...)                                       \
-  MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__);                             \
   NS_INTERFACE_TABLE_BEGIN                                                    \
     MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass,), (__VA_ARGS__))          \
     NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(aClass, nsISupports,                   \
                                        MOZ_ARG_1(__VA_ARGS__))                \
   NS_INTERFACE_TABLE_END
 
 #define NS_IMPL_QUERY_INTERFACE0(_class)                                      \
   NS_INTERFACE_TABLE_HEAD(_class)                                             \
@@ -1036,17 +1035,16 @@ NS_IMETHODIMP_(MozExternalRefCountType) 
 NS_IMETHODIMP_(MozExternalRefCountType) Class::Release(void)                  \
 {                                                                             \
   return Super::Release();                                                    \
 }
 
 #define NS_INTERFACE_TABLE_INHERITED0(Class) /* Nothing to do here */
 
 #define NS_INTERFACE_TABLE_INHERITED(aClass, ...)                             \
-  MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__);                             \
   NS_INTERFACE_TABLE_BEGIN                                                    \
     MOZ_FOR_EACH(NS_INTERFACE_TABLE_ENTRY, (aClass,), (__VA_ARGS__))          \
   NS_INTERFACE_TABLE_END
 
 #define NS_IMPL_QUERY_INTERFACE_INHERITED(aClass, aSuper, ...)                \
   NS_INTERFACE_TABLE_HEAD(aClass)                                             \
   NS_INTERFACE_TABLE_INHERITED(aClass, __VA_ARGS__)                           \
   NS_INTERFACE_TABLE_TAIL_INHERITING(aSuper)