[type_traits] is_pointer<noncopyable> fails on CodeWarrior 9.4

Hi, The following program produces a compiler error on CodeWarrior 9.4 (see error messages at end): #include <boost/noncopyable.hpp> #include <boost/type_traits.hpp> int main() { bool b = boost::is_pointer<boost::noncopyable>::value; } If I change this to: #include <boost/noncopyable.hpp> #include <msl_utility> int main() { bool b = Metrowerks::is_pointer<boost::noncopyable>::value; } everything is fine. What's up? Jonathan --------------------------- Error : illegal access from 'boost::noncopyable_::noncopyable' to protected/private member 'boost::noncopyable_::noncopyable::noncopyable(const boost::noncopyable_::noncopyable &)' (point of instantiation: 'main()') (instantiating: 'boost::is_pointer<boost::noncopyable_::noncopyable>') (instantiating: 'boost::detail::is_pointer_impl<boost::noncopyable_::noncopyable>') (instantiating: 'boost::is_member_pointer<boost::noncopyable_::noncopyable>') (instantiating: 'boost::is_member_function_pointer<boost::noncopyable_::noncopyable>') (instantiating: 'boost::detail::is_member_function_pointer_impl<boost::noncopyable_::noncopyable
') (instantiating: 'boost::detail::is_mem_fun_pointer_select<false>::result_<boost::noncopyable_::n oncopyable>') is_member_function_pointer.hpp line 70 ));

Sorry for the misleading subject line. Obviously, is_pointer<noncopyable> *should* fail -- but it shouldn't produce a compiler error. Jonathan

