Boost logo

Boost :

Subject: Re: [boost] Boost 1.49 BOOST_PP_ITERATION_FLAGS(): causes build failures; would like a boost maintainer comment
From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2012-03-11 12:33:49


On Sat, 10 Mar 2012 22:04:56 -0600, Steve M. Robbins wrote:

> Would really appreciate if ticket 6631 is a Boost bug that I can patch
> for Debian, or whether it is just API breakage that boost-using packages
> (like luabind) must adapt to.
>
> Thanks,
> -Steve

The problem is that GCC is doing syntax analysis on #if/#elif conditional
expressions on non-taken branches (which is highly questionable behavior
at best). E.g.

// 1.cpp
#if !defined(MACRO)
    // ...
#elif MACRO()
    // ...
#endif

$ g++ --version
g++ (GCC) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ -E -P -std=c++0x -D BOOST_PP_VARIADICS -I $BOOST_ROOT -I . 1.cpp
1.cpp:4:12: error: missing binary operator before token "("

A necessary change occurred between Boost 1.48 and 1.49 in the internal
definition of BOOST_PP_ITERATION_FLAGS. Essentially,
BOOST_PP_ITERATION_FLAGS() used to expand to (e.g. on the first iteration
depth) BOOST_PP_ITERATION_FLAGS_1 which, in turn, expanded to whatever
numeric value was specified. However, in 1.49, BOOST_PP_ITERATION_FLAGS()
now expands to BOOST_PP_ITERATION_FLAGS_1() which, in turn, expands to
whatever numeric value was specified. However, the change to a function-
like macro makes GCC choke for the above reason. The choke does not occur
during the iterations, but rather after it. After the iteration, the
iteration depth is 0 (i.e. not an iteration). That makes
BOOST_PP_ITERATION_FLAGS() expand to (BOOST_PP_ITERATION_FLAGS_0()) which
GCC chokes on after it has already taken (and executed) the body of the
preceding #if branch.

For example,

// 1.cpp
#if !BOOST_PP_IS_ITERATING

    #include <boost/preprocessor/iteration/iterate.hpp>

    #define BOOST_PP_ITERATION_PARAMS_1 (4, (1, 5, "1.cpp", 123))
    #include BOOST_PP_ITERATE()

    post: BOOST_PP_ITERATION_FLAGS()

#elif BOOST_PP_ITERATION_DEPTH() == 1 \
    && BOOST_PP_ITERATION_FLAGS() == 123 \
    /**/

    BOOST_PP_ITERATION(): BOOST_PP_ITERATION_FLAGS()

#endif

$ g++ -E -P -std=c++0x -D BOOST_PP_VARIADICS -I $BOOST_ROOT -I . 1.cpp
    1: (123)
    2: (123)
    3: (123)
    4: (123)
    5: (123)
1.cpp:12:1: error: missing binary operator before token "("
    post: (BOOST_PP_ITERATION_FLAGS_0())

The standard "fix" is to alter the code to something like:

#if !defined(MACRO)
    // ...
#else
    #if MACRO()
        // ...
    #endif
#endif

I.e. the #elif branch needs to change to an #else branch with a nested #if/
#endif.

GCC really needs to stop doing this opportunistic parsing even though it
does not appear to be strictly disallowed by the standards. It didn't
used to do it, but it broke quite a bit of stuff like this when it started.

Regards,
Paul Mensonides


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk