Deal with some oddities of MSVC's preprocessor
authorChristopher Dykes <cdykes@fb.com>
Tue, 10 May 2016 00:23:41 +0000 (17:23 -0700)
committerFacebook Github Bot 9 <facebook-github-bot-9-bot@fb.com>
Tue, 10 May 2016 00:35:24 +0000 (17:35 -0700)
Summary: MSVC's preprocessor is different in how it deals with passing arguments expanded from `__VA_ARGS__`, so we have to add a stub to force it to expand the arguments.

Reviewed By: yfeldblum

Differential Revision: D3256328

fbshipit-source-id: 551434833d40e55498a9ab352eb74acdfd094835

folly/Preprocessor.h
folly/Synchronized.h

index 393016bdc8c5a2bd81abd4ab88cec15744206f25..800608d4afc3562569c50e048299ceca03ff7b18 100644 (file)
 #define FB_THIRD(a, b, ...) __VA_ARGS__
 #endif
 
+// MSVC's preprocessor is a pain, so we have to
+// forcefully expand the VA args in some places.
+#define FB_VA_GLUE(a, b) a b
+
 /**
  * Helper macro that extracts the first argument out of a list of any
  * number of arguments.
  * number of arguments. If only one argument is given, it returns
  * that.
  */
+#ifdef _MSC_VER
+// GCC refuses to expand this correctly if this macro itself was
+// called with FB_VA_GLUE :(
+#define FB_ARG_2_OR_1(...) \
+  FB_VA_GLUE(FB_ARG_2_OR_1_IMPL, (__VA_ARGS__, __VA_ARGS__))
+#else
 #define FB_ARG_2_OR_1(...) FB_ARG_2_OR_1_IMPL(__VA_ARGS__, __VA_ARGS__)
+#endif
 // Support macro for the above
 #define FB_ARG_2_OR_1_IMPL(a, b, ...) b
 
index 5ea2ad54247efa5989f59b1cab6273b0eb5aa0f6..4b6a25b80cb71ebc5d9c2b66c38342eacd5e82c1 100644 (file)
@@ -680,40 +680,49 @@ void swap(Synchronized<T, M>& lhs, Synchronized<T, M>& rhs) {
  * Refer to folly/docs/Synchronized.md for a detailed explanation and more
  * examples.
  */
-#define SYNCHRONIZED(...)                                       \
-  FOLLY_PUSH_WARNING                                            \
-  FOLLY_GCC_DISABLE_WARNING(shadow)                             \
-  if (bool SYNCHRONIZED_state = false) {} else                  \
-    for (auto SYNCHRONIZED_lockedPtr =                          \
-           (FB_ARG_2_OR_1(__VA_ARGS__)).operator->();           \
-         !SYNCHRONIZED_state; SYNCHRONIZED_state = true)        \
-      for (auto& FB_ARG_1(__VA_ARGS__) =                        \
-             *SYNCHRONIZED_lockedPtr.operator->();              \
-           !SYNCHRONIZED_state; SYNCHRONIZED_state = true)      \
+#define SYNCHRONIZED(...)                                             \
+  FOLLY_PUSH_WARNING                                                  \
+  FOLLY_GCC_DISABLE_WARNING(shadow)                                   \
+  if (bool SYNCHRONIZED_state = false) {                              \
+  } else                                                              \
+    for (auto SYNCHRONIZED_lockedPtr =                                \
+             (FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))).operator->(); \
+         !SYNCHRONIZED_state;                                         \
+         SYNCHRONIZED_state = true)                                   \
+      for (auto& FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)) =                \
+               *SYNCHRONIZED_lockedPtr.operator->();                  \
+           !SYNCHRONIZED_state;                                       \
+           SYNCHRONIZED_state = true)                                 \
   FOLLY_POP_WARNING
 
-#define TIMED_SYNCHRONIZED(timeout, ...)                           \
-  if (bool SYNCHRONIZED_state = false) {} else                     \
-    for (auto SYNCHRONIZED_lockedPtr =                             \
-           (FB_ARG_2_OR_1(__VA_ARGS__)).timedAcquire(timeout);     \
-         !SYNCHRONIZED_state; SYNCHRONIZED_state = true)           \
-      for (auto FB_ARG_1(__VA_ARGS__) =                            \
-             SYNCHRONIZED_lockedPtr.operator->();                  \
-           !SYNCHRONIZED_state; SYNCHRONIZED_state = true)
+#define TIMED_SYNCHRONIZED(timeout, ...)                                       \
+  if (bool SYNCHRONIZED_state = false) {                                       \
+  } else                                                                       \
+    for (auto SYNCHRONIZED_lockedPtr =                                         \
+             (FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))).timedAcquire(timeout); \
+         !SYNCHRONIZED_state;                                                  \
+         SYNCHRONIZED_state = true)                                            \
+      for (auto FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)) =                          \
+               SYNCHRONIZED_lockedPtr.operator->();                            \
+           !SYNCHRONIZED_state;                                                \
+           SYNCHRONIZED_state = true)
 
 /**
  * Similar to SYNCHRONIZED, but only uses a read lock.
  */
-#define SYNCHRONIZED_CONST(...)                         \
-  SYNCHRONIZED(FB_ARG_1(__VA_ARGS__),                   \
-               (FB_ARG_2_OR_1(__VA_ARGS__)).asConst())
+#define SYNCHRONIZED_CONST(...)            \
+  SYNCHRONIZED(                            \
+      FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)), \
+      (FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))).asConst())
 
 /**
  * Similar to TIMED_SYNCHRONIZED, but only uses a read lock.
  */
-#define TIMED_SYNCHRONIZED_CONST(timeout, ...)                  \
-  TIMED_SYNCHRONIZED(timeout, FB_ARG_1(__VA_ARGS__),            \
-                     (FB_ARG_2_OR_1(__VA_ARGS__)).asConst())
+#define TIMED_SYNCHRONIZED_CONST(timeout, ...) \
+  TIMED_SYNCHRONIZED(                          \
+      timeout,                                 \
+      FB_VA_GLUE(FB_ARG_1, (__VA_ARGS__)),     \
+      (FB_VA_GLUE(FB_ARG_2_OR_1, (__VA_ARGS__))).asConst())
 
 /**
  * Temporarily disables synchronization inside a SYNCHRONIZED block.