From 661dd91603397fe1b180ad83e29e809cfe4b9f2f Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Wed, 13 Nov 2019 20:38:10 -0500 Subject: [PATCH] Added explicit test with the alias 'test_iso' to run tests for macro expansion for the various C++ standards. --- test/Jamfile.v2 | 5 + test/cpp_standard.cpp | 545 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 550 insertions(+) create mode 100644 test/cpp_standard.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index fbda6c0..445a8e1 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -262,3 +262,8 @@ alias test_clang_cuda ; explicit test_clang_cuda ; + +alias test_iso + : + [ run cpp_standard.cpp ] + ; diff --git a/test/cpp_standard.cpp b/test/cpp_standard.cpp new file mode 100644 index 0000000..8b926ba --- /dev/null +++ b/test/cpp_standard.cpp @@ -0,0 +1,545 @@ +#include +#include +#include +#include + +static unsigned int indent = 4; +static unsigned int width = 90; + +using std::cout; +using std::istream; + +void print_separator() +{ + std::cout << +"\n\n*********************************************************************\n\n"; +} + +std::string remove_spaces(const std::string ss) + { + + bool inquotes(false); + bool escape(false); + char qchar; + int len(static_cast(ss.length())); + + std::string ret; + + for (int i = 0; i < len; ++i) + { + + char ch(ss[i]); + + if (inquotes) + { + if (escape) + { + escape = false; + } + else if (ch == '\\') + { + escape = true; + } + else if (ch == qchar) + { + inquotes = false; + } + ret.push_back(ch); + } + else + { + if (ch == '\'' || ch == '"') + { + inquotes = true; + qchar = ch; + ret.push_back(ch); + } + else if (ch != ' ') + { + ret.push_back(ch); + } + } + } + + return ret; + } + +int print_macro(const std::string name,const std::string expected, const std::string expansion) +{ + int bret(0); + const std::string sg("Success: "); + const std::string sb("Failure: "); + for(unsigned i = 0; i < indent; ++i) std::cout.put(' '); + if (name == expansion) + { + if (expected == expansion) + { + std::cout << sg; + std::cout << std::setw(width); + cout.setf(istream::left, istream::adjustfield); + std::cout << name; + std::cout << " [no value]\n"; + } + else + { + std::cout << sb; + std::cout << std::setw(width); + cout.setf(istream::left, istream::adjustfield); + std::cout << name; + std::cout << " [no value]: "; + std::cout << " [expected]: "; + std::cout << expected << "\n"; + bret = 1; + } + } + else + { + + std::string sexpected(remove_spaces(expected)); + std::string sexpansion(remove_spaces(expansion)); + + if (sexpected == sexpansion) + { + std::cout << sg; + std::cout << std::setw(width); + cout.setf(istream::left, istream::adjustfield); + std::cout << name; + std::cout << expansion << "\n"; + } + else + { + std::cout << sb; + std::cout << std::setw(width); + cout.setf(istream::left, istream::adjustfield); + std::cout << name; + std::cout << expansion; + std::cout << " [expected]: "; + std::cout << expected << "\n"; + bret = 1; + } + } + return bret; +} + +#if !BOOST_PP_VARIADICS + +#define STRINGIZE(arg) # arg + +#define PRINT_MACRO_RESULTS(X,exp) print_macro(std::string(# X), std::string(# exp), std::string(STRINGIZE(X))) +#define PRINT_MACRO(x) std::string(# x) +#define PRINT_EXPECTED(x) std::string(# x) +#define PRINT_EXPANSION(x) std::string(STRINGIZE(x)) + +#else + +#define STRINGIZE(...) # __VA_ARGS__ + +#define PRINT_MACRO_RESULTS(X,...) print_macro(std::string(# X), std::string(# __VA_ARGS__), std::string(STRINGIZE(X))) +#define PRINT_MACRO(...) std::string(# __VA_ARGS__) +#define PRINT_EXPECTED(...) std::string(# __VA_ARGS__) +#define PRINT_EXPANSION(...) std::string(STRINGIZE(__VA_ARGS__)) + +#endif + +#if __cplusplus > 201703L + +int print_macros_common_c20() +{ + + int bret = 0; + +#define LPAREN() ( +#define G(Q) 42 +#define F(R, X, ...) __VA_OPT__(G R X) ) + +// int x = F(LPAREN(), 0, <:-); + +// replaced by + +// int x = 42; + +bret += PRINT_MACRO_RESULTS(int x = F(LPAREN(), 0, <:-);,int x = 42;); + +#undef LPAREN +#undef G +#undef F + +#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__) +#define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__) +#define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ }) +#define EMP + +// F(a, b, c) +// F() +// F(EMP) + +// replaced by + +// f(0, a, b, c) +// f(0) +// f(0) + +// G(a, b, c) +// G(a, ) +// G(a) + +// replaced by + +// f(0, a, b, c) +// f(0, a) +// f(0, a) + +// SDEF(foo); +// SDEF(bar, 1, 2); + +// replaced by + +// S foo; +// S bar = { 1, 2 }; + +bret += PRINT_MACRO_RESULTS(F(a, b, c),f(0, a, b, c)); +bret += PRINT_MACRO_RESULTS(F(),f(0)); +bret += PRINT_MACRO_RESULTS(F(EMP),f(0)); +bret += PRINT_MACRO_RESULTS(G(a, b, c),f(0, a, b, c)); +bret += PRINT_MACRO_RESULTS(G(a, ),f(0, a)); +bret += PRINT_MACRO_RESULTS(G(a),f(0, a)); +bret += PRINT_MACRO_RESULTS(SDEF(foo);,S foo;); +bret += PRINT_MACRO_RESULTS(SDEF(bar, 1, 2);,S bar = { 1, 2 };); + +#undef F +#undef G +#undef SDEF +#undef EMP + +#define H2(X, Y, ...) __VA_OPT__(X ## Y,) __VA_ARGS__ +#define H3(X, ...) #__VA_OPT__(X##X X##X) +#define H4(X, ...) __VA_OPT__(a X ## X) ## b +#define H5A(...) __VA_OPT__()/**/__VA_OPT__() +#define H5B(X) a ## X ## b +#define H5C(X) H5B(X) + +// H2(a, b, c, d) + +// replaced by + +// ab, c, d + +// H3(, 0) + +// replaced by + +// "" + +// H4(, 1) + +// replaced by + +// a b + +// H5C(H5A()) + +// replaced by + +// ab + +bret += PRINT_MACRO_RESULTS(H2(a, b, c, d),ab, c, d); +bret += PRINT_MACRO_RESULTS(H3(, 0),""); +bret += PRINT_MACRO_RESULTS(H4(, 1),a b); +bret += PRINT_MACRO_RESULTS(H5C(H5A()),ab); + +#undef H2 +#undef H3 +#undef H4 +#undef H5A +#undef H5B +#undef H5C + + return bret; + +} + +#endif + +int print_macros_common_1() +{ + + int bret = 0; + +#define x 3 +#define f(a) f(x * (a)) +#undef x + +#define x 2 +#define g f +#define z z[0] +#define h g(~ +#define m(a) a(w) +#define w 0,1 +#define t(a) a + +// f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); +// g(x+(3,4)-w) | h 5) & m(f)^m(m); + +// results in + +// f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); +// f(2 * (2+(3,4)-0,1)) | f(2 * ( ~ 5)) & f(2 * (0,1))^m(0,1); + +bret += PRINT_MACRO_RESULTS(f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);,f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);); + +#define PRINT_INPUT g(x+(3,4)-w) | h 5) & m(f)^m(m); + +bret += print_macro + ( + std::string("g(x+(3,4)-w) | h 5) & m(f)^m(m);"), + PRINT_EXPECTED(f(2 * (2+(3,4)-0,1)) | f(2 * ( ~ 5)) & f(2 * (0,1))^m(0,1);), + PRINT_EXPANSION(PRINT_INPUT) + ); + +#undef PRINT_INPUT + +#undef f +#undef x +#undef g +#undef z +#undef h +#undef m +#undef w +#undef t + + return bret; + +} + +int print_macros_common_4() +{ + + int bret = 0; + +#define str(s) # s +#define xstr(s) str(s) +#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", x ## s, x ## t) +#define INCFILE(n) vers ## n +#define glue(a, b) a ## b +#define xglue(a, b) glue(a, b) +#define HIGHLOW "hello" +#define LOW LOW ", world" + +// debug(1, 2); +// fputs(str(strncmp("abc\0d", "abc", ’\4’) // this goes away +// == 0) str(: @\n), s); +// #include xstr(INCFILE(2).h) +// glue(HIGH, LOW); +// xglue(HIGH, LOW) + +// results in + +// printf("x" "1" "= %d, x" "2" "= %s", x1, x2); +// fputs("strncmp(\"abc\\0d\", \"abc\", ’\\4’) == 0" ": @\n", s); +// #include "vers2.h" (after macro replacement, before file access) +// "hello"; +// "hello" ", world" + +bret += PRINT_MACRO_RESULTS(debug(1, 2);,printf("x" "1" "= %d, x" "2" "= %s", x1, x2);); +bret += print_macro + ( + std::string("fputs(str(strncmp(\"abc\\0d\", \"abc\", '\\4') /* this goes away */== 0) str(: @\\n), s);"), + PRINT_EXPECTED(fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s);), + PRINT_EXPANSION(fputs(str(strncmp("abc\0d", "abc", '\4') /* this goes away */== 0) str(: @\n), s);) + ); +bret += PRINT_MACRO_RESULTS(xstr(INCFILE(2).h),"vers2.h"); +bret += PRINT_MACRO_RESULTS(glue(HIGH, LOW);,"hello";); + +#if __cplusplus <= 199711L + +bret += print_macro + ( + PRINT_MACRO(xglue(HIGH, LOW)), + std::string("\"hello\" \", world\""), + PRINT_EXPANSION(xglue(HIGH, LOW)) + ); + +#else + +bret += PRINT_MACRO_RESULTS(xglue(HIGH, LOW),"hello" ", world"); + +#endif + +#undef str +#undef xstr +#undef debug +#undef INCFILE +#undef glue +#undef xglue +#undef HIGHLOW +#undef LOW + + return bret; + +} + +#if BOOST_PP_VARIADICS || __cplusplus > 199711L + +int print_macros_common_2() +{ + + int bret = 0; + +#define hash_hash # ## # +#define mkstr(a) # a +#define in_between(a) mkstr(a) +#define join(c, d) in_between(c hash_hash d) + +// char p[] = join(x, y); + +// equivalent to + +// char p[] = "x ## y"; + +bret += PRINT_MACRO_RESULTS(char p[] = join(x, y);,char p[] = "x ## y";); + +#undef hash_hash +#undef mkstr +#undef in_between +#undef join + + return bret; + +} + +int print_macros_common_3() +{ + + int bret = 0; + +#define p() int +#define q(x) x +#define r(x,y) x ## y +#define str(x) # x + +// p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) }; +// char c[2][6] = { str(hello), str() }; + +// results in + +// int i[] = { 1, 23, 4, 5, }; +// char c[2][6] = { "hello", "" }; + +bret += print_macro + ( + PRINT_MACRO(p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };), + PRINT_EXPECTED(int i[] = { 1, 23, 4, 5, };), + PRINT_EXPANSION(p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };) + ); +bret += print_macro + ( + PRINT_MACRO(char c[2][6] = { str(hello), str() };), + PRINT_EXPECTED(char c[2][6] = { "hello", "" };), + PRINT_EXPANSION(char c[2][6] = { str(hello), str() };) + ); + +#undef p +#undef q +#undef r +#undef str + +bret += print_macros_common_4(); + +#define t(x,y,z) x ## y ## z + +// int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), t(10,,), t(,11,), t(,,12), t(,,) }; + +// results in + +// int j[] = { 123, 45, 67, 89, 10, 11, 12, }; + +bret += print_macro + ( + PRINT_MACRO(int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), t(10,,), t(,11,), t(,,12), t(,,) };), + PRINT_EXPECTED(int j[] = { 123, 45, 67, 89, 10, 11, 12, };), + PRINT_EXPANSION(int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), t(10,,), t(,11,), t(,,12), t(,,) };) + ); + +#undef t + +#define debug(...) fprintf(stderr, __VA_ARGS__) +#define showlist(...) puts(#__VA_ARGS__) +#define report(test, ...) ((test) ? puts(#test) : printf(__VA_ARGS__)) + +// debug("Flag"); +// debug("X = %d\n", x); +// showlist(The first, second, and third items.); +// report(x>y, "x is %d but y is %d", x, y); + +// results in + +// fprintf(stderr, "Flag"); +// fprintf(stderr, "X = %d\n", x); +// puts("The first, second, and third items."); +// ((x>y) ? puts("x>y") : printf("x is %d but y is %d", x, y)); + +#define save_stderr stderr +#undef stderr + +bret += PRINT_MACRO_RESULTS(debug("Flag");,fprintf(stderr, "Flag");); +bret += PRINT_MACRO_RESULTS(debug("X = %d\n", x);,fprintf(stderr, "X = %d\n", x);); + +#define stderr save_stderr + +bret += PRINT_MACRO_RESULTS(showlist(The first, second, and third items.);,puts("The first, second, and third items.");); +bret += PRINT_MACRO_RESULTS(report(x>y, "x is %d but y is %d", x, y);,((x>y) ? puts("x>y") : printf("x is %d but y is %d", x, y));); + +#undef debug +#undef showlist +#undef report + + return bret; + +} + +#endif + +int print_macros() +{ + int bret = 0; + + print_separator(); + + std::cout << "__cplusplus = " << __cplusplus; + + print_separator(); + +#define OBJ_LIKE (1-1) +#define OBJ_LIKE /* white space */ (1-1) /* other */ +#define FTN_LIKE(a) ( a ) +#define FTN_LIKE( a )( /* note the white space */ a /* other stuff on this line */ ) + +#if __cplusplus <= 199711L && !BOOST_PP_VARIADICS + +bret += print_macros_common_1(); +bret += print_macros_common_4(); + +#elif __cplusplus <= 201703L + +bret += print_macros_common_2(); +bret += print_macros_common_1(); +bret += print_macros_common_3(); + +#else + +bret += print_macros_common_c20(); +bret += print_macros_common_2(); +bret += print_macros_common_1(); +bret += print_macros_common_3(); + +#endif + + print_separator(); + + return bret; +} + +int main() +{ + return (print_macros()); +}