Hi, Bruno Haible <br...@clisp.org> writes:
> On macOS 12.5 (machine: gcc104.fsffrance.org), the test-nullptr-c++.cc fails > to compile: > > ----------------------------------------------------------------------------- > Making check in . > c++ -DHAVE_CONFIG_H -I. -I../../gltests -I.. -DGNULIB_STRICT_CHECKING=1 > -DIN_GNULIB_TESTS=1 -I. -I../../gltests -I.. -I../../gltests/.. -I../gllib > -I../../gltests/../gllib -I/Users/haible/include -Wall -Wno-error -g -O2 -MT > test-nullptr-c++.o -MD -MP -MF .deps/test-nullptr-c++.Tpo -c -o > test-nullptr-c++.o ../../gltests/test-nullptr-c++.cc > ../../gltests/test-nullptr-c++.cc:56:27: error: cannot pass object of non-POD > type 'std::nullptr_t' through variadic function; call will abort at runtime > [-Wnon-pod-varargs] > varargs_callee ("type", nullptr, "foo", nullptr); > ^ > /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__nullptr:48:17: > note: expanded from macro 'nullptr' > #define nullptr _VSTD::__get_nullptr_t() > ^ > /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:858:15: > note: expanded from macro '_VSTD' > #define _VSTD std::_LIBCPP_ABI_NAMESPACE > ^ > ../../gltests/test-nullptr-c++.cc:56:43: error: cannot pass object of non-POD > type 'std::nullptr_t' through variadic function; call will abort at runtime > [-Wnon-pod-varargs] > varargs_callee ("type", nullptr, "foo", nullptr); > ^ > /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__nullptr:48:17: > note: expanded from macro 'nullptr' > #define nullptr _VSTD::__get_nullptr_t() > ^ > /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:858:15: > note: expanded from macro '_VSTD' > #define _VSTD std::_LIBCPP_ABI_NAMESPACE > ^ > 2 errors generated. > make[3]: *** [test-nullptr-c++.o] Error 1 > ----------------------------------------------------------------------------- > > What's happening? configure found out that > > checking for C nullptr... no > checking for C++ nullptr... no > > and accordingly, config.h contains > > /* #undef HAVE_CXX_NULLPTR */ > /* #undef HAVE_C_NULLPTR */ > > Here, nullptr is not defined as a keyword (as it should, cf. > https://en.cppreference.com/w/cpp/keyword/nullptr), but rather as a macro, > and only after some header file such as <stddef.h> has been included. > > Our test "checking for C++ nullptr... no" found it out correctly. > > But test-nullptr-c++.cc includes <iostream>, <vector>, etc. and these have > the effect of pulling a definition of nullptr_t and > > #define nullptr _VSTD::__get_nullptr_t() > > and this one does not work in varargs context. > > So, we've now gone a full circle: > * nullptr and nullptr_t were introduced in C++, to resolve a problem with > overloading and a problem with varargs. > * The definition in this compiler solves the problem with overloading, > but is unusable with varargs. > * If we '#define nullptr __null' again after including the header files, > it will be usable with varargs, but will > - violate the requirement that nullptr is an instance of nullptr_t, > - and thus open up problems with overloading again. The latter problem avoided as long as nullptr is not convertible to integrals, which is doable. N2431 proposes a possible base for an alternative: const // this is a const object... class { public: template<class T> // convertible to any type operator T*() const // of null non-member { return 0; } // pointer... template<class C, class T> // or any type of null operator T C::*() const // member pointer... { return 0; } void* x = 0; // added by me, to pretend this works in // variadics private: void operator&() const; // whose address can't be taken } nlptr = {}; // and whose name is nullptr #define nullptr nlptr /* This builds on Clang++ 11, which is the closes approx. for AC++ I have. */ void g(...){} void test() { g(nullptr); } The paper outlines a few drawbacks to this approach, but it's better than what libc++ was offering AFAICT. Please test it on Apple Clang (I'm failing to come up with the correct set of compiler sources to inspect this, and failing to emulate the failure with Clang 10, which appears to be matching macOS 12.5s llvm version, except not quite). To get the layout of this object to roughly match that of a null pointer, for sake of variadic passing, I added the ``x''. I'm not sure why the libc++ folk thought to poorly emulate a later language feature without calling it __nullptr or such. Note that this broken libc++ nullptr might be only enabled in pre-11 C++ modes based on what I've seen in llvm-project.git. If that's the case, I suspect the alternative proposed above was intentionally not chosen in order to avoid some other bug I'm failing to see at this point in the night. Whether pre-11 standards are worth supporting is up to you, but my vote is on treating it like C99, though C++11 was more substantial than C99, and requiring it to be enabled. I urge this option, or not reusing the nullptr name. It's, to my awareness, not possible to correctly and portably implement nullptr in-language. I'll ask some friends for second opinions too. > I don't know how to proceed here. C++ is such a waste of time!! This is a fault of an implementation, or an error in usage. > Bruno Hope that helps, have a great night. -- Arsen Arsenović
signature.asc
Description: PGP signature