Search code examples
c++boost-spiritboost-spirit-x3

Spirit X3, semantic action makes compilation fails with: Attribute does not have the expected size


This code does not compiles (gcc 5.3.1 + boost 1.60):

#include <boost/spirit/home/x3.hpp>

namespace x3 = boost::spirit::x3;

template <typename T>
void parse(T begin, T end) {
    auto dest = x3::lit('[') >> x3::int_ >> ';' >> x3::int_ >> ']';

    auto on_portal = [&](auto& ctx) {};
    auto portal    = (x3::char_('P') >> -dest)[on_portal];

    auto tiles = +portal;
    x3::phrase_parse(begin, end, tiles, x3::eol);
}

int main() {
    std::string x;
    parse(x.begin(), x.end());
}

It fails with a static assertion:

error: static assertion failed: Attribute does not have the expected size.

Thanks to wandbox I also tryied boost 1.61 and clang, both produce the same results.

If I remove the semantic action attached to portal, it compiles fine; the same happens if I change dest to:

auto dest = x3::lit('[') >> x3::int_ >> ']';

Any help would be appreciated. TIA.


Solution

  • This is surprising to me too, I'd report it at the mailing list (or the bug tracker) as a potential bug.

    Meanwhile, you can "fix" it by supplying an attribute type for dest:

    Live On Coliru

    #include <boost/fusion/adapted/std_tuple.hpp>
    #include <boost/spirit/home/x3.hpp>
    #include <iostream>
    
    namespace x3 = boost::spirit::x3;
    
    template <typename T>
    void parse(T begin, T end) {
        auto dest = x3::rule<struct dest_type, std::tuple<int, int> > {} = '[' >> x3::int_ >> ';' >> x3::int_ >> ']';
    
        auto on_portal = [&](auto& ctx) {
            int a, b;
            if (auto tup = x3::_attr(ctx)) {
                std::tie(a, b) = *tup;
                std::cout << "Parsed [" << a << ", " << b << "]\n";
            }
        };
        auto portal    = ('P' >> -dest)[on_portal];
    
        auto tiles = +portal;
        x3::phrase_parse(begin, end, tiles, x3::eol);
    }
    
    int main() {
        std::string x = "P[1;2]P[3;4]P[5;6]";
        parse(x.begin(), x.end());
    }
    

    Prints:

    Parsed [1, 2]
    Parsed [3, 4]
    Parsed [5, 6]
    

    NOTE I changed char_('P') into just lit('P') because I didn't want to complicate the sample dealing with the character in the attribute. Perhaps you didn't mean to have it in the exposed attribute anyways.