diff --git a/include/boost/wave/cpp_exceptions.hpp b/include/boost/wave/cpp_exceptions.hpp index 1358479d9..e70e27353 100644 --- a/include/boost/wave/cpp_exceptions.hpp +++ b/include/boost/wave/cpp_exceptions.hpp @@ -116,6 +116,7 @@ class BOOST_SYMBOL_VISIBLE preprocess_exception : ill_formed_operator, bad_define_statement, bad_define_statement_va_args, + bad_define_statement_named_va_args, bad_define_statement_va_opt, bad_define_statement_va_opt_parens, bad_define_statement_va_opt_recurse, @@ -209,6 +210,7 @@ class BOOST_SYMBOL_VISIBLE preprocess_exception : case preprocess_exception::unbalanced_if_endif: case preprocess_exception::bad_define_statement: case preprocess_exception::bad_define_statement_va_args: + case preprocess_exception::bad_define_statement_named_va_args: case preprocess_exception::bad_define_statement_va_opt: case preprocess_exception::bad_define_statement_va_opt_parens: case preprocess_exception::bad_define_statement_va_opt_recurse: @@ -265,6 +267,7 @@ class BOOST_SYMBOL_VISIBLE preprocess_exception : "ill formed #define directive", // bad_define_statement "__VA_ARGS__ can only appear in the " "expansion of a C99 variadic macro", // bad_define_statement_va_args + "named variadic like x... is disabled", // bad_define_statement_named_va_args "__VA_OPT__ can only appear in the " "expansion of a C++20 variadic macro", // bad_define_statement_va_opt "__VA_OPT__ must be followed by a left " @@ -334,6 +337,7 @@ class BOOST_SYMBOL_VISIBLE preprocess_exception : util::severity_error, // ill_formed_operator util::severity_error, // bad_define_statement util::severity_error, // bad_define_statement_va_args + util::severity_error, // bad_define_statement_named_va_args util::severity_error, // bad_define_statement_va_opt util::severity_error, // bad_define_statement_va_opt_parens util::severity_error, // bad_define_statement_va_opt_recurse diff --git a/include/boost/wave/grammars/cpp_grammar.hpp b/include/boost/wave/grammars/cpp_grammar.hpp index e310d43ac..63776905b 100644 --- a/include/boost/wave/grammars/cpp_grammar.hpp +++ b/include/boost/wave/grammars/cpp_grammar.hpp @@ -347,23 +347,38 @@ struct cpp_grammar : ) ) ; - +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 +#if BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS != 0 + typedef typename ScannerT::iterator_t iterator_t; + typedef node_val_data node_t; + typedef typename node_t::iterator_t container_iterator_t; + const auto &named_variadics = [](tree_node& node, iterator_t begin, iterator_t end) { + container_iterator_t it = node.value.begin(); + it->set_token_id(T_GNU_NAMED_ELLIPSIS); + it->set_value(it->get_value() + "..."); + }; +#endif +#endif // parameter list // normal C++ mode macro_parameters = confix_p( no_node_d[ch_p(T_LEFTPAREN) >> *ppsp], !list_p( - ( ch_p(T_IDENTIFIER) - | pattern_p(KeywordTokenType, + ( pattern_p(KeywordTokenType, TokenTypeMask|PPTokenFlag) | pattern_p(OperatorTokenType|AltExtTokenType, ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. | pattern_p(BoolLiteralTokenType, TokenTypeMask|PPTokenFlag) // true/false #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 +#if BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS != 0 + | access_node_d[token_node_d[(ch_p(T_IDENTIFIER) >> *ppsp >> ch_p(T_ELLIPSIS))]] + [named_variadics] +#endif | ch_p(T_ELLIPSIS) #endif + | ch_p(T_IDENTIFIER) // must be after the named variadic ), no_node_d[*ppsp >> ch_p(T_COMMA) >> *ppsp] ), diff --git a/include/boost/wave/language_support.hpp b/include/boost/wave/language_support.hpp index 6d011131f..1ad0d03c3 100644 --- a/include/boost/wave/language_support.hpp +++ b/include/boost/wave/language_support.hpp @@ -33,6 +33,9 @@ enum language_support { // support flags for C99 support_option_variadics = 0x04, support_c99 = support_option_variadics | support_option_long_long | 0x08, +#if BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS != 0 + support_option_gnu_named_variadics = 0x100000, +#endif #endif #if BOOST_WAVE_SUPPORT_CPP0X != 0 // support flags for C++11 @@ -61,7 +64,7 @@ enum language_support { #endif #endif - support_option_mask = 0xFFC0, + support_option_mask = 0x10FFC0, support_option_emit_contnewlines = 0x0040, support_option_insert_whitespace = 0x0080, support_option_preserve_comments = 0x0100, @@ -71,7 +74,7 @@ enum language_support { support_option_prefer_pp_numbers = 0x1000, support_option_emit_line_directives = 0x2000, support_option_include_guard_detection = 0x4000, - support_option_emit_pragma_directives = 0x8000 + support_option_emit_pragma_directives = 0x8000, }; /////////////////////////////////////////////////////////////////////////////// @@ -240,6 +243,9 @@ BOOST_WAVE_OPTION(include_guard_detection) // support_option_include_guard_det #endif #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 BOOST_WAVE_OPTION(variadics) // support_option_variadics +#if BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS != 0 +BOOST_WAVE_OPTION(gnu_named_variadics) // support_option_named_variadics +#endif #endif #if BOOST_WAVE_SUPPORT_VA_OPT != 0 BOOST_WAVE_OPTION(va_opt) // support_option_va_opt diff --git a/include/boost/wave/token_ids.hpp b/include/boost/wave/token_ids.hpp index 713a7d862..1e9521bf7 100644 --- a/include/boost/wave/token_ids.hpp +++ b/include/boost/wave/token_ids.hpp @@ -315,6 +315,9 @@ enum token_id : std::uint32_t { // C++20 operators T_SPACESHIP = TOKEN_FROM_ID(441, OperatorTokenType), +// GNU named variadics + T_GNU_NAMED_ELLIPSIS = TOKEN_FROM_ID(442, IdentifierTokenType), + T_LAST_TOKEN_ID, T_LAST_TOKEN = ID_FROM_TOKEN(T_LAST_TOKEN_ID & ~PPTokenFlag), diff --git a/include/boost/wave/util/cpp_iterator.hpp b/include/boost/wave/util/cpp_iterator.hpp index 9c0a2966a..d1a997237 100644 --- a/include/boost/wave/util/cpp_iterator.hpp +++ b/include/boost/wave/util/cpp_iterator.hpp @@ -1719,6 +1719,16 @@ pp_iterator_functor::on_define (parse_node_type const &node) typedef typename std::vector::iterator parameter_iterator_t; +#if BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS != 0 + string_type named_variadic; + if (boost::wave::need_gnu_named_variadics(ctx.get_language()) && + macroparameters.size() > 0 && + token_id(macroparameters.back()) == T_GNU_NAMED_ELLIPSIS) { + named_variadic = macroparameters.back().get_value(); + named_variadic = named_variadic.substr(0, named_variadic.size()-3); + } +#endif + bool seen_ellipses = false; parameter_iterator_t end = macroparameters.end(); for (parameter_iterator_t pit = macroparameters.begin(); @@ -1731,6 +1741,26 @@ pp_iterator_functor::on_define (parse_node_type const &node) (*pit).get_position()); return; } +#if BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS != 0 + if (T_GNU_NAMED_ELLIPSIS == token_id(*pit)) { + if (boost::wave::need_gnu_named_variadics(ctx.get_language())) { + seen_ellipses = true; + } else { + // named variadics are not supported + BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, + bad_define_statement_named_va_args, macroname.get_value().c_str(), + (*pit).get_position()); + return; + } + } + if (named_variadic == (*pit).get_value()) { + // can't use named_variadic as a argument name + BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, + duplicate_parameter_name, + macroname.get_value().c_str(), (*pit).get_position()); + return; + } +#endif if (T_ELLIPSIS == token_id(*pit)) seen_ellipses = true; diff --git a/include/boost/wave/util/cpp_macromap.hpp b/include/boost/wave/util/cpp_macromap.hpp index 5c49e1f21..81711367b 100644 --- a/include/boost/wave/util/cpp_macromap.hpp +++ b/include/boost/wave/util/cpp_macromap.hpp @@ -1486,13 +1486,18 @@ macromap::expand_macro(ContainerT &expanded, macro_def.macroparameters.size(), seen_newline); std::size_t parm_count_required = macro_def.macroparameters.size(); + #if BOOST_WAVE_SUPPORT_CPP2A if (boost::wave::need_cpp2a(ctx.get_language())) { // Starting with C++20, variable arguments may be left out // entirely, so reduce the mandatory argument count by one // if the last parameter is ellipsis: if ((parm_count_required > 0) && - (T_ELLIPSIS == token_id(macro_def.macroparameters.back()))) { + (T_ELLIPSIS == token_id(macro_def.macroparameters.back()) +#if BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS != 0 + || T_GNU_NAMED_ELLIPSIS == token_id(macro_def.macroparameters.back()) +#endif + )) { --parm_count_required; } } diff --git a/include/boost/wave/util/macro_definition.hpp b/include/boost/wave/util/macro_definition.hpp index 29ecdccdf..5e9379180 100644 --- a/include/boost/wave/util/macro_definition.hpp +++ b/include/boost/wave/util/macro_definition.hpp @@ -81,6 +81,18 @@ struct macro_definition { if (!replaced_parameters) { typename definition_container_type::iterator end = macrodefinition.end(); typename definition_container_type::iterator it = macrodefinition.begin(); + typename ContextT::string_type va_args = "__VA_ARGS__"; +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 +#if BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS != 0 + if (need_gnu_named_variadics(ctx.get_language())) { + if (macroparameters.size() > 0 && + T_GNU_NAMED_ELLIPSIS == token_id(macroparameters.back())) { + va_args = macroparameters.back().get_value(); + va_args = va_args.substr(0, va_args.size()-3); + } + } +#endif +#endif for (/**/; it != end; ++it) { token_id id = *it; @@ -103,12 +115,22 @@ struct macro_definition { #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 else if (need_variadics(ctx.get_language()) && T_ELLIPSIS == token_id(*cit) && - "__VA_ARGS__" == (*it).get_value()) + va_args == (*it).get_value()) { // __VA_ARGS__ requires special handling (*it).set_token_id(token_id(T_EXTPARAMETERBASE+i)); break; } +#if BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS != 0 + else if (need_gnu_named_variadics(ctx.get_language()) && + T_GNU_NAMED_ELLIPSIS == token_id(*cit) && + va_args == (*it).get_value()) + { + // __VA_ARGS__ requires special handling + (*it).set_token_id(token_id(T_EXTPARAMETERBASE+i)); + break; + } +#endif #if BOOST_WAVE_SUPPORT_VA_OPT != 0 else if (need_va_opt(ctx.get_language()) && T_ELLIPSIS == token_id(*cit) && @@ -131,6 +153,13 @@ struct macro_definition { { has_ellipsis = true; } +#if BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS != 0 + if (macroparameters.size() > 0 && + T_GNU_NAMED_ELLIPSIS == token_id(macroparameters.back())) + { + has_ellipsis = true; + } +#endif #endif replaced_parameters = true; // do it only once } diff --git a/include/boost/wave/wave_config.hpp b/include/boost/wave/wave_config.hpp index 04844cc88..4010c7f1b 100644 --- a/include/boost/wave/wave_config.hpp +++ b/include/boost/wave/wave_config.hpp @@ -158,6 +158,23 @@ #endif #endif +/////////////////////////////////////////////////////////////////////////////// +// Change the following, to enable the support for GNU named variadics: +// #define(x...) x +// By default this is disabled. +#if !defined(BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS) +#define BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS 0 +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// Warn the user if GNU named variadics are enabled without variadics support +#if BOOST_WAVE_SUPPORT_GNU_NAMED_VARIADICS_PLACEMARKERS != 0 +#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS == 0 +#warning "Boost.Wave: The support for GNU named variadics requires variadics support." +#endif +#endif + /////////////////////////////////////////////////////////////////////////////// // Allow the message body of the #error and #warning directives to be // preprocessed before the diagnostic is issued. diff --git a/src/token_ids.cpp b/src/token_ids.cpp index 6a0b1cc6d..8851da2e6 100644 --- a/src/token_ids.cpp +++ b/src/token_ids.cpp @@ -232,6 +232,7 @@ static char const *tok_names[] = { /* 439 */ "T_CO_YIELD", /* 440 */ "T_REQUIRES", /* 441 */ "T_SPACESHIP", + /* 442 */ "T_GNU_NAMED_ELLIPSIS", }; // make sure, I have not forgotten any commas (as I did more than once) @@ -444,6 +445,7 @@ static char const *tok_values[] = { /* 439 */ "co_yield", /* 440 */ "requires", /* 441 */ "<=>", + /* 442 */ "", // gnu_named_ellipsis }; // make sure, I have not forgotten any commas (as I did more than once)