Opened 11 years ago

Closed 10 years ago

#6331 closed Bugs (fixed)

[Boost.Test] g++ compilation error due to ambiguity between template<class Cond, class T> struct boost::enable_if and class boost::unit_test::decorator::enable_if as well as the disable_if counterparts introduced after Boost 1.48.0 (up to at least svn rev. 76217)

Reported by: t0rt1e@… Owned by: Gennadiy Rozental
Milestone: To Be Determined Component: test
Version: Boost Development Trunk Severity: Regression
Keywords: enable_if, disable_if Cc: Gennadiy Rozental vexocide@… bugs@…

Description

The attached test case exposes a compilation problem with g++ (not clang++) against Boost trunk svn rev. <=76217 (after 1.48.0 release) due to an ambiguity between [[[template<class Cond, class T> struct boost::enable_if}}} and class boost::unit_test::decorator::enable_if in boost/typeof/native.hpp, as well as the disable_if counterparts. The test case compiles correctly against Boost 1.48.0 using Apple g++ 4.2.1, MacPorts g++ 4.5.3 and 4.6.2 as well as Apple clang++ 3.0 on Mac OS X Lion 10.7.2 and Xcode 4.2.1. It fails to compile against Boost trunk until at least svn rev. 76217 using any of the mentioned g++ versions. Surprisingly, clang++ 3.0 is still able to correctly compile the test case. The test case is derived from test_signed_integer_output_with_karma.cpp in Trac ticket #6126. During the discussion of ticket #6126 on the Boost-Spirit-general mailing list, Jeroen Habraken identified the header boost/test/tree/decorator.hpp as the origin for the compilation failure of the test case against Boost trunk. He found the cause to be an ambiguity:

$ g++-mp-4.6 -o test_boost_test_decorator_enable_if test_boost_test_decorator_enable_if.cpp -I.../boost-trunk
In file included from test_boost_test_decorator_enable_if.cpp:58:0:
boost/typeof/native.hpp:30:18: error: expected nested-name-specifier before 'enable_if'
boost/typeof/native.hpp:30:27: error: expected initializer before '<' token
boost/typeof/native.hpp:34:18: error: expected nested-name-specifier before 'disable_if'
boost/typeof/native.hpp:34:28: error: expected initializer before '<' token

These occur because the code states "typename enable_if<Cond, T>::type" and the type name doesn't make sense in combination with boost::unit_test::decorator::enable_if. When removing the typename, on gets the following ambiguity error:

boost/typeof/native.hpp:30:9: error: reference to 'enable_if' is ambiguous
boost/utility/enable_if.hpp:36:10: error: candidates are: template<class Cond, class T> struct boost::enable_if
boost/test/tree/decorator.hpp:184:23: error:                 class boost::unit_test::decorator::enable_if

showing the conflict between template<class Cond, class T> struct boost::enable_if and class boost::unit_test::decorator::enable_if.

As enable_if is often used without being fully qualified this breaks in a major fashion. Since boost/test/tree/decorator.hpp seems to be quite new (added 2011-10-02 11:00:16 +0200) it might be best fixed there.

My search on trac for boost::unit_test::decorator_enable_if turned up changeset 74663 by rogeeff, who I therefore put in CC.

Attachments (2)

test_boost_test_decorator_enable_if.cpp (2.7 KB ) - added by t0rt1e@… 11 years ago.
test case
test_impl_logged_expectations.ipp.patch (605 bytes ) - added by t0rt1e@… 11 years ago.
Patch misplaced using namespace statement in boost/test/impl/logged_expectations.ipp

Download all attachments as: .zip

Change History (12)

by t0rt1e@…, 11 years ago

test case

comment:1 by t0rt1e@…, 11 years ago

Keywords: disable_if added

comment:2 by t0rt1e@…, 11 years ago

Severity: ProblemRegression

comment:3 by rogeeff@…, 11 years ago

  1. I am yet to see why this is boost.test fault and not compiler bug.
  2. I think qualifying symbols from boost namespace is right thing to

do in any case

  1. This code is not part of the release.

Gennadiy

in reply to:  3 comment:4 by t0rt1e@…, 11 years ago

Replying to rogeeff@…:

  1. I am yet to see why this is boost.test fault and not compiler bug.

It might well be a compiler bug, but seeing how long it takes that new compiler versions are widely deployed even on common platforms such as Windows, Linux, or Mac OS X -- especially in production environments, such issues should be fixed also in the Boost library.

That said, before simply blaming the compiler, we should also make sure that it is not some bug in Boost.Test or other Boost component.

The test case just includes two Boost headers and then fails to compile with g++ 4.2.1, 4.5.3, and 4.6.2 (clang+ + 3.0 compiles just fine the test case):

#define BOOST_TEST_MODULE test_boost_test_decorator_enable_if
#include <boost/test/included/unit_test.hpp>
#include <boost/typeof/native.hpp>

BOOST_AUTO_TEST_CASE(test_dummy)
{
  // do nothing
}

I'm not familiar enough with all the magic going on behind the scenes in Boost.Test to judge if it not changes the visibility of certain symbols in certain namespaces, e.g., by issuing using statements.

At least, just including into a test case:

#include <boost/test/tree/decorator.hpp>
#include <boost/typeof/native.hpp>

int main(int argc, char* argv[]) {
  return 0;
}

won't cause a compiler error. I don't know what triggers the compiler to look-up enable_if<Cond, T> in the other test case.

I don't know either why the compiler sees the definition of boost::unit_test::decorator::enable_if in namespace boost::type_of.

I don't know how to further analyse the issue.

  1. I think qualifying symbols from boost namespace is right thing to do in any case

Well, I agree, but what is a user of the Boost libraries able to do about it? Using enable_if and co. without a qualifying namespace is widespread in the Boost sources: A grep on the Boost headers and some filtering shows that enable_if without a qualifying namespace identifier is used approx. 1000 times all over the Boost library. Therefore, I can imaging that qualifying all occurences of enable_if and co. will need a quite huge and well coordinated effort to be fixed by the different library authors.

I am aware that also other Boost libraries have their own enable_if variants. However, all seem to be templates except for the boost::unit_test::decorator::enable_if. Maybe therefore no problems were yet observed in combination with typename statements. At least that is how far I understand the issue.

  1. This code is not part of the release.

This is good to hear. Boost.Test is very useful for me and I use it in conjunction with other Boost libraries regularly. Having it broken in a an official Boost release would cause me quite some headache as suddenly my unit tests for my own code would stop compiling for reasons I cannot influence.

Gennadiy

comment:5 by t0rt1e@…, 11 years ago

While digging into the issue, I came across the CHANGES document for g++ 4.7.0 currently under development. It states:

"G++ now correctly implements the two-phase lookup rules such that an unqualified name used in a template must have an appropriate declaration found either in scope at the point of definition of the template or by argument-dependent lookup at the point of instantiation. As a result, code that relies on a second unqualified lookup at the point of instantiation to find functions declared after the template or in dependent bases will be rejected. The compiler will suggest ways to fix affected code, and using the -fpermissive compiler flag will allow the code to compile with a warning."

Could this problem be related?

I also found a meta-bug in gcc's bug tracker (ticket #18805) grouping currently known problems around the name-lookup.

comment:6 by t0rt1e@…, 11 years ago

I just tried to compile the test case with g++ version 4.7.0 20120114 (experimental). It still gives the same errors as the older g++ that I tried previously.

comment:7 by Gennadiy Rozental, 11 years ago

Resolution: fixed
Status: newclosed

(In [76600]) Fixes #6331

comment:8 by t0rt1e@…, 11 years ago

Resolution: fixed
Status: closedreopened

Thanks for finding the origin of the issue in a misplaced using namespace boost::unit_test statement in the implementation of the boost::unit_test! Unfortunately, the change set 76600 doesn't fully resolve the issue. There's another using namespace boost::unit_test statement hidden in in boost/test/impl/logged_expectations.ipp. I attach a patch, which finally allows me to compile my test case against Boost trunk.

by t0rt1e@…, 11 years ago

Patch misplaced using namespace statement in boost/test/impl/logged_expectations.ipp

comment:9 by t0rt1e@…, 11 years ago

I just checked out Boost trunk rev. 76906. test_impl_logged_expectations.ipp.patch hasn't been applied to it yet to fix the misplaced using namespace statement in boost/test/impl/logged_expectations.ipp.

comment:10 by Gennadiy Rozental, 10 years ago

Resolution: fixed
Status: reopenedclosed
Note: See TracTickets for help on using tickets.