[Bug c++/54043] New: [C++0x] cout << nullptr does not work

ayg at aryeh dot name gcc-bugzilla@gcc.gnu.org
Fri Jul 20 08:46:00 GMT 2012


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54043

             Bug #: 54043
           Summary: [C++0x] cout << nullptr does not work
    Classification: Unclassified
           Product: gcc
           Version: 4.6.3
            Status: UNCONFIRMED
          Severity: minor
          Priority: P3
         Component: c++
        AssignedTo: unassigned@gcc.gnu.org
        ReportedBy: ayg@aryeh.name


I was converting the Mozilla codebase to use nullptr instead of 0L and fixing
the resulting compile errors
<https://bugzilla.mozilla.org/show_bug.cgi?id=626472> when I ran into this. 
Test program:

<<<<
#include <iostream>

int main()
{
        std::cout << nullptr << std::endl;
}
>>>>

Command line and output:

<<<<
$ g++ -v -Wall -Wextra -Werror -std=c++0x test.cpp -otest
Using built-in specs.
COLLECT_GCC=/usr/bin/g++-4.6.real
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper
Target: i686-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro
4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr
--program-suffix=-4.6 --enable-shared --enable-linker-build-id
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext
--enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6
--libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu
--enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object
--enable-plugin --enable-objc-gc --enable-targets=all --disable-werror
--with-arch-32=i686 --with-tune=generic --enable-checking=release
--build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
Thread model: posix
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
COLLECT_GCC_OPTIONS='-v' '-Wall' '-Wextra' '-Werror' '-std=c++0x' '-o' 'test'
'-shared-libgcc' '-mtune=generic' '-march=i686'
 /usr/lib/gcc/i686-linux-gnu/4.6/cc1plus -quiet -v -imultilib . -imultiarch
i386-linux-gnu -D_GNU_SOURCE test.cpp -quiet -dumpbase test.cpp -mtune=generic
-march=i686 -auxbase test -Wall -Wextra -Werror -std=c++0x -version
-fstack-protector -o /tmp/cca9VYQZ.s
GNU C++ (Ubuntu/Linaro 4.6.3-1ubuntu5) version 4.6.3 (i686-linux-gnu)
        compiled by GNU C version 4.6.3, GMP version 5.0.2, MPFR version
3.1.0-p3, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/i386-linux-gnu"
ignoring nonexistent directory
"/usr/lib/gcc/i686-linux-gnu/4.6/../../../../i686-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/c++/4.6
 /usr/include/c++/4.6/i686-linux-gnu/.
 /usr/include/c++/4.6/backward
 /usr/lib/gcc/i686-linux-gnu/4.6/include
 /usr/local/include
 /usr/lib/gcc/i686-linux-gnu/4.6/include-fixed
 /usr/include/i386-linux-gnu
 /usr/include
End of search list.
GNU C++ (Ubuntu/Linaro 4.6.3-1ubuntu5) version 4.6.3 (i686-linux-gnu)
        compiled by GNU C version 4.6.3, GMP version 5.0.2, MPFR version
