diff --git a/Jamroot b/Jamroot index 20d9622..6a2fc5a 100644 --- a/Jamroot +++ b/Jamroot @@ -12,11 +12,8 @@ use-project boost : $(BOOST_ROOT) ; project : requirements - msvc:/Wall gcc:-std=c++11 - gcc:-Wall clang:-std=c++11 - clang:-Wall "./include" $(BOOST_ROOT) $(BOOST_ROOT)/stage/lib diff --git a/include/boost/contract/ext_/preprocessor/keyword/utility/remove.hpp b/include/boost/contract/ext_/preprocessor/keyword/utility/remove.hpp index a504c04..bed132f 100644 --- a/include/boost/contract/ext_/preprocessor/keyword/utility/remove.hpp +++ b/include/boost/contract/ext_/preprocessor/keyword/utility/remove.hpp @@ -8,12 +8,13 @@ // NOTE: All these levels of indirection (instead of doing the PP_CAT directly) // are necessary to ensure proper macro expansion on MSVC which would otherwise -// get confused sometimes. - -#define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REMOVE_EXPAND1_(x) x +// get confused sometimes. Also, use its own implementation of EXPAND_ONCE to +// avoid reentrancy issues. +#define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REMOVE_EXPAND_ONCE_(x) x #define BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REMOVE_CAT_(a, b) \ - BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REMOVE_EXPAND1_(BOOST_PP_CAT(a, b)) + BOOST_CONTRACT_EXT_PP_KEYWORD_UTILITY_REMOVE_EXPAND_ONCE_( \ + BOOST_PP_CAT(a, b)) /* PUBLIC */ diff --git a/include/boost/contract/ext_/preprocessor/traits/adt.hpp b/include/boost/contract/ext_/preprocessor/traits/adt.hpp index 13bf596..a2c3764 100644 --- a/include/boost/contract/ext_/preprocessor/traits/adt.hpp +++ b/include/boost/contract/ext_/preprocessor/traits/adt.hpp @@ -46,13 +46,13 @@ // NOTE: Using `BOOST_PP_TUPLE_ELEM(2, 0, sign_traits)` instead of this // confuses MSVC macro expansion sometimes (OK on GCC, CLang, Wave, etc.). #define BOOST_CONTRACT_EXT_PP_SIGN_TRAITS_FIRST(sign_traits) \ - BOOST_CONTRACT_EXT_PP_EXPAND1( \ + BOOST_CONTRACT_EXT_PP_EXPAND_ONCE( \ BOOST_CONTRACT_EXT_PP_SIGN_TRAITS_FIRST_ sign_traits) // NOTE: Using `BOOST_PP_TUPLE_ELEM(2, 1, sign_traits)` instead of this // confuses MSVC macro expansion sometimes (OK on GCC, CLang, Wave, etc.). #define BOOST_CONTRACT_EXT_PP_SIGN_TRAITS_SECOND(sign_traits) \ - BOOST_CONTRACT_EXT_PP_EXPAND1( \ + BOOST_CONTRACT_EXT_PP_EXPAND_ONCE( \ BOOST_CONTRACT_EXT_PP_SIGN_TRAITS_SECOND_ sign_traits) #endif // #include guard diff --git a/include/boost/contract/ext_/preprocessor/traits/func/classifiers.hpp b/include/boost/contract/ext_/preprocessor/traits/func/classifiers.hpp index 95aa419..1379784 100644 --- a/include/boost/contract/ext_/preprocessor/traits/func/classifiers.hpp +++ b/include/boost/contract/ext_/preprocessor/traits/func/classifiers.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -32,7 +33,7 @@ #define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_CLASSIFIERS_OP_ARGS_(continue_, \ sign, inline_, static_, extern_, explicit_, virtual_, friend_) \ - BOOST_CONTRACT_EXT_PP_EXPAND1( \ + BOOST_CONTRACT_EXT_PP_EXPAND_ONCE( \ BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_CLASSIFIERS_SIGN_ \ BOOST_PP_IIF(BOOST_PP_BITAND(BOOST_PP_COMPL(inline_), \ BOOST_CONTRACT_EXT_PP_KEYWORD_IS_INLINE_FRONT(sign)), \ @@ -59,14 +60,14 @@ (1, BOOST_CONTRACT_EXT_PP_KEYWORD_FRIEND_REMOVE_FRONT, sign, \ inline_, static_, extern_, explicit_, virtual_, 1) \ , \ - (0, BOOST_CONTRACT_EXT_PP_EXPAND1, sign, \ + (0, BOOST_CONTRACT_EXT_PP_IDEM, sign, \ inline_, static_, extern_, explicit_, virtual_, friend_) \ )))))) \ ) #define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_CLASSIFIERS_OP_( \ d, continue_sign_inline_static_extern_explicit_virtual_friend) \ - BOOST_CONTRACT_EXT_PP_EXPAND1( \ + BOOST_CONTRACT_EXT_PP_EXPAND_ONCE( \ BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_CLASSIFIERS_OP_ARGS_ \ continue_sign_inline_static_extern_explicit_virtual_friend \ ) diff --git a/include/boost/contract/ext_/preprocessor/traits/func/export.hpp b/include/boost/contract/ext_/preprocessor/traits/func/export.hpp index 8424a38..1b6d774 100644 --- a/include/boost/contract/ext_/preprocessor/traits/func/export.hpp +++ b/include/boost/contract/ext_/preprocessor/traits/func/export.hpp @@ -39,10 +39,10 @@ #define BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_PARSE(sign_traits) \ ( \ - BOOST_CONTRACT_EXT_PP_EXPAND1( \ + BOOST_CONTRACT_EXT_PP_EXPAND_ONCE( \ BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_SIGN_ sign_traits) \ , \ - BOOST_CONTRACT_EXT_PP_EXPAND1( \ + BOOST_CONTRACT_EXT_PP_EXPAND_ONCE( \ BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_EXPORT_TRAIT_ sign_traits) \ ) diff --git a/include/boost/contract/ext_/preprocessor/traits/tparam/kind.hpp b/include/boost/contract/ext_/preprocessor/traits/tparam/kind.hpp index b914ec8..489a674 100644 --- a/include/boost/contract/ext_/preprocessor/traits/tparam/kind.hpp +++ b/include/boost/contract/ext_/preprocessor/traits/tparam/kind.hpp @@ -65,10 +65,10 @@ #define BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_PARSE(sign_traits) \ ( \ - BOOST_CONTRACT_EXT_PP_EXPAND1( \ + BOOST_CONTRACT_EXT_PP_EXPAND_ONCE( \ BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_SIGN_ sign_traits) \ , \ - BOOST_CONTRACT_EXT_PP_EXPAND1( \ + BOOST_CONTRACT_EXT_PP_EXPAND_ONCE( \ BOOST_CONTRACT_EXT_PP_TPARAM_TRAITS_KIND_TRAIT_ sign_traits) \ ) diff --git a/include/boost/contract/ext_/preprocessor/utility/expand.hpp b/include/boost/contract/ext_/preprocessor/utility/expand.hpp index df444fe..29928d5 100644 --- a/include/boost/contract/ext_/preprocessor/utility/expand.hpp +++ b/include/boost/contract/ext_/preprocessor/utility/expand.hpp @@ -5,14 +5,19 @@ /* PUBLIC */ // Expand its argument once, `BOOST_PP_EXPAND` expands it twice instead: -// EXPAND1(x) --> x (x expanded once) -// EXPAND(x) --> EXPAND_(x) --> x (x expanded twice) -// NOTE: This macro is sometimes useful to enforce proper macro expansion on +// EXPAND_ONCE(x) --> x (x expanded once) +// EXPAND(x) --> EXPAND_(x) --> x (x expanded twice) +// This macro is sometimes useful to enforce proper macro expansion at least on // MSVC (on better preprocessors like GCC, CLang, and Wave this macro is not -// necessary instead). For example, `EXPAND1(macro args) ...` where `args` is -// `(a, b EMPTY)` expands to `macro(a, b EMPTY) ...`. Otherwise, MSVC would +// necessary instead). For example, `EXPAND_ONCE(macro args) ...` where `args` +// is `(a, b EMPTY)` expands to `macro(a, b EMPTY) ...`. Otherwise, MSVC would // sometimes confuse `...` as arguments for `EMPTY`, etc. -#define BOOST_CONTRACT_EXT_PP_EXPAND1(tokens) tokens +// NOTE: +// * In theory this macro is equivalent to `IDEM(tokens)` but these are +// logically different, plus not using both macros confuses MSVC sometimes. +// * In theory this macro is also equivalent to `BOOST_PP_REM(1) (tokens)` +// but again that confuses MSVC sometimes. +#define BOOST_CONTRACT_EXT_PP_EXPAND_ONCE(tokens) tokens #endif // #include gaurd diff --git a/include/boost/contract/ext_/preprocessor/utility/idem.hpp b/include/boost/contract/ext_/preprocessor/utility/idem.hpp new file mode 100644 index 0000000..c0d3694 --- /dev/null +++ b/include/boost/contract/ext_/preprocessor/utility/idem.hpp @@ -0,0 +1,16 @@ + +#ifndef BOOST_CONTRACT_EXT_PP_IDEM_HPP_ +#define BOOST_CONTRACT_EXT_PP_IDEM_HPP_ + +/* PUBLIC */ + +// NOTE: +// * In theory this macro is equivalent to `EXPAND_ONCE(tokens)` but these +// are logically different plus not using both macros confuses MSVC +// sometimes. +// * In theory this macro is also equivalent to `BOOST_PP_REM(1) (tokens)` +// but again that confuses MSVC sometimes. +#define BOOST_CONTRACT_EXT_PP_IDEM(tokens) tokens + +#endif // #include guard + diff --git a/test/aux_/pp_traits.hpp b/test/aux_/pp_traits.hpp index 0b27c55..d25a275 100644 --- a/test/aux_/pp_traits.hpp +++ b/test/aux_/pp_traits.hpp @@ -54,9 +54,10 @@ std::string trim ( std::string const& source ) { ) #define BOOST_CONTRACT_TEST_AUX_PP_TRAITS_( \ - sign_traits, get_trait_macro, parsed_trait, sign_after_trait) \ + sign_traits, traits_elem_macro, parsed_trait, sign_after_trait) \ BOOST_CONTRACT_TEST_AUX_PP_TRAITS_EQUAL_( \ - get_trait_macro(BOOST_CONTRACT_EXT_PP_SIGN_TRAITS_DONE(sign_traits)), \ + traits_elem_macro( \ + BOOST_CONTRACT_EXT_PP_SIGN_TRAITS_DONE(sign_traits)), \ parsed_trait \ ) \ BOOST_CONTRACT_TEST_AUX_PP_TRAITS_EQUAL_( \ @@ -70,17 +71,17 @@ std::string trim ( std::string const& source ) { // of the trait that needs to be tested. #ifndef DEBUG # define BOOST_CONTRACT_TEST_AUX_PP_TRAITS( \ - get_trait_macro, \ - parse_traits_macro, \ + traits_elem_macro, \ + traits_parse_macro, \ sign_before_trait, \ sign_at_trait, \ sign_after_trait, \ parsed_trait \ ) \ BOOST_CONTRACT_TEST_AUX_PP_TRAITS_( \ - parse_traits_macro( \ + traits_parse_macro( \ sign_before_trait sign_at_trait sign_after_trait), \ - get_trait_macro, \ + traits_elem_macro, \ parsed_trait, \ sign_after_trait \ ) @@ -88,17 +89,17 @@ std::string trim ( std::string const& source ) { // To #define DEBUG is useful when looking at pre-processed output (the NIL // leading parsed_traits will be remove by non-debug invocation of DONE). # define BOOST_CONTRACT_TEST_AUX_PP_TRAITS( \ - get_trait_macro, \ - parse_traits_macro, \ + traits_elem_macro, \ + traits_parse_macro, \ sign_before_trait, \ sign_at_trait, \ sign_after_trait, \ parsed_trait \ ) \ - "#undefine DEBUG macro `-DDEBUG` to complete C++ code generation" \ + "#undefine DEBUG macro `-UDEBUG` to complete C++ code generation" \ sign = sign_before_trait sign_at_trait sign_after_trait \ --> \ - (remaining_sign, BOOST_PP_NIL parsed_traits) = parse_traits_macro( \ + (remaining_sign, BOOST_PP_NIL parsed_traits) = traits_parse_macro( \ sign_before_trait sign_at_trait sign_after_trait) #endif diff --git a/test/pp_func_traits/classifiers.cpp b/test/pp_func_traits/classifiers.cpp index 1442c32..238f30d 100644 --- a/test/pp_func_traits/classifiers.cpp +++ b/test/pp_func_traits/classifiers.cpp @@ -10,24 +10,42 @@ #include "../aux_/pp_traits.hpp" #include -#include +#include +#include +#include +#include + +#define BOOST_CONTRACT_TEST_FIND_(r, trait_id, elem) \ + BOOST_PP_EXPR_IIF(BOOST_PP_SEQ_CAT((BOOST_CONTRACT_EXT_PP_KEYWORD_IS_) \ + (trait_id)(_FRONT))(elem), \ + elem \ + ) -#define BOOST_CONTRACT_TEST_(trait) \ +#define BOOST_CONTRACT_TEST_ELEM_(r, unused, elem) elem + +#define BOOST_CONTRACT_TEST_TRAIT_(trait_id, traits) \ BOOST_CONTRACT_TEST_AUX_PP_TRAITS( \ - BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_CLASSIFIERS, \ + BOOST_PP_CAT(BOOST_CONTRACT_EXT_PP_FUNC_TRAITS_, trait_id), \ BOOST_CONTRACT_EXT_PP_FUNC_TRAITS, \ template( typename T, (std::map::value_type) V ), \ - trait, \ + BOOST_PP_LIST_FOR_EACH(BOOST_CONTRACT_TEST_ELEM_, ~, traits), \ (std::map&) (f) ( int x, (std::map&) y ), \ - trait \ + BOOST_PP_LIST_FOR_EACH(BOOST_CONTRACT_TEST_FIND_, trait_id, traits) \ ) + +#define BOOST_CONTRACT_TEST_(traits) \ + BOOST_CONTRACT_TEST_TRAIT_(INLINE, traits) \ + BOOST_CONTRACT_TEST_TRAIT_(STATIC, traits) int main ( ) { - BOOST_CONTRACT_TEST_( BOOST_PP_EMPTY() ) - BOOST_CONTRACT_TEST_( inline ) - BOOST_CONTRACT_TEST_( static ) - BOOST_CONTRACT_TEST_( inline static ) - BOOST_CONTRACT_TEST_( static inline ) + BOOST_CONTRACT_TEST_( BOOST_PP_NIL ) + + BOOST_CONTRACT_TEST_( (inline, BOOST_PP_NIL) ) + BOOST_CONTRACT_TEST_( (static, BOOST_PP_NIL) ) + BOOST_CONTRACT_TEST_( (inline, (static, BOOST_PP_NIL)) ) + BOOST_CONTRACT_TEST_( (static, (inline, BOOST_PP_NIL)) ) + + // TODO: Test permutations of all classifiers. return BOOST_CONTRACT_TEST_AUX_PP_TRAITS_REPORT_ERRORS; }