Opened 11 years ago

Closed 11 years ago

Last modified 10 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 11 years ago.
Test case.

Download all attachments as: .zip

Change History (24)

by loonycyborg, 11 years ago

Attachment: foreachtest.cpp added

Test case.

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

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 by Eric Niebler, 11 years ago

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 by Eric Niebler, 11 years ago

Resolution: fixed
Status: newclosed

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

comment:4 by anonymous, 11 years ago

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'

in reply to:  4 comment:5 by anonymous, 11 years ago

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 by Eric Niebler, 11 years ago

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

comment:7 by Eric Niebler, 11 years ago

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 by Eric Niebler, 11 years ago

Resolution: fixed
Status: reopenedclosed

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

comment:9 by anonymous, 10 years ago

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 by Eric Niebler, 10 years ago

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 by anonymous, 10 years ago

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 by Eric Niebler, 10 years ago

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 by monster.romster@…, 10 years ago

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 by Eric Niebler, 10 years ago

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 by anonymous, 10 years ago

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 by anonymous, 10 years ago

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 by Michel Morin, 10 years ago

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 by Eric Niebler, 10 years ago

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.

in reply to:  18 comment:19 by linasvepstas@…, 10 years ago

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 by anonymous, 10 years ago

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 by linasvepstas@…, 10 years ago

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 by anonymous, 10 years ago

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 by Eric Niebler, 10 years ago

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.

Note: See TracTickets for help on using tickets.