|
Boost : |
Subject: [boost] Conformance issues in Boost.Icl
From: Doug Gregor (doug.gregor_at_[hidden])
Date: 2011-03-05 16:35:52
Hi all,
I've been going through the Boost.Icl test failures for Clang, and
there are few conformance issues that should be addressed on the Boost
side.
The main issue is the test fastest_set_icl_set.cpp, which has some
declaration-ordering issues with templates that only Clang seems to
diagnose (I've verified that Clang is right). The basic problem, which
is repeated in a few places, is that Boost.Icl adds operators and
operator templates into namespace boost::icl, e.g., from
<boost/icl/concept/element_associator.hpp>:
namespace boost{namespace icl
{
template <class Type>
inline typename enable_if<is_associative_element_container<Type>, Type>::type
operator + (Type object, const Type& operand)
{
return object += operand;
}
} }
Now, this operator + can be used with any associative element
container, which includes std::set, but only in a context where normal
name lookup will find the operator. ADL doesn't help, since the
associated namespaces of std::set don't include boost::icl [1].
In the test file fastest_set_icl_set.cpp, that use of the operator
comes from the instantiating this macro in <lib/icl/test_laws.hpp>:
#define DEFINE_ASSOCIATIVITY_CHECK_WRT(op_tag, op_sign) \
template<class Type, class TypeB, class TypeC> \
void check_associativity_wrt_##op_tag(const Type& a, const TypeB& b,
const TypeC& c) \
{ \
Type left = (a op_sign b) op_sign c; \
Type right = a op_sign (b op_sign c); \
BOOST_CHECK(left==right); \
}
which is instantiated withe op_sign=+ in namespace boost::icl, so name
lookup on + looks inside namespace boost::icl and finds the operator+
from earlier.
Except that it doesn't, because <lib/icl/test_laws.hpp> is included
*before* <boost/icl/concept/element_associator.hpp>. So, the operator+
we wanted isn't visible from the template definition, and isn't
visible to ADL during template instantiation, and the code is
ill-formed.
Moving the inclusion of test_laws.hpp earlier fixes this particular
instance of the problem, but there's a more serious one lurking: the
header <boost/icl/concept/element_set.hpp> tends to come very early in
translation, and has this:
template<class Type>
inline typename enable_if<is_element_set<Type>, Type>::type
operator & (Type object, const Type& operand)
{
return object &= operand;
}
which depends on other operator &= definitions in namespace boost::icl
that tend to come later (including in headers that #include
<boost/icl/concept/element_set.hpp>). I didn't try to detangle these
relations, because it's a header ordering issue that requires more
knowledge of the library than I have. The right fix is probably to
provide forward declarations for these operations in a common header
that always gets included very early.
Another probably-not-significant issue is that the use of template
template parameters whose template parameters have default arguments
(in <lib/icl/test/test_interval_quantifier_shared.hpp>) *might* not be
well-formed in the standard. The standard is fairly silent on the
issue, although the likely resolution of core issue #150 ([3], item
#2) does support this usage, and Clang seems to have been the only
compiler to get this wrong.
Big thanks to Joachim for such an excellent compiler test case :)
- Doug
[1] Naturally, the template arguments given to set::set might bring
boost::icl into scope, but the test we're talking about using
std::set<int>.
[2] This is a common compatibility issue. See
http://clang.llvm.org/compatibility.html#dep_lookup
[3] http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#150
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk