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;