Bug 1368932 - Allow MOZ_PASTE_PREFIX_AND_ARG_COUNT to work with 0 arguments. r?froydnj draft
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 25 May 2017 15:47:21 +0900
changeset 586887 475e999c64657de22ce81d316a16044e5e4ad60e
parent 586886 74f38b4f44d698664b0129d0cf2bee63e9aefa93
child 586888 ea9fcd289efcc9467d032a209e15906acb9ea6c3
child 587414 0f1f28d6f6e88d58f68af5caa8e0571e995bd83e
push id61568
push userbmo:mh+mozilla@glandium.org
push dateWed, 31 May 2017 08:30:17 +0000
reviewersfroydnj
bugs1368932
milestone55.0a1
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)