Modify

Opened 6 years ago

Closed 6 years ago

Last modified 5 years ago

#6131 closed Bugs (fixed)

#define foreach BOOST_FOREACH causes weird compile error in certain circumstances with boost 1.48

Reported by: loonycyborg Owned by: Eric Niebler
Milestone: To Be Determined Component: foreach
Version: Boost 1.50.0 Severity: Problem
Keywords: Cc: monster.romster@…

Description

#define foreach BOOST_FOREACH causes compile error "'boost::BOOST_FOREACH' has not been declared" on its line if it appears after #include <boost/foreach.hpp> and before certain other boost headers.

Compiler version: gcc (Gentoo 4.5.3-r1 p1.0, pie-0.4.5) 4.5.3 Also tried gcc 4.3.5, 4.4.6 and 4.6.2

Attachments (1)

foreachtest.cpp (174 bytes) - added by loonycyborg 6 years ago.
Test case.

Download all attachments as: .zip

Change History (24)

Changed 6 years ago by loonycyborg

Attachment: foreachtest.cpp added

Test case.

comment:1 in reply to:  description Changed 6 years ago by Michel Morin <mimomorin@…>

before certain other boost headers.

Specifically, those Boost headers are

  • boost/multi_index/hashed_index.hpp
  • boost/multi_index/ordered_index.hpp
  • boost/multi_index/random_access_index.hpp
  • boost/multi_index/sequenced_index.hpp

and headers that eventually include them, right?

Here are related threads in Boost-users ML:

comment:2 Changed 6 years ago by Eric Niebler

Attempted a workaround on trunk here: <https://svn.boost.org/trac/boost/changeset/75540>. I'll merge to release if the tests don't explode. I don't see why they would.

comment:3 Changed 6 years ago by Eric Niebler

Resolution: fixed
Status: newclosed

(In [75634]) merge [75540] from trunk, fixes #6131

comment:4 Changed 6 years ago by anonymous

Resolution: fixed
Status: closedreopened
Version: Boost 1.48.0Boost 1.49.0

I use just this #define in my code and I have actually _started_ to get compiler error with boost 1.49 (Xcode 4.3, LLVM compiler 3.1):

Redefinition of 'is_lightweight_proxy' Redefinition of 'is_noncopyable'

And even more errors that say:

No matching function for call to 'should_copy_impl'

comment:5 in reply to:  4 Changed 6 years ago by anonymous

Replying to anonymous:

I use just this #define in my code and I have actually _started_ to get compiler error with boost 1.49 (Xcode 4.3, LLVM compiler 3.1):

Redefinition of 'is_lightweight_proxy' Redefinition of 'is_noncopyable'

And even more errors that say:

No matching function for call to 'should_copy_impl'

FWIW the error actually comes up when using BOOST_REVERSE_FOREACH (which I use alongside foreach):

../Game/Widgets?.hpp:130:9: error: no matching function for call to 'should_copy_impl'

PASS_TOUCH(touchBegan) ~

../Game/Widgets?.hpp:124:17: note: expanded from macro 'PASS_TOUCH'

BOOST_REVERSE_FOREACH (const WidgetPtr?& child, children) \

/usr/local/include/boost/foreach.hpp:1117:77: note: expanded from macro 'BOOST_REVERSE_FOREACH'

if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_end) = BOOST_FOREACH_REND(COL)) {} else \

/usr/local/include/boost/foreach.hpp:1051:9: note: expanded from macro 'BOOST_FOREACH_REND'

, BOOST_FOREACH_SHOULD_COPY(COL))

/usr/local/include/boost/foreach.hpp:961:6: note: expanded from macro 'BOOST_FOREACH_SHOULD_COPY'

