Skip to content

Commit

Permalink
Fixed MSVC issues with variadic macros
Browse files Browse the repository at this point in the history
  • Loading branch information
ludocode committed Oct 20, 2018
1 parent 90d6865 commit a2049b9
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 15 deletions.
33 changes: 21 additions & 12 deletions src/mpack/mpack-platform.h
Expand Up @@ -199,15 +199,24 @@ MPACK_HEADER_START
#define MPACK_STRINGIFY_IMPL(arg) #arg
#define MPACK_STRINGIFY(arg) MPACK_STRINGIFY_IMPL(arg)

// This is a workaround for MSVC's incorrect expansion of __VA_ARGS__. It
// treats __VA_ARGS__ as a single preprocessor token when passed in the
// argument list of another macro unless we use an outer wrapper to expand it
// lexically first. (For safety/consistency we use this in all variadic macros
// that don't ignore the variadic arguments regardless of whether __VA_ARGS__
// is passed to another macro.)
// https://stackoverflow.com/a/32400131
#define MPACK_EXPAND(x) x

// Extracts the first argument of a variadic macro list, where there might only
// be one argument.
#define MPACK_EXTRACT_ARG0_IMPL(first, ...) first
#define MPACK_EXTRACT_ARG0(...) MPACK_EXTRACT_ARG0_IMPL( __VA_ARGS__ , ignored)
#define MPACK_EXTRACT_ARG0(...) MPACK_EXPAND(MPACK_EXTRACT_ARG0_IMPL( __VA_ARGS__ , ignored))

// Stringifies the first argument of a variadic macro list, where there might
// only be one argument.
#define MPACK_STRINGIFY_ARG0_impl(first, ...) #first
#define MPACK_STRINGIFY_ARG0(...) MPACK_STRINGIFY_ARG0_impl( __VA_ARGS__ , ignored)
#define MPACK_STRINGIFY_ARG0(...) MPACK_EXPAND(MPACK_STRINGIFY_ARG0_impl( __VA_ARGS__ , ignored))



Expand Down Expand Up @@ -648,14 +657,14 @@ MPACK_HEADER_START
#if MPACK_STDIO
MPACK_NORETURN(void mpack_assert_fail_format(const char* format, ...));
#define mpack_assert_fail_at(line, file, exprstr, format, ...) \
mpack_assert_fail_format("mpack assertion failed at " file ":" #line "\n%s\n" format, exprstr, __VA_ARGS__)
MPACK_EXPAND(mpack_assert_fail_format("mpack assertion failed at " file ":" #line "\n%s\n" format, exprstr, __VA_ARGS__))
#else
#define mpack_assert_fail_at(line, file, exprstr, format, ...) \
mpack_assert_fail_wrapper("mpack assertion failed at " file ":" #line "\n" exprstr "\n")
#endif

#define mpack_assert_fail_pos(line, file, exprstr, expr, ...) \
mpack_assert_fail_at(line, file, exprstr, __VA_ARGS__)
MPACK_EXPAND(mpack_assert_fail_at(line, file, exprstr, __VA_ARGS__))

// This contains a workaround to the pedantic C99 requirement of having at
// least one argument to a variadic macro. The first argument is the
Expand All @@ -671,26 +680,26 @@ MPACK_HEADER_START
// -Wformat and __attribute__((format)) on mpack_assert_fail_format() if we
// ever bothered to implement it.
#define mpack_assert(...) \
((!(MPACK_EXTRACT_ARG0(__VA_ARGS__))) ? \
MPACK_EXPAND(((!(MPACK_EXTRACT_ARG0(__VA_ARGS__))) ? \
mpack_assert_fail_pos(__LINE__, __FILE__, MPACK_STRINGIFY_ARG0(__VA_ARGS__) , __VA_ARGS__ , "", NULL) : \
(void)0)
(void)0))

void mpack_break_hit(const char* message);
#if MPACK_STDIO
void mpack_break_hit_format(const char* format, ...);
#define mpack_break_hit_at(line, file, ...) \
mpack_break_hit_format("mpack breakpoint hit at " file ":" #line "\n" __VA_ARGS__)
MPACK_EXPAND(mpack_break_hit_format("mpack breakpoint hit at " file ":" #line "\n" __VA_ARGS__))
#else
#define mpack_break_hit_at(line, file, ...) \
mpack_break_hit("mpack breakpoint hit at " file ":" #line )
#endif
#define mpack_break_hit_pos(line, file, ...) mpack_break_hit_at(line, file, __VA_ARGS__)
#define mpack_break(...) mpack_break_hit_pos(__LINE__, __FILE__, __VA_ARGS__)
#define mpack_break_hit_pos(line, file, ...) MPACK_EXPAND(mpack_break_hit_at(line, file, __VA_ARGS__))
#define mpack_break(...) MPACK_EXPAND(mpack_break_hit_pos(__LINE__, __FILE__, __VA_ARGS__))
#else
#define mpack_assert(...) \
((!(MPACK_EXTRACT_ARG0(__VA_ARGS__))) ? \
(MPACK_EXPAND((!(MPACK_EXTRACT_ARG0(__VA_ARGS__))) ? \
(MPACK_UNREACHABLE, (void)0) : \
(void)0)
(void)0))
#define mpack_break(...) ((void)0)
#endif

Expand Down Expand Up @@ -780,7 +789,7 @@ size_t mpack_strlen(const char* s);
/* Debug logging */
#if 0
#include <stdio.h>
#define mpack_log(...) (printf(__VA_ARGS__), fflush(stdout))
#define mpack_log(...) (MPACK_EXPAND(printf(__VA_ARGS__), fflush(stdout)))
#else
#define mpack_log(...) ((void)0)
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/mpack/mpack-writer.c
Expand Up @@ -742,7 +742,7 @@ MPACK_STATIC_INLINE void mpack_encode_timestamp_12(char* p, int64_t seconds, uin
// it will flag an error so we don't have to do anything.
#define MPACK_WRITE_ENCODED(encode_fn, size, ...) do { \
if (MPACK_LIKELY(mpack_writer_buffer_left(writer) >= size) || mpack_writer_ensure(writer, size)) { \
encode_fn(writer->current, __VA_ARGS__); \
MPACK_EXPAND(encode_fn(writer->current, __VA_ARGS__)); \
writer->current += size; \
} \
} while (0)
Expand Down
4 changes: 2 additions & 2 deletions test/test.h
Expand Up @@ -92,10 +92,10 @@ extern "C" {
// runs the given expression, causing a unit test failure with the
// given printf format string if the expression is not true.
#define TEST_TRUE(...) \
TEST_TRUE_IMPL((MPACK_EXTRACT_ARG0(__VA_ARGS__)), __FILE__, __LINE__, __VA_ARGS__ , "" , NULL)
MPACK_EXPAND(TEST_TRUE_IMPL((MPACK_EXTRACT_ARG0(__VA_ARGS__)), __FILE__, __LINE__, __VA_ARGS__ , "" , NULL))

#define TEST_TRUE_IMPL(result, file, line, ignored, ...) \
test_true_impl(result, file, line, __VA_ARGS__)
MPACK_EXPAND(test_true_impl(result, file, line, __VA_ARGS__))

void test_true_impl(bool result, const char* file, int line, const char* format, ...);

Expand Down

0 comments on commit a2049b9

Please sign in to comment.