Strange semantic behaviour of boost spirit x3 after splitting

这一生的挚爱 提交于 2019-12-04 14:04:38

I've found the cause of the bug.

The bug is with the fact that the expect directive takes it subject parser by value, which is before the parser::impl::identifier initializer runs.

To visualize, imagine the static initializer for parser::impl::enum_parser running before parser::impl::identifier. This is valid for a compiler to do.

The copy, therefore, has an uninitialized name field, which fails as soon as the expectation point tries to construct the x3::expectation_failure with the which_ member, because constructing a std::string from a nullptr is illegal.

All in all, I fear the root cause here is Static Initialization Order Fiasco. I'll see whether I can fix it and submit a PR.

WORKAROUND:

An immediate workaround is to list the order of the source files in reverse, so that use comes after definition:

set(SOURCE_FILES 
    identifier.cpp
    enum.cpp 
    main.cpp 
)

Note that if this fixes it on your compiler (it does on mine) that is implementation defined. The standard does NOT specify the order of static initialization across compilation units.

Here's a solution that worked for me, when the above workround does not.

Say you have files a.cpp, a.h, a_def.hpp, b.cpp, b.h, b_def.hpp, ... as recommended by the Boost.Spirit X3 docs.

The basic idea is to combine the *.cpp and *_def.hpp files into 1 file for each group. The *.h files can and should remain.

  1. ls *_def.hpp > parser_def.hpp (assuming parser_def.hpp doesn't already exist) and edit parser_def.hpp to #include the files in the correct order. Remove redundant lines (add a header guard, etc.) The goal is for parser_def.hpp to include the other files in the correct order.
  2. cat *.cpp > parser.cpp and edit parser.cpp to be syntactically correct, and replace all #include <*_def.hpp> lines with a single #include <parser_def.hpp> at the top. In your build file (e.g. make or cmake), replace the compilation of the *.cpp files with the single parser.cpp.
  3. You can get rid of the old *.cpp files.

You lose the convenience of separately compiled files, but it will avoid the Static Initialization Order Fiasco.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!