"Jonathan Turkanis" <technews@kangaroologic.com> writes:
Sorry for the misleading subject line. Obviously, is_pointer<noncopyable> *should* fail -- but it shouldn't produce a compiler error.
Email me a compressed, preprocessed source file and I'll send it on to their compiler engineer for answers. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On May 26, 2005, at 1:32 AM, Jonathan Turkanis wrote:
Hi,
The following program produces a compiler error on CodeWarrior 9.4 (see error messages at end):
#include <boost/noncopyable.hpp> #include <boost/type_traits.hpp>
int main() { bool b = boost::is_pointer<boost::noncopyable>::value; }
If I change this to:
#include <boost/noncopyable.hpp> #include <msl_utility>
int main() { bool b = Metrowerks::is_pointer<boost::noncopyable>::value; }
everything is fine.
What's up?
Jonathan
---------------------------
Error : illegal access from 'boost::noncopyable_::noncopyable' to protected/private member 'boost::noncopyable_::noncopyable::noncopyable(const boost::noncopyable_::noncopyable &)' (point of instantiation: 'main()') (instantiating: 'boost::is_pointer<boost::noncopyable_::noncopyable>') (instantiating: 'boost::detail::is_pointer_impl<boost::noncopyable_::noncopyable>') (instantiating: 'boost::is_member_pointer<boost::noncopyable_::noncopyable>') (instantiating: 'boost::is_member_function_pointer<boost::noncopyable_::noncopyable>') (instantiating: 'boost::detail::is_member_function_pointer_impl<boost::noncopyable_:: noncopyable
') (instantiating: 'boost::detail::is_mem_fun_pointer_select<false>::result_<boost:: noncopyable_::n oncopyable>') is_member_function_pointer.hpp line 70 ));
I haven't dug into boost::is_pointer, but I'm guessing it involves a tentative binding to an ellipsis: template <class U> static two test(...); 5.2.2p7 says that binding a non-POD class type to an ellipsis has undefined behavior. CodeWarrior's behavior in this context is to try to pass the type by value by using the type's copy constructor, which in this case is private, and thus triggers the access error. Metrowerks::is_pointer has a much simpler implementation. -Howard

Howard Hinnant <hinnant@twcny.rr.com> writes:
I haven't dug into boost::is_pointer, but I'm guessing it involves a tentative binding to an ellipsis:
template <class U> static two test(...);
5.2.2p7 says that binding a non-POD class type to an ellipsis has undefined behavior. CodeWarrior's behavior in this context is to try to pass the type by value by using the type's copy constructor, which in this case is private, and thus triggers the access error.
Metrowerks::is_pointer has a much simpler implementation.
We should probably be forwarding to the metrowerks implementation on 9.4, where it's available. Failing that we can check is_class first and avoid the rest of the check in that case. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Howard Hinnant <hinnant@twcny.rr.com> writes:
I haven't dug into boost::is_pointer, but I'm guessing it involves a tentative binding to an ellipsis:
template <class U> static two test(...);
5.2.2p7 says that binding a non-POD class type to an ellipsis has undefined behavior. CodeWarrior's behavior in this context is to try to pass the type by value by using the type's copy constructor, which in this case is private, and thus triggers the access error.
Metrowerks::is_pointer has a much simpler implementation.
We should probably be forwarding to the metrowerks implementation on 9.4, where it's available. Failing that we can check is_class first and avoid the rest of the check in that case.
I must be missing something. The trivial implementation of is_pointer: template<class T> struct is_pointer: mpl::false_ {}; template<class T> struct is_pointer<T*>: mpl::true_ {}; should work on everything except MSVC 6/7, right? So why isn't it being used?

"Peter Dimov" <pdimov@mmltd.net> writes:
David Abrahams wrote:
Howard Hinnant <hinnant@twcny.rr.com> writes:
I haven't dug into boost::is_pointer, but I'm guessing it involves a tentative binding to an ellipsis:
template <class U> static two test(...);
5.2.2p7 says that binding a non-POD class type to an ellipsis has undefined behavior. CodeWarrior's behavior in this context is to try to pass the type by value by using the type's copy constructor, which in this case is private, and thus triggers the access error.
Metrowerks::is_pointer has a much simpler implementation.
We should probably be forwarding to the metrowerks implementation on 9.4, where it's available. Failing that we can check is_class first and avoid the rest of the check in that case.
I must be missing something. The trivial implementation of is_pointer:
template<class T> struct is_pointer: mpl::false_ {}; template<class T> struct is_pointer<T*>: mpl::true_ {};
should work on everything except MSVC 6/7, right? So why isn't it being used?
Yeah, duh. Why not? -- Dave Abrahams Boost Consulting www.boost-consulting.com

Metrowerks::is_pointer has a much simpler implementation.
Compiler specific versions always do, I really wish we could have a clean Boost version, loud sigh etc, etc....
We should probably be forwarding to the metrowerks implementation on 9.4, where it's available. Failing that we can check is_class first and avoid the rest of the check in that case.
I must be missing something. The trivial implementation of is_pointer:
template<class T> struct is_pointer: mpl::false_ {}; template<class T> struct is_pointer<T*>: mpl::true_ {};
should work on everything except MSVC 6/7, right? So why isn't it being used?
Yeah, duh. Why not?
Lots of reasons, but as usual it's complex: 1) There are some compilers that bind member [function] pointers to foo<T*> partial specialisations, if I remember correctly, gcc was one, but don't quote me on that, and I don't know which behaviours are right and which wrong either. The fix was to check that a pointer was not a member pointer before actually declaring it a pointer. 2) is_member_pointer is a lot more complex than it really needs to be, but again it's workarounds that cause the problem: some compilers bind pointers to member functions to a foo<T (U::*)> partial specialisation, and others do not. I believe they all should bind to this partial specialisation, but that's a whole other argument. Anyway the fix was to check that a type was a member function pointer, as well as the "generic" partial specialisation. 3) There was a recent support request to recognise __stdcall, __fastcall, __cdecl etc function types as member function pointers and function types (in is_function and is_member_function_pointer). Sadly, no compiler I've tried allows you to write a partial specialisation based on function call type, where as function overloads based on function call types do work. For this reason windows compilers that support different calling conventions use the old "pass to an overloaded function" workaround for is_member_function_pointer and is_function. Frankly it all sucks, but it does mostly all work as well: probably better and with less maintenance than a pre-processor config based version would (the pre-processor logic is already too complex IMO). It's also possible that MWCW doesn't need any of the three workarounds above (if so it's in a minority of one). So what to do? Right now I'm thinking it's too close to release to do anything, but the easiest fix would be to change the function overload versions to not use ellipsis, I believe this is reasonably easy to do in this case, but haven't tested it, so knowing how these things usually go it probably won't work! :-) John.

John Maddock wrote:
I must be missing something. The trivial implementation of is_pointer: template<class T> struct is_pointer: mpl::false_ {}; template<class T> struct is_pointer<T*>: mpl::true_ {};
should work on everything except MSVC 6/7, right? So why isn't it being used?
Yeah, duh. Why not?
Lots of reasons, but as usual it's complex:
1) There are some compilers that bind member [function] pointers to foo<T*> partial specialisations, if I remember correctly, gcc was one, but don't quote me on that, and I don't know which behaviours are right and which wrong either. The fix was to check that a pointer was not a member pointer before actually declaring it a pointer.
I suspected something along those lines. Yes, some versions of g++ do that; some even allow you to delete a member pointer. No, it's not right. But why didn't you guard this in a BOOST_WORKAROUND specific to the particular g++ versions in question? (This is fixed in g++ 3.4 and above, I believe.)

I suspected something along those lines. Yes, some versions of g++ do that; some even allow you to delete a member pointer. No, it's not right. But why didn't you guard this in a BOOST_WORKAROUND specific to the particular g++ versions in question? (This is fixed in g++ 3.4 and above, I believe.)
Because I don't know if the issue is restricted to gcc, or to which versions, we can try and find out by experiment, but be prepared for a whole of bunch of regressions if it goes wrong... like I said I think this should wait until after 1.33 is out. John.

"John Maddock" <john@johnmaddock.co.uk> writes:
I suspected something along those lines. Yes, some versions of g++ do that; some even allow you to delete a member pointer. No, it's not right. But why didn't you guard this in a BOOST_WORKAROUND specific to the particular g++ versions in question? (This is fixed in g++ 3.4 and above, I believe.)
Because I don't know if the issue is restricted to gcc, or to which versions, we can try and find out by experiment, but be prepared for a whole of bunch of regressions if it goes wrong... like I said I think this should wait until after 1.33 is out.
Peter was asking why you didn't do it that way to begin with, not why you don't do it now. If you leave too much workaround code in for compilers that don't need it, well, eventually you forget which do and which don't, and then you can't back out. See? -- Dave Abrahams Boost Consulting www.boost-consulting.com

which don't, and then you can't back out. See?
Have I finally found out what oder? means;) Martin -- No virus found in this outgoing message. Checked by AVG Anti-Virus. Version: 7.0.322 / Virus Database: 267.1.0 - Release Date: 27/05/2005

Peter was asking why you didn't do it that way to begin with, not why you don't do it now. If you leave too much workaround code in for compilers that don't need it, well, eventually you forget which do and which don't, and then you can't back out. See?
Understood, this is all lost in the mist of time, but as far as I can remember: At the time there were only a minority of compilers that supported partial specialisation that we could really test with, and no one back then was too sure which of the various behaviours was correct. Of course BOOST_WORKAROUND didn't exist then either. Most of all, I think we've all learned a lot since then, well OK since I can only really speak for myself, *I've* learned a lot since then! John.
participants (6)
-
David Abrahams
-
Howard Hinnant
-
John Maddock
-
Jonathan Turkanis
-
Martin Slater
-
Peter Dimov