diff --git a/include/boost/spirit/home/x3/nonterminal/rule.hpp b/include/boost/spirit/home/x3/nonterminal/rule.hpp index 0d3ddba18b..0ba94ea746 100644 --- a/include/boost/spirit/home/x3/nonterminal/rule.hpp +++ b/include/boost/spirit/home/x3/nonterminal/rule.hpp @@ -76,7 +76,7 @@ namespace boost { namespace spirit { namespace x3 typedef ID id; typedef Attribute attribute_type; static bool const has_attribute = - !is_same::value; + !std::is_same, unused_type>::value; static bool const handles_container = traits::is_container::value; static bool const force_attribute = force_attribute_; @@ -111,9 +111,24 @@ namespace boost { namespace spirit { namespace x3 bool parse(Iterator& first, Iterator const& last , Context const& context, unused_type, Attribute_& attr) const { + static_assert(has_attribute, + "The rule does not have an attribute. Check your parser."); + return parse_rule(*this, first, last, context, attr); } + template + bool parse(Iterator& first, Iterator const& last + , Context const& context, unused_type, unused_type) const + { + static_assert(!has_attribute, + "The rule requires an input attribute. Check your parser."); + + // shield from user specified `unused_type const` as rule attribute + attribute_type no_attr; + return parse_rule(*this, first, last, context, no_attr); + } + char const* name; }; @@ -140,42 +155,12 @@ namespace boost { namespace spirit { namespace x3 } }; - namespace detail - { - template - struct rule_attr_deducer - { - template - using deduce = PassedAttribute&; - }; - - template - struct rule_requires_unused_attribute - { - static_assert(std::is_same, unused_type>::value, - "The rule does not syntesize an attribute"); - - static int constexpr dummy = 1; // just a dummy member, used to force instantiation - }; - - template <> - struct rule_attr_deducer - { - template ::dummy> - using deduce = PassedAttribute; - }; - - template - using deduce_rule_attr = typename rule_attr_deducer::template deduce; - } - #define BOOST_SPIRIT_DECLARE_(r, data, rule_type) \ template \ bool parse_rule( \ rule_type rule_ \ , Iterator& first, Iterator const& last \ - , Context const& context \ - , ::boost::spirit::x3::detail::deduce_rule_attr attr); \ + , Context const& context, Attribute& attr); \ /***/ #define BOOST_SPIRIT_DECLARE(...) BOOST_PP_SEQ_FOR_EACH( \ @@ -189,8 +174,7 @@ namespace boost { namespace spirit { namespace x3 inline bool parse_rule( \ BOOST_PP_CAT(rule_name, _synonym) /* rule_ */ \ , Iterator& first, Iterator const& last \ - , Context const& context \ - , ::boost::spirit::x3::detail::deduce_rule_attr attr) \ + , Context const& context, Attribute& attr) \ { \ using boost::spirit::x3::unused; \ static auto const def_ = (rule_name = BOOST_PP_CAT(rule_name, _def)); \ @@ -203,8 +187,7 @@ namespace boost { namespace spirit { namespace x3 inline bool parse_rule( \ decltype(rule_name) /* rule_ */ \ , Iterator& first, Iterator const& last \ - , Context const& context \ - , ::boost::spirit::x3::detail::deduce_rule_attr attr) \ + , Context const& context, Attribute& attr) \ { \ using boost::spirit::x3::unused; \ static auto const def_ = (rule_name = BOOST_PP_CAT(rule_name, _def)); \ @@ -221,8 +204,7 @@ namespace boost { namespace spirit { namespace x3 template bool parse_rule( \ rule_type rule_ \ , Iterator& first, Iterator const& last \ - , Context const& context \ - , ::boost::spirit::x3::detail::deduce_rule_attr attr); \ + , Context const& context, rule_type::attribute_type&); \ /***/ diff --git a/test/x3/rule_separate_tu.cpp b/test/x3/rule_separate_tu.cpp index 50909a70cf..74810c6ad2 100644 --- a/test/x3/rule_separate_tu.cpp +++ b/test/x3/rule_separate_tu.cpp @@ -18,5 +18,10 @@ int main() BOOST_TEST(parse(s, end, unused_attr::grammar)); BOOST_TEST(phrase_parse(s, end, unused_attr::grammar, unused_attr::skipper)); + std::string rs; + BOOST_TEST(parse(s, end, used_attr::skipper)); + BOOST_TEST(parse(s, end, used_attr::grammar, rs)); + BOOST_TEST(phrase_parse(s, end, used_attr::grammar, used_attr::skipper, rs)); + return boost::report_errors(); } diff --git a/test/x3/rule_separate_tu_grammar.cpp b/test/x3/rule_separate_tu_grammar.cpp index 4c6b1616a8..568e7760b8 100644 --- a/test/x3/rule_separate_tu_grammar.cpp +++ b/test/x3/rule_separate_tu_grammar.cpp @@ -24,3 +24,18 @@ BOOST_SPIRIT_INSTANTIATE(grammar_type, char const*, x3::unused_type) BOOST_SPIRIT_INSTANTIATE(grammar_type, char const*, x3::phrase_parse_context::type) } + +namespace used_attr { + +const skipper_type skipper = "skipper"; +const auto skipper_def = x3::char_('*'); +BOOST_SPIRIT_DEFINE(skipper) +BOOST_SPIRIT_INSTANTIATE(skipper_type, char const*, x3::unused_type) + +const grammar_type grammar = "grammar"; +const auto grammar_def = *x3::char_('='); +BOOST_SPIRIT_DEFINE(grammar) +BOOST_SPIRIT_INSTANTIATE(grammar_type, char const*, x3::unused_type) +BOOST_SPIRIT_INSTANTIATE(grammar_type, char const*, x3::phrase_parse_context::type) + +} diff --git a/test/x3/rule_separate_tu_grammar.hpp b/test/x3/rule_separate_tu_grammar.hpp index 5691dd94d6..19a9ed7d78 100644 --- a/test/x3/rule_separate_tu_grammar.hpp +++ b/test/x3/rule_separate_tu_grammar.hpp @@ -26,3 +26,21 @@ extern const grammar_type grammar; BOOST_SPIRIT_DECLARE(grammar_type) } + +// Check instantiation when rule has an attribute. + +#include + +namespace used_attr { + +namespace x3 = boost::spirit::x3; + +using skipper_type = x3::rule; +extern const skipper_type skipper; +BOOST_SPIRIT_DECLARE(skipper_type) + +using grammar_type = x3::rule; +extern const grammar_type grammar; +BOOST_SPIRIT_DECLARE(grammar_type) + +}