Skip to content

Commit

Permalink
X3: Fixed static assert on parse_rule instantiation
Browse files Browse the repository at this point in the history
During overload resolution disallowed signature can be instantiated leading
to firing the static assertation and overload resolution failure. I could
just remove it, but do not want to leave unbounded by value overloads;
replacing to not deducing Attribute with specifying a default parameter will
not work because we want to allow `BOOST_SPIRIT_DECLARE` without prior
`BOOST_SPIRIT_DEFINE` - this requires having default parameters in both
declaration and definition and the standard seems to forbid it (GCC - fine,
MSVC - warning, Clang - error).

Reverts #437, fixes #453.
  • Loading branch information
Kojoley committed Feb 7, 2019
1 parent 5663d7d commit dec0c9c
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 38 deletions.
58 changes: 20 additions & 38 deletions include/boost/spirit/home/x3/nonterminal/rule.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ namespace boost { namespace spirit { namespace x3
typedef ID id;
typedef Attribute attribute_type;
static bool const has_attribute =
!is_same<Attribute, unused_type>::value;
!std::is_same<std::remove_const_t<Attribute>, unused_type>::value;
static bool const handles_container =
traits::is_container<Attribute>::value;
static bool const force_attribute = force_attribute_;
Expand Down Expand Up @@ -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 <typename Iterator, typename Context>
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;
};

Expand All @@ -140,42 +155,12 @@ namespace boost { namespace spirit { namespace x3
}
};

namespace detail
{
template <typename Attribute>
struct rule_attr_deducer
{
template <typename PassedAttribute>
using deduce = PassedAttribute&;
};

template <typename PassedAttribute>
struct rule_requires_unused_attribute
{
static_assert(std::is_same<std::remove_cv_t<PassedAttribute>, 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<unused_type>
{
template <typename PassedAttribute, int = rule_requires_unused_attribute<PassedAttribute>::dummy>
using deduce = PassedAttribute;
};

template <typename Rule, typename Attribute = typename Rule::attribute_type>
using deduce_rule_attr = typename rule_attr_deducer<typename Rule::attribute_type>::template deduce<Attribute>;
}

#define BOOST_SPIRIT_DECLARE_(r, data, rule_type) \
template <typename Iterator, typename Context, typename Attribute> \
bool parse_rule( \
rule_type rule_ \
, Iterator& first, Iterator const& last \
, Context const& context \
, ::boost::spirit::x3::detail::deduce_rule_attr<rule_type, Attribute> attr); \
, Context const& context, Attribute& attr); \
/***/

#define BOOST_SPIRIT_DECLARE(...) BOOST_PP_SEQ_FOR_EACH( \
Expand All @@ -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<BOOST_PP_CAT(rule_name, _synonym), Attribute> attr) \
, Context const& context, Attribute& attr) \
{ \
using boost::spirit::x3::unused; \
static auto const def_ = (rule_name = BOOST_PP_CAT(rule_name, _def)); \
Expand All @@ -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<decltype(rule_name), Attribute> attr) \
, Context const& context, Attribute& attr) \
{ \
using boost::spirit::x3::unused; \
static auto const def_ = (rule_name = BOOST_PP_CAT(rule_name, _def)); \
Expand All @@ -221,8 +204,7 @@ namespace boost { namespace spirit { namespace x3
template bool parse_rule<Iterator, Context, rule_type::attribute_type>( \
rule_type rule_ \
, Iterator& first, Iterator const& last \
, Context const& context \
, ::boost::spirit::x3::detail::deduce_rule_attr<rule_type> attr); \
, Context const& context, rule_type::attribute_type&); \
/***/


Expand Down
5 changes: 5 additions & 0 deletions test/x3/rule_separate_tu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
15 changes: 15 additions & 0 deletions test/x3/rule_separate_tu_grammar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<skipper_type>::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<skipper_type>::type)

}
18 changes: 18 additions & 0 deletions test/x3/rule_separate_tu_grammar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,21 @@ extern const grammar_type grammar;
BOOST_SPIRIT_DECLARE(grammar_type)

}

// Check instantiation when rule has an attribute.

#include <string>

namespace used_attr {

namespace x3 = boost::spirit::x3;

using skipper_type = x3::rule<class skipper_r, x3::unused_type const>;
extern const skipper_type skipper;
BOOST_SPIRIT_DECLARE(skipper_type)

using grammar_type = x3::rule<class grammar_r, std::string>;
extern const grammar_type grammar;
BOOST_SPIRIT_DECLARE(grammar_type)

}

0 comments on commit dec0c9c

Please sign in to comment.