bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
* nullptr in C++ mode on macOS
@ 2023-02-09 19:31 Bruno Haible
  2023-02-09 20:08 ` Arsen Arsenović
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Bruno Haible @ 2023-02-09 19:31 UTC (permalink / raw)
  To: bug-gnulib

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.

I don't know how to proceed here. C++ is such a waste of time!!

Bruno





^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: nullptr in C++ mode on macOS
  2023-02-09 19:31 nullptr in C++ mode on macOS Bruno Haible
@ 2023-02-09 20:08 ` Arsen Arsenović
  2023-02-09 20:38 ` Jeffrey Walton
  2023-02-10  1:20 ` Paul Eggert
  2 siblings, 0 replies; 6+ messages in thread
From: Arsen Arsenović @ 2023-02-09 20:08 UTC (permalink / raw)
  To: Bruno Haible; +Cc: bug-gnulib

[-- Attachment #1: Type: text/plain, Size: 5797 bytes --]

Hi,

Bruno Haible <bruno@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ć

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 381 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: nullptr in C++ mode on macOS
  2023-02-09 19:31 nullptr in C++ mode on macOS Bruno Haible
  2023-02-09 20:08 ` Arsen Arsenović
@ 2023-02-09 20:38 ` Jeffrey Walton
  2023-02-10  9:10   ` Bruno Haible
  2023-02-10  1:20 ` Paul Eggert
  2 siblings, 1 reply; 6+ messages in thread
From: Jeffrey Walton @ 2023-02-09 20:38 UTC (permalink / raw)
  To: Bruno Haible; +Cc: bug-gnulib

On Thu, Feb 9, 2023 at 2:31 PM Bruno Haible <bruno@clisp.org> wrote:
>
> On macOS 12.5 (machine: gcc104.fsffrance.org), the test-nullptr-c++.cc fails
> to compile:

One of the sharp edges you may be encountering is, LLVM was shipping a
C++03 compiler by default. You had to do something special to use
C++11 (-std=c++11). And this was in 2016 or 2018. I filed a couple of
bug reports about it.

Then you have Apple's version of Clang. They are probably C++03 for
compatibility reasons for Xcode developers. So even if LLVM moved to
C++11, Apple's Clang may stay at C++03.

> I don't know how to proceed here. C++ is such a waste of time!!

In the projects I work on, I use a library specific define. In
Gnulib's case, it would be GNULIB_NULLPTR. Then I have a feature test
to set GNULIB_NULLPTR to either nullptr or NULL. The strategy works
well for me.

    #if defined(HAVE_CXX11_NULLPTR)
    #   define GNULIB_NULLPTR nullptr
    #else
    #   define GNULIB_NULLPTR NULL
    #endif

Most compilers will use nulltpr nowadays. But Clang may provide
unusual results due to LLVM and Apple pinning the compiler at C++03.

Jeff


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: nullptr in C++ mode on macOS
  2023-02-09 19:31 nullptr in C++ mode on macOS Bruno Haible
  2023-02-09 20:08 ` Arsen Arsenović
  2023-02-09 20:38 ` Jeffrey Walton
@ 2023-02-10  1:20 ` Paul Eggert
  2023-02-10  8:58   ` Bruno Haible
  2 siblings, 1 reply; 6+ messages in thread
From: Paul Eggert @ 2023-02-10  1:20 UTC (permalink / raw)
  To: Bruno Haible; +Cc: bug-gnulib, Arsen Arsenović

[-- Attachment #1: Type: text/plain, Size: 1064 bytes --]

On 2/9/23 11:31, Bruno Haible wrote:
>   * 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.
> 
> I don't know how to proceed here.

Let's treat C++ overloading like we already treat C _Generic, that is, 
as a documented limitation of the substitute nullptr macro. This should 
be good enough for Gnulib itself. I installed the attached to document 
that, and to work around the Apple clang 14 incompatibility with it in mind.

On 2/9/23 12:08, Arsen Arsenović wrote:

> It's, to my awareness, not possible to correctly and portably implement
> nullptr in-language.

Yes, but all that's needed here is to implement Gnulib's limited 
substitute well enough to work with Apple clang 14 and any other 
compilers that have similar incompatibilities with current C++. I hope 
the attached patch does that, though I'm by no means a C++ whiz.

[-- Attachment #2: 0001-nullptr-work-around-Apple-clang-14-issue.patch --]
[-- Type: text/x-patch, Size: 3713 bytes --]

From 36f06b07d9cfb3974c160ecc22def3cb1b117106 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Thu, 9 Feb 2023 17:09:23 -0800
Subject: [PATCH] nullptr: work around Apple clang 14 issue

Problem reported by Bruno Haible in:
https://lists.gnu.org/r/bug-gnulib/2023-02/msg00098.html
* doc/gnulib.texi (nullptr): Document limitations better.
* m4/nullptr.m4 (gl_NULLPTR): Check for incompatibility of macOS
clang 14.0.0 (clang-1400.0.29.202), where <stddef.h> defines a
non-working nullptr macro.
---
 ChangeLog       | 10 ++++++++++
 doc/gnulib.texi |  7 ++++---
 m4/nullptr.m4   | 30 ++++++++++++++++++++----------
 3 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 867107bb14..ce5ce330e6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2023-02-09  Paul Eggert  <eggert@cs.ucla.edu>
+
+	nullptr: work around Apple clang 14 issue
+	Problem reported by Bruno Haible in:
+	https://lists.gnu.org/r/bug-gnulib/2023-02/msg00098.html
+	* doc/gnulib.texi (nullptr): Document limitations better.
+	* m4/nullptr.m4 (gl_NULLPTR): Check for incompatibility of macOS
+	clang 14.0.0 (clang-1400.0.29.202), where <stddef.h> defines a
+	non-working nullptr macro.
+
 2023-02-09  Bruno Haible  <bruno@clisp.org>
 
 	math: Fix compilation error in C++ mode on macOS 12.5.
diff --git a/doc/gnulib.texi b/doc/gnulib.texi
index 6fe2678834..28d8c20d8c 100644
--- a/doc/gnulib.texi
+++ b/doc/gnulib.texi
@@ -954,9 +954,10 @@ In C, it has type @code{void *}; in C++ it has an integer type.
 
 @item
 On older platforms Gnulib cannot easily emulate @code{nullptr_t}, so
-null pointer type checking is more error prone, and @code{_Generic}
-expressions cannot reliably distinguish @code{nullptr}'s type from
-integer or @code{void *} types.
+null pointer type checking is more error prone.  In C, @code{_Generic}
+expressions cannot reliably distinguish the type of @code{nullptr}
+from integer or @code{void *} types.  C++ overloading has similar
+limitations.
 @end itemize
 
 @node static_assert
diff --git a/m4/nullptr.m4 b/m4/nullptr.m4
index a0b438be94..1f8ab51b85 100644
--- a/m4/nullptr.m4
+++ b/m4/nullptr.m4
@@ -28,20 +28,30 @@ AC_DEFUN([gl_NULLPTR],
        [AC_COMPILE_IFELSE(
           [AC_LANG_SOURCE([[int *p = nullptr;]])],
           [gl_cv_cxx_nullptr=yes],
-          [gl_cv_cxx_nullptr=no])])
-      gl_cxx_nullptr=$gl_cv_cxx_nullptr
-      AC_LANG_POP([C++])],
-     [gl_cxx_nullptr=no])
-  if test "$gl_cxx_nullptr" = yes; then
-    AC_DEFINE([HAVE_CXX_NULLPTR], [1], [Define to 1 if C++ nullptr works.])
-  fi
+          [AC_COMPILE_IFELSE(
+             [AC_LANG_SOURCE([[#include <stddef.h>
+                               int *p = nullptr;]])],
+             [gl_cv_cxx_nullptr="yes, but it is a <stddef.h> macro"],
+             [gl_cv_cxx_nullptr=no])])])
+     AS_CASE([$gl_cv_cxx_nullptr],
+       [yes],  [gl_have_cxx_nullptr=1],
+       [yes*], [gl_have_cxx_nullptr="(-1)"],
+               [gl_have_cxx_nullptr=0])
+     AC_DEFINE_UNQUOTED([HAVE_CXX_NULLPTR], [$gl_have_cxx_nullptr],
+                        [Define to 1 if C++ nullptr works, 0 if not,
+                         (-1) if it is a <stddef.h> macro.])
+     AC_LANG_POP([C++])])
 ])
 
