Boost C++ Libraries: Ticket #9737: [spirit][classic] returning reference to temporary when using position_iterator with istreambuf_iterator<char> https://svn.boost.org/trac10/ticket/9737 <p> In boost spirit classic, when using position_iterator with istreambuf_iterator&lt;char&gt;, the underlying iterator_adaptor::deference() might return a reference to temporary: </p> <p> For example with clang34/libc++: </p> <pre class="wiki">$ clang++34 -O2 -Wall test-boost.cpp -o test-boost source/boost/boost/iterator/iterator_adaptor.hpp:310:18: warning: returning reference to local temporary object [-Wreturn-stack-address] { return *m_iterator; } ^~~~~~~~~~~ </pre><p> or with gcc47/libstdc++ in c++11 mode: </p> <pre class="wiki">$ g++47 --std=c++11 -O2 -Wall test-boost.cpp -o test-boost source/boost/boost/iterator/iterator_adaptor.hpp:310:19: warning: returning reference to temporary [enabled by default] </pre><p> but not in default gcc47 default code (gnu++98): </p> <pre class="wiki">$ g++47 -O2 -Wall test-boost.cpp -o test-boost </pre><p> We tracked down this issue to istreambuf_iterator&lt;char&gt;::reference and istreambuf_iterator&lt;char&gt;::operator*() definition: </p> <ul><li>On clang3.4/libc++: </li></ul><p> istreambuf_iterator&lt;char&gt;::reference type is 'char' and istreambuf_iterator&lt;char&gt;::operator*() also returns a 'char'. </p> <ul><li>On gcc47/libstdc++ in c++11 mode: </li></ul><p> istreambuf_iterator&lt;char&gt;::reference type is 'char' and istreambuf_iterator&lt;char&gt;::operator*() also returns a 'char'. </p> <p> See: istreambuf_iterator::reference changes from _CharT&amp; to _CharT: <a class="ext-link" href="http://gcc.gnu.org/wiki/Cxx11AbiCompatibility"><span class="icon">​</span>http://gcc.gnu.org/wiki/Cxx11AbiCompatibility</a> </p> <ul><li>However on gcc47/libstdc++ in default mode: </li></ul><p> istreambuf_iterator&lt;char&gt;::reference type is 'char &amp;' where istreambuf_iterator&lt;char&gt;::operator*() returns a 'char'. </p> <blockquote> <p> And position_iterator being built from iterator_adaptor with: </p> </blockquote> <pre class="wiki"> typedef boost::iterator_adaptor&lt; main_iter_t, ForwardIterT, const_value_type, boost::forward_traversal_tag &gt; type; </pre><blockquote> <p> there is no 5th template type which defines iterator_adaptor 'Reference': </p> </blockquote> <pre class="wiki"> // Iterator Adaptor // ... // // Reference - the reference type of the resulting iterator, and in // particular, the result type of operator*(). If not supplied but // Value is supplied, Value&amp; is used. Otherwise // iterator_traits&lt;Base&gt;::reference is used. </pre><blockquote> <p> Thus by default, iterator_adaptor::deference() from a position_iterator built of istreambuf_iterator&lt;char&gt; returns a &amp;char, which is fine only when istreambuf_iterator&lt;char&gt;::reference type is also 'char &amp;'. </p> </blockquote> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/9737 Trac 1.4.3 Julien Charbon <jcharbon@…> Tue, 04 Mar 2014 14:02:13 GMT attachment set https://svn.boost.org/trac10/ticket/9737 https://svn.boost.org/trac10/ticket/9737 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">test-boost.cpp</span> </li> </ul> <p> Simple test case example </p> Ticket Julien Charbon <jcharbon@…> Tue, 04 Mar 2014 14:10:41 GMT <link>https://svn.boost.org/trac10/ticket/9737#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9737#comment:1</guid> <description> <p> Side-effects of this returning reference to temporary are enlighten with attached test case: </p> <ul><li>clang34/libc++ (fail): </li></ul><pre class="wiki">$ clang++34 -O2 -Wall test-boost.cpp -o test-boost source/boost/boost/iterator/iterator_adaptor.hpp:310:18: warning: returning reference to local temporary object [-Wreturn-stack-address] { return *m_iterator; } ^~~~~~~~~~~ ... $ ./test-boost File: internal string Line: 1 Col: 1 Expecting a number, but found something else Parsing failed </pre><ul><li>gcc47/libstdc++ in c++11 mode (fail): </li></ul><pre class="wiki">$ g++47 -O2 -Wall test-boost.cpp -o test-boost source/boost/boost/iterator/iterator_adaptor.hpp:310:19: warning: returning reference to temporary [enabled by default] ... $ ./test-boost File: internal string Line: 1 Col: 1 Expecting a number, but found something else Parsing failed </pre><ul><li>gcc47/libstdc++ default mode (success): </li></ul><pre class="wiki">$ g++47 -O2 -Wall test-boost.cpp -o test-boost $ ./test-boost Parsing: 0, 1, 2 Parses OK: 0: 0 1: 1 2: 2 </pre><blockquote> <p> For the record the complete warnings clang34/libc++: </p> </blockquote> <pre class="wiki">$ clang++34 -O2 -Wall test-boost.cpp -o test-boost In file included from test-boost.cpp:5: In file included from source/boost/boost/spirit/include/classic_position_iterator.hpp:11: In file included from source/boost/boost/spirit/home/classic/iterator/position_iterator.hpp:98: In file included from source/boost/boost/spirit/home/classic/iterator/impl/position_iterator.ipp:15: In file included from source/boost/boost/iterator_adaptors.hpp:11: source/boost/boost/iterator/iterator_adaptor.hpp:310:18: warning: returning reference to local temporary object [-Wreturn-stack-address] { return *m_iterator; } ^~~~~~~~~~~ source/boost/boost/iterator/iterator_facade.hpp:514:20: note: in instantiation of member function 'boost::iterator_adaptor&lt;boost::spirit::classic::position_iterator&lt;boost::spirit::classic::multi_pass&lt;std::__1::istreambuf_iterator&lt;char, std::__1::char_traits&lt;char&gt; &gt;, boost::spirit::classic::multi_pass_policies::input_iterator, boost::spirit::classic::multi_pass_policies::ref_counted, boost::spirit::classic::multi_pass_policies::buf_id_check, boost::spirit::classic::multi_pass_policies::std_deque&gt;, boost::spirit::classic::file_position_base&lt;std::__1::basic_string&lt;char&gt; &gt;, boost::spirit::classic::nil_t&gt;, boost::spirit::classic::multi_pass&lt;std::__1::istreambuf_iterator&lt;char, std::__1::char_traits&lt;char&gt; &gt;, boost::spirit::classic::multi_pass_policies::input_iterator, boost::spirit::classic::multi_pass_policies::ref_counted, boost::spirit::classic::multi_pass_policies::buf_id_check, boost::spirit::classic::multi_pass_policies::std_deque&gt;, const char, boost::forward_traversal_tag, boost::use_default, boost::use_default&gt;::dereference' requested here return f.dereference(); ^ source/boost/boost/iterator/iterator_facade.hpp:639:40: note: in instantiation of function template specialization 'boost::iterator_core_access::dereference&lt;boost::spirit::classic::position_iterator&lt;boost::spirit::classic::multi_pass&lt;std::__1::istreambuf_iterator&lt;char, std::__1::char_traits&lt;char&gt; &gt;, boost::spirit::classic::multi_pass_policies::input_iterator, boost::spirit::classic::multi_pass_policies::ref_counted, boost::spirit::classic::multi_pass_policies::buf_id_check, boost::spirit::classic::multi_pass_policies::std_deque&gt;, boost::spirit::classic::file_position_base&lt;std::__1::basic_string&lt;char&gt; &gt;, boost::spirit::classic::nil_t&gt; &gt;' requested here return iterator_core_access::dereference(this-&gt;derived()); ^ source/boost/boost/spirit/home/classic/core/scanner/scanner.hpp:54:20: note: in instantiation of member function 'boost::iterator_facade&lt;boost::spirit::classic::position_iterator&lt;boost::spirit::classic::multi_pass&lt;std::__1::istreambuf_iterator&lt;char, std::__1::char_traits&lt;char&gt; &gt;, boost::spirit::classic::multi_pass_policies::input_iterator, boost::spirit::classic::multi_pass_policies::ref_counted, boost::spirit::classic::multi_pass_policies::buf_id_check, boost::spirit::classic::multi_pass_policies::std_deque&gt;, boost::spirit::classic::file_position_base&lt;std::__1::basic_string&lt;char&gt; &gt;, boost::spirit::classic::nil_t&gt;, const char, boost::forward_traversal_tag, const char &amp;, long long&gt;::operator*' requested here return *scan.first; ^ source/boost/boost/spirit/home/classic/core/scanner/skipper.hpp:61:66: note: in instantiation of function template specialization 'boost::spirit::classic::iteration_policy::get&lt;boost::spirit::classic::scanner&lt;boost::spirit::classic::position_iterator&lt;boost::spirit::classic::multi_pass&lt;std::__1::istreambuf_iterator&lt;char, std::__1::char_traits&lt;char&gt; &gt;, boost::spirit::classic::multi_pass_policies::input_iterator, boost::spirit::classic::multi_pass_policies::ref_counted, boost::spirit::classic::multi_pass_policies::buf_id_check, boost::spirit::classic::multi_pass_policies::std_deque&gt;, boost::spirit::classic::file_position_base&lt;std::__1::basic_string&lt;char&gt; &gt;, boost::spirit::classic::nil_t&gt;, boost::spirit::classic::scanner_policies&lt;boost::spirit::classic::skipper_iteration_policy&lt;boost::spirit::classic::iteration_policy&gt;, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy&gt; &gt; &gt;' requested here while (!BaseT::at_end(scan) &amp;&amp; impl::isspace_(BaseT::get(scan))) ^ source/boost/boost/spirit/home/classic/core/scanner/skipper.hpp:53:18: note: in instantiation of function template specialization 'boost::spirit::classic::skipper_iteration_policy&lt;boost::spirit::classic::iteration_policy&gt;::skip&lt;boost::spirit::classic::scanner&lt;boost::spirit::classic::position_iterator&lt;boost::spirit::classic::multi_pass&lt;std::__1::istreambuf_iterator&lt;char, std::__1::char_traits&lt;char&gt; &gt;, boost::spirit::classic::multi_pass_policies::input_iterator, boost::spirit::classic::multi_pass_policies::ref_counted, boost::spirit::classic::multi_pass_policies::buf_id_check, boost::spirit::classic::multi_pass_policies::std_deque&gt;, boost::spirit::classic::file_position_base&lt;std::__1::basic_string&lt;char&gt; &gt;, boost::spirit::classic::nil_t&gt;, boost::spirit::classic::scanner_policies&lt;boost::spirit::classic::skipper_iteration_policy&lt;boost::spirit::classic::iteration_policy&gt;, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy&gt; &gt; &gt;' requested here scan.skip(scan); ^ source/boost/boost/spirit/home/classic/core/scanner/scanner.hpp:252:43: note: in instantiation of function template specialization 'boost::spirit::classic::skipper_iteration_policy&lt;boost::spirit::classic::iteration_policy&gt;::at_end&lt;boost::spirit::classic::scanner&lt;boost::spirit::classic::position_iterator&lt;boost::spirit::classic::multi_pass&lt;std::__1::istreambuf_iterator&lt;char, std::__1::char_traits&lt;char&gt; &gt;, boost::spirit::classic::multi_pass_policies::input_iterator, boost::spirit::classic::multi_pass_policies::ref_counted, boost::spirit::classic::multi_pass_policies::buf_id_check, boost::spirit::classic::multi_pass_policies::std_deque&gt;, boost::spirit::classic::file_position_base&lt;std::__1::basic_string&lt;char&gt; &gt;, boost::spirit::classic::nil_t&gt;, boost::spirit::classic::scanner_policies&lt;boost::spirit::classic::skipper_iteration_policy&lt;boost::spirit::classic::iteration_policy&gt;, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy&gt; &gt; &gt;' requested here return iteration_policy_type::at_end(*this); ^ source/boost/boost/spirit/home/classic/core/scanner/scanner.hpp:235:13: note: in instantiation of member function 'boost::spirit::classic::scanner&lt;boost::spirit::classic::position_iterator&lt;boost::spirit::classic::multi_pass&lt;std::__1::istreambuf_iterator&lt;char, std::__1::char_traits&lt;char&gt; &gt;, boost::spirit::classic::multi_pass_policies::input_iterator, boost::spirit::classic::multi_pass_policies::ref_counted, boost::spirit::classic::multi_pass_policies::buf_id_check, boost::spirit::classic::multi_pass_policies::std_deque&gt;, boost::spirit::classic::file_position_base&lt;std::__1::basic_string&lt;char&gt; &gt;, boost::spirit::classic::nil_t&gt;, boost::spirit::classic::scanner_policies&lt;boost::spirit::classic::skipper_iteration_policy&lt;boost::spirit::classic::iteration_policy&gt;, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy&gt; &gt;::at_end' requested here at_end(); ^ source/boost/boost/spirit/home/classic/core/scanner/impl/skipper.ipp:132:27: note: in instantiation of member function 'boost::spirit::classic::scanner&lt;boost::spirit::classic::position_iterator&lt;boost::spirit::classic::multi_pass&lt;std::__1::istreambuf_iterator&lt;char, std::__1::char_traits&lt;char&gt; &gt;, boost::spirit::classic::multi_pass_policies::input_iterator, boost::spirit::classic::multi_pass_policies::ref_counted, boost::spirit::classic::multi_pass_policies::buf_id_check, boost::spirit::classic::multi_pass_policies::std_deque&gt;, boost::spirit::classic::file_position_base&lt;std::__1::basic_string&lt;char&gt; &gt;, boost::spirit::classic::nil_t&gt;, boost::spirit::classic::scanner_policies&lt;boost::spirit::classic::skipper_iteration_policy&lt;boost::spirit::classic::iteration_policy&gt;, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy&gt; &gt;::scanner' requested here scanner_t scan(first, last); ^ source/boost/boost/spirit/home/classic/core/scanner/impl/skipper.ipp:155:13: note: in instantiation of function template specialization 'boost::spirit::classic::impl::phrase_parser&lt;boost::spirit::classic::space_parser&gt;::parse&lt;boost::spirit::classic::position_iterator&lt;boost::spirit::classic::multi_pass&lt;std::__1::istreambuf_iterator&lt;char, std::__1::char_traits&lt;char&gt; &gt;, boost::spirit::classic::multi_pass_policies::input_iterator, boost::spirit::classic::multi_pass_policies::ref_counted, boost::spirit::classic::multi_pass_policies::buf_id_check, boost::spirit::classic::multi_pass_policies::std_deque&gt;, boost::spirit::classic::file_position_base&lt;std::__1::basic_string&lt;char&gt; &gt;, boost::spirit::classic::nil_t&gt;, boost::spirit::classic::sequence&lt;boost::spirit::classic::alternative&lt;boost::spirit::classic::action&lt;boost::spirit::classic::real_parser&lt;double, boost::spirit::classic::real_parser_policies&lt;double&gt; &gt;, boost::spirit::classic::ref_value_actor&lt;std::__1::vector&lt;double, std::__1::allocator&lt;double&gt; &gt;, boost::spirit::classic::push_back_action&gt; &gt;, boost::spirit::classic::functor_parser&lt;error_report_parser&gt; &gt;, boost::spirit::classic::kleene_star&lt;boost::spirit::classic::sequence&lt;boost::spirit::classic::alternative&lt;boost::spirit::classic::chlit&lt;char&gt;, boost::spirit::classic::functor_parser&lt;error_report_parser&gt; &gt;, boost::spirit::classic::alternative&lt;boost::spirit::classic::action&lt;boost::spirit::classic::real_parser&lt;double, boost::spirit::classic::real_parser_policies&lt;double&gt; &gt;, boost::spirit::classic::ref_value_actor&lt;std::__1::vector&lt;double, std::__1::allocator&lt;double&gt; &gt;, boost::spirit::classic::push_back_action&gt; &gt;, boost::spirit::classic::functor_parser&lt;error_report_parser&gt; &gt; &gt; &gt; &gt; &gt;' requested here parse(first, last, p.derived(), skip.derived()); ^ test-boost.cpp:92:12: note: in instantiation of function template specialization 'boost::spirit::classic::parse&lt;boost::spirit::classic::position_iterator&lt;boost::spirit::classic::multi_pass&lt;std::__1::istreambuf_iterator&lt;char, std::__1::char_traits&lt;char&gt; &gt;, boost::spirit::classic::multi_pass_policies::input_iterator, boost::spirit::classic::multi_pass_policies::ref_counted, boost::spirit::classic::multi_pass_policies::buf_id_check, boost::spirit::classic::multi_pass_policies::std_deque&gt;, boost::spirit::classic::file_position_base&lt;std::__1::basic_string&lt;char&gt; &gt;, boost::spirit::classic::nil_t&gt;, boost::spirit::classic::sequence&lt;boost::spirit::classic::alternative&lt;boost::spirit::classic::action&lt;boost::spirit::classic::real_parser&lt;double, boost::spirit::classic::real_parser_policies&lt;double&gt; &gt;, boost::spirit::classic::ref_value_actor&lt;std::__1::vector&lt;double, std::__1::allocator&lt;double&gt; &gt;, boost::spirit::classic::push_back_action&gt; &gt;, boost::spirit::classic::functor_parser&lt;error_report_parser&gt; &gt;, boost::spirit::classic::kleene_star&lt;boost::spirit::classic::sequence&lt;boost::spirit::classic::alternative&lt;boost::spirit::classic::chlit&lt;char&gt;, boost::spirit::classic::functor_parser&lt;error_report_parser&gt; &gt;, boost::spirit::classic::alternative&lt;boost::spirit::classic::action&lt;boost::spirit::classic::real_parser&lt;double, boost::spirit::classic::real_parser_policies&lt;double&gt; &gt;, boost::spirit::classic::ref_value_actor&lt;std::__1::vector&lt;double, std::__1::allocator&lt;double&gt; &gt;, boost::spirit::classic::push_back_action&gt; &gt;, boost::spirit::classic::functor_parser&lt;error_report_parser&gt; &gt; &gt; &gt; &gt;, boost::spirit::classic::space_parser&gt;' requested here return parse(pos_begin, pos_end, ^ 1 warning generated. </pre> </description> <category>Ticket</category> </item> <item> <author>Julien Charbon <jcharbon@…></author> <pubDate>Tue, 04 Mar 2014 14:13:31 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/9737 https://svn.boost.org/trac10/ticket/9737 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">position_iterator.patch</span> </li> </ul> <p> Patch that fix this specific issue (open to discussion) </p> Ticket Julien Charbon <jcharbon@…> Tue, 04 Mar 2014 14:17:28 GMT <link>https://svn.boost.org/trac10/ticket/9737#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9737#comment:2</guid> <description> <p> The joined position_iterator.patch fixes this specific issue, however it is difficult to promote this patch as _the_ solution as position_iterator usages are quite diverse. It can be used to start discussion on this issue. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Joel de Guzman</dc:creator> <pubDate>Sat, 24 Nov 2018 05:09:41 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/9737#comment:3 https://svn.boost.org/trac10/ticket/9737#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> <p> fixed in <a class="ext-link" href="https://github.com/boostorg/spirit/pull/422"><span class="icon">​</span>https://github.com/boostorg/spirit/pull/422</a> </p> Ticket