3.1.0-p3, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 2ed62271b86e2b75137544459bab1a81
test.cpp: In function ‘int main()’:
test.cpp:5:15: error: ambiguous overload for ‘operator<<’ in ‘std::cout <<
nullptr’
test.cpp:5:15: note: candidates are:
/usr/include/c++/4.6/ostream:110:7: note: std::basic_ostream<_CharT,
_Traits>::__ostream_type& std::basic_ostream<_CharT,
_Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type&
(*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char,
_Traits = std::char_traits<char>, std::basic_ostream<_CharT,
_Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:119:7: note: std::basic_ostream<_CharT,
_Traits>::__ostream_type& std::basic_ostream<_CharT,
_Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type&
(*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char,
_Traits = std::char_traits<char>, std::basic_ostream<_CharT,
_Traits>::__ostream_type = std::basic_ostream<char>, std::basic_ostream<_CharT,
_Traits>::__ios_type = std::basic_ios<char>]
/usr/include/c++/4.6/ostream:129:7: note: std::basic_ostream<_CharT,
_Traits>::__ostream_type& std::basic_ostream<_CharT,
_Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char,
_Traits = std::char_traits<char>, std::basic_ostream<_CharT,
_Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:175:7: note: std::basic_ostream<_CharT,
_Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool)
[with _CharT = char, _Traits = std::char_traits<char>,
std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/ostream:227:7: note: std::basic_ostream<_CharT,
_Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const
void*) [with _CharT = char, _Traits = std::char_traits<char>,
std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.6/bits/ostream.tcc:121:5: note: std::basic_ostream<_CharT,
_Traits>& std::basic_ostream<_CharT,
_Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__streambuf_type*)
[with _CharT = char, _Traits = std::char_traits<char>,
std::basic_ostream<_CharT, _Traits>::__streambuf_type =
std::basic_streambuf<char>]
/usr/include/c++/4.6/ostream:581:5: note: std::basic_ostream<_CharT, _Traits>&
std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT
= char, _Traits = std::char_traits<char>, _Tp = std::nullptr_t] <near match>
/usr/include/c++/4.6/ostream:581:5: note:   no known conversion for argument 1
from ‘std::ostream {aka std::basic_ostream<char>}’ to
‘std::basic_ostream<char>&&’
/usr/include/c++/4.6/ostream:528:5: note: std::basic_ostream<char, _Traits>&
std::operator<<(std::basic_ostream<char, _Traits>&, const unsigned char*) [with
_Traits = std::char_traits<char>]
/usr/include/c++/4.6/ostream:523:5: note: std::basic_ostream<char, _Traits>&
std::operator<<(std::basic_ostream<char, _Traits>&, const signed char*) [with
_Traits = std::char_traits<char>]
/usr/include/c++/4.6/ostream:510:5: note: std::basic_ostream<char, _Traits>&
std::operator<<(std::basic_ostream<char, _Traits>&, const char*) [with _Traits
= std::char_traits<char>]
/usr/include/c++/4.6/bits/ostream.tcc:323:5: note: std::basic_ostream<_CharT,
_Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const char*)
[with _CharT = char, _Traits = std::char_traits<char>]
>>>>


In case you're wondering why anyone would bother sending a nullptr_t to a
stream, given that it only has one possible value: this came up in Mozilla's
codebase in a macro:

"do_check_eq(valueArray->AsSharedBlob(0, &len), nsnull);"
http://hg.mozilla.org/mozilla-central/file/3a05d298599e/storage/test/test_AsXXX_helpers.cpp#l52

nsnull was formerly a macro for 0L (or 0LL on Win64), but I was in the process
of changing it to nullptr (see aforementioned bug,
https://bugzilla.mozilla.org/show_bug.cgi?id=626472) to get better type-safety.
 do_check_eq is a macro that checks its arguments' equality, and if they fail,
prints an error:

http://hg.mozilla.org/mozilla-central/file/3a05d298599e/storage/test/storage_test_harness.h#l57

It uses std::ostringstream to hold the error message, and relies on << to print
the expected and actual values according to their respective types.  The
variable aActual in this case happens to be nsnull, so it fails due to this
error.  In the absence of macros, obviously, it's not likely anyone would try
outputting a nullptr to a stream, but the use-case seems legitimate to me.


Reading <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.pdf>, I
find in 27.7.3.1 (p. 1010) that basic_ostream<charT,traits>& operator<< is
defined with a number of operators that nullptr_t will convert to, including
void* and bool.  13.3.3.1.1 seems to say (p. 288) that any pointer conversion
or boolean conversion has rank "conversion".  4.10 (p. 80) says that nullptr_t
can be converted to any pointer type as a pointer conversion, and 4.12 (p. 81)
says it can be converted to bool as a boolean conversion.  Thus, per spec, gcc
appears to be correct -- the call is ambiguous, since there are multiple
equally good viable functions.  (I might be wrong, since I didn't read the spec
thoroughly.  My background is more web standards.)

However, this does not seem at all expected behavior.  I would expect printing
nullptr to a stream to work, probably printing the same as (void*)0.  I don't
know what gcc's policy is on deviating from the spec in cases like this --
please advise.  Perhaps someone on the gcc team who works with WG21 could refer
this to them for discussion, to change at the next opportunity -- either in the
next major version, or perhaps in errata (I don't know what WG21's policy is on
minor updates).


If you need any more information, please let me know.  Thanks.



More information about the Gcc-bugs mailing list