On Mon, Oct 13, 2025 at 6:50 AM Bruno Haible via Gnulib discussion
list <[email protected]> wrote:
>
> Collin Funk wrote:
> > Thanks for the review. I pushed the patches with that change to the
> > manual and Bruno's formatting suggestions.
>
> Unfortunately, the CI reports a compilation error on glibc systems
> and musl libc systems. It can be reproduced with a testdir:
>
> $ ./gnulib-tool --create-testdir --dir=../testdir --symlink --with-c++-tests 
> nullptr getline
>
> This is the error:
>
> g++ -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/media/develdata/devel/inst-x86_64-64/include 
> -Wall -Wno-error -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
> In file included from /gnu-inst-gcc/15.2.0/include/c++/15.2.0/cstdio:47,
>                  from 
> /gnu-inst-gcc/15.2.0/include/c++/15.2.0/ext/string_conversions.h:47,
>                  from 
> /gnu-inst-gcc/15.2.0/include/c++/15.2.0/bits/basic_string.h:4444,
>                  from /gnu-inst-gcc/15.2.0/include/c++/15.2.0/string:56,
>                  from 
> /gnu-inst-gcc/15.2.0/include/c++/15.2.0/bits/locale_classes.h:42,
>                  from 
> /gnu-inst-gcc/15.2.0/include/c++/15.2.0/bits/ios_base.h:43,
>                  from /gnu-inst-gcc/15.2.0/include/c++/15.2.0/ios:46,
>                  from 
> /gnu-inst-gcc/15.2.0/include/c++/15.2.0/bits/ostream.h:43,
>                  from /gnu-inst-gcc/15.2.0/include/c++/15.2.0/ostream:42,
>                  from /gnu-inst-gcc/15.2.0/include/c++/15.2.0/iostream:43,
>                  from ../../gltests/test-nullptr-c++.cc:25:
> /gnu-inst-gcc/15.2.0/include/c++/15.2.0/bits/basic_string.tcc:1032:5: error: 
> template-id ‘rpl_getline<>’ for ‘std::basic_istream<char>& 
> std::rpl_getline(basic_istream<char>&, string&)’ does not match any template 
> declaration
>  1032 |     getline(basic_istream<char>&, string&);
>       |     ^~~~~~~
>
> The cause is a std::basic_istream::getline member function, that
> is visible in <string> or <istream>.
>
> The usual workaround to #include <string> and/or #include <istream>
> does not work here, because some definitions from <stdio.h> would not
> be available.
>
> So, the fix is to define getline as an inline function rather than as a
> macro. But additionally, this gets complicated by an inline function in
> glibc's <bits/stdio.h>:
>
> __STDIO_INLINE __ssize_t
> getline (char **__lineptr, size_t *__n, FILE *__stream)
> {
>   return __getdelim (__lineptr, __n, '\n', __stream);
> }
>
> We can't override an inline function with an inline function. The
> workaround therefore gets complicated:
>
>
> 2025-10-13  Bruno Haible  <[email protected]>
>
>         getline: Fix compilation error in C++ mode (regression 2025-10-10).
>         * lib/stdio.in.h (getdelim): On glibc, define __getdelim instead of
>         rpl_getdelim.
>         (getline): In C++ mode, define getline as an inline function instead 
> of
>         as a macro.
>         * lib/getdelim.c (getdelim): On glibc, don't test whether fp is NULL.
>
> diff --git a/lib/stdio.in.h b/lib/stdio.in.h
> index f3ab7969d1..2c70bc049f 100644
> --- a/lib/stdio.in.h
> +++ b/lib/stdio.in.h
> @@ -1044,6 +1044,11 @@ _GL_CXXALIASWARN (getchar);
>  #   undef getdelim
>  #   define getdelim rpl_getdelim
>  #  endif
> +#  if __GLIBC__ >= 2
> +/* Arrange for the inline definition of getline() in <bits/stdio.h>
> +   to call our getdelim() override.  */
> +#   define rpl_getdelim __getdelim
> +#  endif
>  _GL_FUNCDECL_RPL (getdelim, ssize_t,
>                    (char **restrict lineptr, size_t *restrict linesize,
>                     int delimiter,
> @@ -1085,14 +1090,27 @@ _GL_WARN_ON_USE (getdelim, "getdelim is unportable - "
>     Return the number of bytes read and stored at *LINEPTR (not including the
>     NUL terminator), or -1 on error or EOF.  */
>  # if @REPLACE_GETLINE@
> -#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
> -#   undef getline
> -#   define getline rpl_getline
> -#  endif
>  _GL_FUNCDECL_RPL (getline, ssize_t,
>                    (char **restrict lineptr, size_t *restrict linesize,
>                     FILE *restrict stream),
>                    _GL_ARG_NONNULL ((1, 2, 3)) _GL_ATTRIBUTE_NODISCARD);
> +#  if defined __cplusplus
> +/* The C++ standard library defines std::basic_istream::getline in <istream>
> +   or <string>.  */
> +#   if !(__GLIBC__ >= 2)
> +extern "C" {
> +inline ssize_t
> +getline (char **restrict lineptr, size_t *restrict linesize,
> +         FILE *restrict stream)
> +{
> +  return rpl_getline (lineptr, linesize, stream);
> +}
> +}
> +#   endif
> +#  else
> +#   undef getline
> +#   define getline rpl_getline
> +#  endif
>  _GL_CXXALIAS_RPL (getline, ssize_t,
>                    (char **restrict lineptr, size_t *restrict linesize,
>                     FILE *restrict stream));
> diff --git a/lib/getdelim.c b/lib/getdelim.c
> index 2576d376f0..4cd5eca189 100644
> --- a/lib/getdelim.c
> +++ b/lib/getdelim.c
> @@ -65,7 +65,13 @@ getdelim (char **lineptr, size_t *n, int delimiter, FILE 
> *fp)
>    ssize_t result;
>    size_t cur_len = 0;
>
> -  if (lineptr == NULL || n == NULL || fp == NULL)
> +  if (lineptr == NULL || n == NULL
> +      /* glibc already declares this function as __nonnull ((4)).
> +         Avoid a gcc warning "‘nonnull’ argument ‘fp’ compared to NULL".  */
> +#if !(__GLIBC__ >= 2)
> +      || fp == NULL
> +#endif
> +     )
>      {
>        errno = EINVAL;
>        return -1;


Based on "> 
/gnu-inst-gcc/15.2.0/include/c++/15.2.0/bits/basic_string.tcc:1032:5:
error: template-id ‘rpl_getline<>’ for ‘std::basic_istream<char>&
std::rpl_getline(basic_istream<char>&, string&)’ does not match any
template declaration".  Notice the
"std::rpl_getline(basic_istream<char>&, string&)".

I don't think Gnulib is allowed to override symbols in the C++ std::
namespace.  I think the only symbol that can be overridden is
std::swap.

Jeff

Reply via email to