-  AH_VERBATIM([nullptr],
-[#ifndef nullptr /* keep config.h idempotent */
+  AH_VERBATIM([zznullptr],
+[#if defined __cplusplus && HAVE_CXX_NULLPTR < 0
+# include <stddef.h>
+# undef/**/nullptr
+#endif
+#ifndef nullptr
 # if !defined __cplusplus && !defined HAVE_C_NULLPTR
 #  define nullptr ((void *) 0)
-# elif defined __cplusplus && !defined HAVE_CXX_NULLPTR
+# elif defined __cplusplus && HAVE_CXX_NULLPTR <= 0
 #  if 3 <= __GNUG__
 #   define nullptr __null
 #  else
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: nullptr in C++ mode on macOS
  2023-02-10  1:20 ` Paul Eggert
@ 2023-02-10  8:58   ` Bruno Haible
  0 siblings, 0 replies; 6+ messages in thread
From: Bruno Haible @ 2023-02-10  8:58 UTC (permalink / raw)
  To: Paul Eggert; +Cc: bug-gnulib, Arsen Arsenović

Paul Eggert wrote:
> Let's treat C++ overloading like we already treat C _Generic, that is, 
> as a documented limitation of the substitute nullptr macro. This should 
> be good enough for Gnulib itself. I installed the attached to document 
> that, and to work around the Apple clang 14 incompatibility with it in mind.

It should also be good enough for real C++ packages such as groff and octave,
which both use nullptr but not nullptr_t.

> Yes, but all that's needed here is to implement Gnulib's limited 
> substitute well enough to work with Apple clang 14 and any other 
> compilers that have similar incompatibilities with current C++.

It works fine. Clever. Thank you!!

Thank you Arsen, for the proposal. I prefer Paul's approach because it
avoids getting deeper and deeper into the C++ swamp of complicated
inconsistencies.

Bruno





^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: nullptr in C++ mode on macOS
  2023-02-09 20:38 ` Jeffrey Walton
@ 2023-02-10  9:10   ` Bruno Haible
  0 siblings, 0 replies; 6+ messages in thread
From: Bruno Haible @ 2023-02-10  9:10 UTC (permalink / raw)
  To: noloader; +Cc: bug-gnulib

Jeffrey Walton wrote:
> Then you have Apple's version of Clang. They are probably C++03 for
> compatibility reasons for Xcode developers. So even if LLVM moved to
> C++11, Apple's Clang may stay at C++03.

Ah, that explains the nullptr issue with this compiler, and also why
we have to test __apple_build_version__ (or __APPLE_CC__) in a couple
of places.

> > I don't know how to proceed here. C++ is such a waste of time!!
> 
> In the projects I work on, I use a library specific define. In
> Gnulib's case, it would be GNULIB_NULLPTR. Then I have a feature test
> to set GNULIB_NULLPTR to either nullptr or NULL. The strategy works
> well for me.
> 
>     #if defined(HAVE_CXX11_NULLPTR)
>     #   define GNULIB_NULLPTR nullptr
>     #else
>     #   define GNULIB_NULLPTR NULL
>     #endif

In Gnulib, we started with this coding style many years ago. Then
switched to the today's style where the programmer can use exactly
the identifiers from the relevant standards (POSIX, ISO C, ISO C++),
without some 'gnulib_' or 'gl_' prefixes in most of the cases.

Bruno





^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-02-10  9:10 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-09 19:31 nullptr in C++ mode on macOS Bruno Haible
2023-02-09 20:08 ` Arsen Arsenović
2023-02-09 20:38 ` Jeffrey Walton
2023-02-10  9:10   ` Bruno Haible
2023-02-10  1:20 ` Paul Eggert
2023-02-10  8:58   ` Bruno Haible

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).