(boost::foreach_detail_::should_copy_impl( \

~

So maybe this is actually another bug?

comment:6 Changed 6 years ago by Eric Niebler

It's impossible to say without looking at a repro. Can you attach code that demonstrates the problem?

comment:7 Changed 6 years ago by Eric Niebler

In light of #6455, it seems this "fix" is doing more harm than good. I've reverted foreach to the 1.47 version on trunk and plan to close this bug "won't fix". Sorry, I tried.

comment:8 Changed 6 years ago by Eric Niebler

Resolution: fixed
Status: reopenedclosed

(In [77591]) merge [77416] from trunk, fixes #6131, fixes #6455

comment:9 Changed 6 years ago by anonymous

In 1.49 under Visual Studio 2008, I am now getting this error whenever I DON'T include <boost/foreach.hpp> until AFTER I #define foreach BOOST_FOREACH:

'boost::BOOST_FOREACH::is lightweight proxy' : class template has already been defined

foreach_fwd.hpp(62) : see declaration of 'boost::BOOST_FOREACH::is_lightweight_proxy'

Simple test that fails:

#define foreach BOOST_FOREACH #include <boost/foreach.hpp>

It works fine in the other order, i.e., the include before the #define. This never used to be a problem.

comment:10 Changed 6 years ago by Eric Niebler

Foreach was broken in 1.49. As you can see from the comment above, the change was reverted and the fix has already been migrated to the release branch. In 1.50 (currently in beta), the problem should be fixed.

comment:11 Changed 5 years ago by anonymous

The problem still occur in 1.50.0. I stumbled on it while building mkvtoolnix 5.0.1 using clang 3.1 from Xcode 4.3.3. The patches from changeset 75540 are still a valid cure.

comment:12 Changed 5 years ago by Eric Niebler

As you can see from the comments above yours, the patch in [75540], which was released as part of Boost 1.49, caused more problems than it solved. The bug is unfortunate, but there is nothing that can be done at this point, AFAIK. Sorry.

comment:13 Changed 5 years ago by monster.romster@…

Cc: monster.romster@… added
Version: Boost 1.49.0Boost 1.50.0

I tried that patch https://svn.boost.org/trac/boost/changeset/75540 but then boost fails to compile:

    "ccache" "g++"  -ftemplate-depth-128 -O2 -march=i686 -pipe -O3 -Wno-deprecated -fno-strict-aliasing -finline-functions -Wno-inline -Wall -fPIC  -DBOOST_ALL_NO_LIB=1 -DBOOST_GRAPH_DYN_LINK=1 -DBOOST_HAS_ICU=1 -DNDEBUG  -I"." -I"/usr/include" -I"libs/graph/src" -c -o "bin.v2/libs/graph/build/gcc-4.5.3/release/graphml.o" "libs/graph/src/graphml.cpp"

In file included from libs/graph/src/graphml.cpp:14:0:
./boost/foreach.hpp:126:16: error: 'boost::boost::mpl' has not been declared
./boost/foreach.hpp:126:21: error: expected '{' before 'false_'
./boost/foreach.hpp:127:5: error: invalid type in declaration before '{' token
./boost/foreach.hpp:127:5: error: template declaration of 'int boost::boost::foreach::false_'
./boost/foreach.hpp:127:5: warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x
./boost/foreach.hpp:137:16: error: 'boost::boost::mpl' has not been declared
./boost/foreach.hpp:137:21: error: expected '{' before 'or_'
./boost/foreach.hpp:137:24: error: expected initializer before '<' token
In file included from libs/graph/src/graphml.cpp:14:0:
./boost/foreach.hpp:168:8: error: 'BOOST_FOREACH' in namespace 'boost::boost' does not name a type

So I am forced to keep boost at 1.49.0 due to wesnoth failing on 1.50.0

[ 15%] Building CXX object src/CMakeFiles/wesnoth-game.dir/font.cpp.o
In file included from /usr/ports/work/wesnoth/src/wesnoth-1.10.3/src/shared_object.hpp:21:0,
                 from /usr/ports/work/wesnoth/src/wesnoth-1.10.3/src/tstring.hpp:19,
                 from /usr/ports/work/wesnoth/src/wesnoth-1.10.3/src/config.hpp:40,
                 from /usr/ports/work/wesnoth/src/wesnoth-1.10.3/src/terrain.hpp:18,
                 from /usr/ports/work/wesnoth/src/wesnoth-1.10.3/src/map.hpp:23,
                 from /usr/ports/work/wesnoth/src/wesnoth-1.10.3/src/builder.cpp:26:
/usr/ports/work/wesnoth/src/wesnoth-1.10.3/src/foreach.hpp:9:22: error: 'boost::BOOST_FOREACH' has not been declared
make[2]: *** [src/CMakeFiles/wesnoth-game.dir/builder.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [src/CMakeFiles/wesnoth-game.dir/all] Error 2
make: *** [all] Error 2
=======> ERROR: Building '/var/ports/packages/wesnoth#1.10.3-1.pkg.tar.gz' failed.

Lets hope boost 1.51.0 fixes this, or is wesnoth 1.10.3 doing something wrong?

Regards, Danny Rawlins Romster @ freenode distro http://crux.nu

comment:14 Changed 5 years ago by Eric Niebler

There is no fix that doesn't cause more problems than it solves, to the best of my knowledge. No changes are planned for 1.51. Simply do not #define foreach to anything and you should avoid this problem entirely.

comment:15 Changed 5 years ago by anonymous

Someone should then update the documentation (http://www.boost.org/doc/libs/1_50_0/doc/html/foreach.html#foreach.introduction.making__literal_boost_foreach__literal__prettier) and clarify that "#define foreach should not be used". Thanks.

comment:16 Changed 5 years ago by anonymous

Congrats, boost, you managed to break compatibility in one of the simplest-to-use libraries, and nobody gives a damn enough to at least fix the docs. Good job.

comment:17 Changed 5 years ago by Michel Morin

The following treatment does not solve the problem, but it slightly improves the situation:

In boost/multi_index/hashed_index.hpp, change

/* Boost.Foreach compatibility */

template<
  typename KeyFromValue,typename Hash,typename Pred,
  typename SuperMeta,typename TagList,typename Category
>
inline boost::mpl::true_* boost_foreach_is_noncopyable(
  boost::multi_index::detail::hashed_index<
    KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>*&,
  boost::foreach::tag)
{
  return 0;
}

into

#if !(!defined(BOOST_NO_CXX11_RVALUE_REFERENCES)                                                 \
 || BOOST_WORKAROUND(BOOST_MSVC, >= 1310) && !defined(_PREFAST_)                                 \
 || (BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ <= 5) && !defined(BOOST_INTEL) &&       \
                                                                  !defined(BOOST_CLANG))         \
 || (BOOST_WORKAROUND(__GNUC__, == 3) && (__GNUC_MINOR__ >= 4) && !defined(BOOST_INTEL) &&       \
                                                                  !defined(BOOST_CLANG)))
/* Boost.Foreach compatibility */

template<
  typename KeyFromValue,typename Hash,typename Pred,
  typename SuperMeta,typename TagList,typename Category
>
inline boost::mpl::true_* boost_foreach_is_noncopyable(
  boost::multi_index::detail::hashed_index<
    KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>*&,
  boost::foreach::tag)
{
  return 0;
}

#endif

and do the same thing for boost/multi_index/ordered_index.hpp, boost/multi_index/random_access_index.hpp and boost/multi_index/sequenced_index.hpp.

comment:18 Changed 5 years ago by Eric Niebler

Can someone try defining their foreach macro like this:

#include <boost/foreach.hpp>

namespace boost
{
    namespace BOOST_FOREACH = foreach;
}

#define foreach BOOST_FOREACH

Let me know how that works for you.

comment:19 in reply to:  18 Changed 5 years ago by linasvepstas@…

Replying to eric_niebler:

Can someone try defining their foreach macro like this:

#include <boost/foreach.hpp>

namespace boost
{
    namespace BOOST_FOREACH = foreach;
}

#define foreach BOOST_FOREACH

Let me know how that works for you.

Does not work for boost-1.49 I get: error: declaration of namespace ‘boost::BOOST_FOREACH’ conflicts with ...

/usr/local/include/boost/foreach_fwd.hpp:56:1: error: previous declaration of namespace ‘boost::BOOST_FOREACH’ here

comment:20 Changed 5 years ago by anonymous

Anyway, I hacked around this by surrounding above with #if BOOST_VERSION != 104900 which seems to work for that one installation, and also has been reported to work with other installations (MacOS, archlinux) running boost-1.50, which break if the above is NOT done.

Original ticket: https://bugs.launchpad.net/opencog/+bug/1057640/

comment:21 Changed 5 years ago by linasvepstas@…

To be completely clear: the following seems to work for multiple versions of boost (1.46, 1.48, 1.49, 1.50) and for multiple OS'es (MacOS, arch linux, multiple different ubuntu, RHEL4, and a cluster running old CentOS):

 #include <boost/foreach.hpp>
 #include <boost/version.hpp>

 namespace boost {

 #if BOOST_VERSION != 104900
 namespace BOOST_FOREACH = foreach;
 #endif
 
 } // namespace boost
 
 #define foreach BOOST_FOREACH

comment:22 Changed 5 years ago by anonymous

Note from boost foreach 1.52 documentation:

I discourage this. It leads to name conflicts within the BOOST_FOREACH macro itself, where foreach is the name of a namespace

Why can't you simply rename the boost::foreach namespace into something different? These changes would be much smaller than forcing the users of boost to rename their foreach macros in thousands of source files.

comment:23 Changed 5 years ago by Eric Niebler

Renaming the foreach namespace would be a breaking change. There are templates in the foreach namespace that end-users have specialized to make BOOST_FOREACH work with their types. All that would break if the foreach namespace changed.

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Eric Niebler.
The resolution will be deleted.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.