IMO this is an unwanted bug, as copies of various AST subparts can be expensive. It's also nowhere stated in the documentation that types need to be copyable.
I don't have an MCVE now (ask me if you want any, I will try to reduce my project as long as it reproduces). The error message (template backtrace) points to spirit implementation:
../src/parser/ast.hpp:243:8: required from 'static bool boost::spirit::x3::detail::rule_parser<Attribute, ID>::call_rule_definition(const RHS&, const char*, Iterator&, const Iterator&, const Context&, ActualAttribute&, ExplicitAttrPropagation) [...]
[...]/boost/spirit/home/x3/nonterminal/rule.hpp:61:39: required from 'bool boost::spirit::x3::rule_definition<ID, RHS, Attribute, force_attribute_>::parse(Iterator&, const Iterator&, const Context&, boost::spirit::x3::unused_type, Attribute_&) const [...]
../src/parser/grammar_def.hpp:256:1: required from 'bool fs::parser::parse_rule(fs::parser::grammar_type, Iterator&, const Iterator&, const Context&, Attribute&) [...]
../src/parser/grammar.cpp:13:1: required from here
[...]/mingw64/include/c++/8.2.0/bits/stl_construct.h:75:7: error: use of deleted function 'fs::parser::ast::action_expression::action_expression(const fs::parser::ast::action_expression&)'
digging the implementation (x3/nonterminal/rule.hpp, lines 56-66):
template <typename Iterator, typename Context, typename Attribute_>
bool parse(Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute_& attr) const
{
return detail::rule_parser<attribute_type, ID>
::call_rule_definition(
rhs, name, first, last
, context
, attr
, mpl::bool_<force_attribute>());
}
then (x3/nonterminal/detail/rule.hpp, lines 295-349)
template <typename RHS, typename Iterator, typename Context
, typename ActualAttribute, typename ExplicitAttrPropagation>
static bool call_rule_definition(
RHS const& rhs
, char const* rule_name
, Iterator& first, Iterator const& last
, Context const& context, ActualAttribute& attr
, ExplicitAttrPropagation)
{
boost::ignore_unused(rule_name);
typedef traits::make_attribute<Attribute, ActualAttribute> make_attribute;
// do down-stream transformation, provides attribute for
// rhs parser
typedef traits::transform_attribute<
typename make_attribute::type, Attribute, parser_id>
transform;
typedef typename make_attribute::value_type value_type;
typedef typename transform::type transform_attr;
value_type made_attr = make_attribute::call(attr); // HERE IS THE COPY
transform_attr attr_ = transform::pre(made_attr);
bool ok_parse
//Creates a place to hold the result of parse_rhs
//called inside the following scope.
;
{
// Create a scope to cause the dbg variable below (within
// the #if...#endif) to call it's DTOR before any
// modifications are made to the attribute, attr_ passed
// to parse_rhs (such as might be done in
// traits::post_transform when, for example,
// ActualAttribute is a recursive variant).
#if defined(BOOST_SPIRIT_X3_DEBUG)
context_debug<Iterator, transform_attr>
dbg(rule_name, first, last, attr_, ok_parse);
#endif
ok_parse = parse_rhs(rhs, first, last, context, attr_, attr_
, mpl::bool_
< ( RHS::has_action
&& !ExplicitAttrPropagation::value
)
>()
);
}
if (ok_parse)
{
// do up-stream transformation, this integrates the results
// back into the original attribute value, if appropriate
traits::post_transform(attr, std::forward<transform_attr>(attr_));
}
return ok_parse;
}
x3/support/traits/make_attribute
template <typename Attribute>
struct make_attribute_base
{
static Attribute call(unused_type)
{
// synthesize the attribute/parameter
return Attribute();
}
template <typename T>
static T& call(T& value)
{
return value; // just pass the one provided
}
};
The core of the problem lies on these 2 lines
value_type made_attr = make_attribute::call(attr);
transform_attr attr_ = transform::pre(made_attr);
make_attribute::call() default-constructs the attribute if originally it was unused, but copies it instead if it was. At first I though that the library wants to preserve the state of the attribute (in case it's already partially filled) but ... no, the copy that is just made is then passed to transform::pre which doesn't do anything with the argument and returns a default-constructed object of type transform_attr. made_attr is never used anymore which makes it essentially a useless copy. At the end, attr (the orginal user object) is move-constructed from attr_.
IMO this is an unwanted bug, as copies of various AST subparts can be expensive. It's also nowhere stated in the documentation that types need to be copyable.
I don't have an MCVE now (ask me if you want any, I will try to reduce my project as long as it reproduces). The error message (template backtrace) points to spirit implementation:
digging the implementation (
x3/nonterminal/rule.hpp, lines 56-66):then (
x3/nonterminal/detail/rule.hpp, lines 295-349)x3/support/traits/make_attributeThe core of the problem lies on these 2 lines
make_attribute::call()default-constructs the attribute if originally it was unused, but copies it instead if it was. At first I though that the library wants to preserve the state of the attribute (in case it's already partially filled) but ... no, the copy that is just made is then passed totransform::prewhich doesn't do anything with the argument and returns a default-constructed object of typetransform_attr.made_attris never used anymore which makes it essentially a useless copy. At the end,attr(the orginal user object) is move-constructed fromattr_.