Boost C++ Libraries: Ticket #12016: x3::symbols moves result and therefore removes it from the symbol_parser itself https://svn.boost.org/trac10/ticket/12016 <p> So, I ran into strange behaviour with boost::spirit::x3 as supplied in boost 1.59: </p> <div class="wikipage"><p> I defined a 'dynamic' symbol table via: </p> <div class="wiki-code"><div class="code"><pre> <span class="k">struct</span> <span class="nl">instructions</span> <span class="p">:</span> <span class="n">x3</span><span class="o">::</span><span class="n">symbols</span><span class="o">&lt;</span><span class="n">OpCode</span><span class="o">&gt;</span> <span class="p">{</span> <span class="n">instructions</span><span class="p">()</span> <span class="p">{</span> <span class="n">name</span><span class="p">(</span><span class="s">&quot;instructions&quot;</span><span class="p">);</span> <span class="p">}</span> <span class="kt">void</span> <span class="n">set_instruction_set</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">unordered_map</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="n">OpCode</span><span class="o">&gt;&amp;</span> <span class="n">instruction_set</span><span class="p">)</span> <span class="p">{</span> <span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="nl">var</span> <span class="p">:</span> <span class="n">instruction_set</span><span class="p">)</span> <span class="p">{</span> <span class="n">add</span><span class="p">(</span><span class="n">var</span><span class="p">.</span><span class="n">first</span><span class="p">,</span> <span class="n">var</span><span class="p">.</span><span class="n">second</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="n">instructions_parser</span><span class="p">;</span> </pre></div></div></div><div class="wikipage"><p> <em><a class="missing wiki">OpCode</a></em> is defined as : </p> <div class="wiki-code"><div class="code"><pre> <span class="k">struct</span> <span class="n">OpCode</span> <span class="p">{</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">mnemonic</span><span class="p">;</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="p">...</span><span class="o">&gt;</span> <span class="n">variants</span><span class="p">;</span><span class="c1">// actual type in vector&lt;&gt; not important.</span> <span class="p">};</span> </pre></div></div></div><p> now, with the symbol table embedded in the neccessary rules, when parsing an input string like </p> <div class="wikipage"><div class="wiki-code"><div class="code"><pre> <span class="nf">mov</span> <span class="no">r2</span> <span class="no">r1</span> <span class="nf">mov</span> <span class="no">r1</span> <span class="err">@</span><span class="mi">80</span> </pre></div></div></div><p> the resulting ast only contains the first <code>mov</code> with its operands. The second mov is missing but the operands are correctly parsed. This may look as followed, when printing the resulting AST: </p> <div class="wikipage"><div class="wiki-code"><div class="code"><pre> <span class="nf">mov</span> <span class="no">r2</span> <span class="no">r1</span> <span class="no">r1</span> <span class="err">@</span><span class="mi">80</span> </pre></div></div></div><div class="wikipage"><p> With the debugger I located the source of the error in symbols.hpp in <em>symbol_parser::parse()</em>: </p> <div class="wiki-code"><div class="code"><pre> <span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">Iterator</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Context</span><span class="p">,</span> <span class="k">typename</span> <span class="n">Attribute</span><span class="o">&gt;</span> <span class="kt">bool</span> <span class="n">parse</span><span class="p">(</span><span class="n">Iterator</span><span class="o">&amp;</span> <span class="n">first</span><span class="p">,</span> <span class="n">Iterator</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">last</span> <span class="p">,</span> <span class="n">Context</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">context</span><span class="p">,</span> <span class="n">unused_type</span><span class="p">,</span> <span class="n">Attribute</span><span class="o">&amp;</span> <span class="n">attr</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span> <span class="n">x3</span><span class="o">::</span><span class="n">skip_over</span><span class="p">(</span><span class="n">first</span><span class="p">,</span> <span class="n">last</span><span class="p">,</span> <span class="n">context</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">value_type</span><span class="o">*</span> <span class="n">val_ptr</span> <span class="o">=</span> <span class="n">lookup</span><span class="o">-&gt;</span><span class="n">find</span><span class="p">(</span><span class="n">first</span><span class="p">,</span> <span class="n">last</span><span class="p">,</span> <span class="n">get_case_compare</span><span class="o">&lt;</span><span class="n">Encoding</span><span class="o">&gt;</span><span class="p">(</span><span class="n">context</span><span class="p">)))</span> <span class="p">{</span> <span class="n">x3</span><span class="o">::</span><span class="n">traits</span><span class="o">::</span><span class="n">move_to</span><span class="p">(</span><span class="o">*</span><span class="n">val_ptr</span><span class="p">,</span> <span class="n">attr</span><span class="p">);</span> <span class="c1">//&lt;- the error originates from here</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span> <span class="p">}</span> </pre></div></div></div><div class="wikipage"><p> with <em>move_to</em> beeing: </p> <div class="wiki-code"><div class="code"><pre> <span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">T</span><span class="o">&gt;</span> <span class="kr">inline</span> <span class="kt">void</span> <span class="n">move_to</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;</span> <span class="n">src</span><span class="p">,</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">dest</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">addressof</span><span class="p">(</span><span class="n">src</span><span class="p">)</span> <span class="o">!=</span> <span class="n">boost</span><span class="o">::</span><span class="n">addressof</span><span class="p">(</span><span class="n">dest</span><span class="p">))</span> <span class="n">dest</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">src</span><span class="p">);</span> <span class="p">}</span> </pre></div></div></div><p> As you can see, the <em>src</em> which is my <a class="missing wiki">OpCode</a> instance added in the symbol_parser is moved. This means after the first call its empty again and that's why only the first instructions appears. It's, simply put, moved out of the symbol table. </p> <p> <a class="ext-link" href="http://melpon.org/wandbox/permlink/XxPCnmWExNkmsmP2"><span class="icon">​</span>''Live example (shows the bug is also present in 1.60)''</a> provided by cv_and_he @stackoverflow </p> <p> <strong>Temporary Workaround:</strong> </p> <p> By declaring the template parameter as const one can suppress move semantics. The copy-ctor is then called. </p> <div class="wikipage"><p> I.E.: </p> <div class="wiki-code"><div class="code"><pre> <span class="n">x3</span><span class="o">::</span><span class="n">symbols</span><span class="o">&lt;</span><span class="k">const</span> <span class="n">OpCode</span><span class="o">&gt;</span> </pre></div></div></div> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/12016 Trac 1.4.3 anonymous Tue, 23 Feb 2016 21:54:01 GMT keywords set https://svn.boost.org/trac10/ticket/12016#comment:1 https://svn.boost.org/trac10/ticket/12016#comment:1 <ul> <li><strong>keywords</strong> spirit x3 symbols added </li> </ul> Ticket Joel de Guzman Tue, 23 Feb 2016 22:30:36 GMT <link>https://svn.boost.org/trac10/ticket/12016#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12016#comment:2</guid> <description> <p> Fixed in develop branch. Please confirm! Thanks for the report! </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Tue, 23 Feb 2016 22:30:46 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/12016#comment:3 https://svn.boost.org/trac10/ticket/12016#comment:3 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> Ticket bugs@… Tue, 23 Feb 2016 22:39:19 GMT <link>https://svn.boost.org/trac10/ticket/12016#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12016#comment:4</guid> <description> <p> Excellent report. </p> <p> It strikes me that the const-ness of the value seems to be _the_ way to indicate a parser's result value is not to be moved from. </p> <p> (This seems to be by design? It seems a bit odd that the library would not strictly perfectly forward all temporaries and only move from known rvalues) </p> <p> I suggested a patch based on const mapped values <a class="ext-link" href="https://github.com/boostorg/spirit/pull/174"><span class="icon">​</span>https://github.com/boostorg/spirit/pull/174</a> </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Tue, 23 Feb 2016 22:39:53 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12016#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12016#comment:5</guid> <description> <p> Oh wow. That's fast </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Tue, 23 Feb 2016 22:43:18 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12016#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12016#comment:6</guid> <description> <p> I agree! Excellent report! I beat sehe to a fix, but thanks a lot sehe, I really appreciate it. You rock! Esp. on the spirit list and stack-exchange. </p> <p> PS&gt; Sometimes I try to post a solution to stack-exchange, but then it says I do not have enough credibility points :-) </p> </description> <category>Ticket</category> </item> </channel> </rss>