Hi Bruno,

Bruno Haible <[email protected]> writes:

> Reviewing the patch: It's nearly right, except:
>
> 1) In m4/stdckdint.m4:
>
> +  if test $HAVE_STDCKDINT_H == 1; then
>
> '==' is an invalid operator for 'test'. See
> https://pubs.opengroup.org/onlinepubs/9799919799/utilities/test.html
> or https://www.man7.org/linux/man-pages/man1/test.1.html .
> (It may be a bash extension.)

Yep, it is a bash extension. I typed it by mistake, fixed.

> 2) In lib/stdckdint.in.h: Due to the #include_next,
> you need the
>   /* The include_next requires a split double-inclusion guard.  */
> idiom, found e.g. in mntent.in.h.

Ah, okay. I had a feeling something was off there. The mntent.in.h
example is good.

I looked at ones that are much more complex like fcntl.in.h which has
work work around nested includes and missing typedefs. So more complex
than an example needs to be.

> 3) "checking whether stdckdint.h defines ckd_add, ckd_sub, ckd_mul in C..."
>
> This message is a bit long and technical. Can you try to shorten it?
> Such as "checking for an ISO C23 compliant stdckdint.h in C..." ?

Sure, I changed the messages to:

    checking for an ISO C23 compliant stdckdint.h in C
    checking for an ISO C++26 compliant stdckdint.h in C++

And updated the comment in stdckdint.in.h to mention the upcoming C++26
standard plans to add this header.

> It seems that the GCC developers, for the C language, like to make stuff
> from newer standards available with older -std options. Whereas the
> libstdc++ and glibc developers prefer to follow the standard specified
> through -std to the letter.
> Each of the approaches has its upsides and downsides. I don't think it's
> worth reporting one or the other as a "bug".

Okay, makes sense. I agree, not a bug. I just wasn't sure that it was
intentional at the time.

Anyways, pushed the attached patch since the changes were minimal.
Thanks for checking!

Collin

>From e331531a771443edae4135e6bcd016282cf1a3aa Mon Sep 17 00:00:00 2001
Message-ID: <e331531a771443edae4135e6bcd016282cf1a3aa.1747968399.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Thu, 22 May 2025 19:33:05 -0700
Subject: [PATCH] stdckdint-h: Don't generate header if it is not needed.

Suggested by Paul Eggert in:
<https://lists.gnu.org/archive/html/bug-gnulib/2025-05/msg00216.html>.

* m4/stdckdint_h.m4: New file.
* modules/stdckdint-h (Files): Add m4/stdckdint_h.m4.
(configure.ac): Remove checks and just invoke gl_STDCKDINT_H.
(Makefile.am): Replace variables set by ./configure.
* lib/stdckdint.in.h: Include the compilers header if it exists.  Add
comment mentioning expected future standardization in C++26.
(ckd_add, ckd_sub, ckd_mul): Only define if the compilers definitions do
not work.
---
 ChangeLog           |  14 +++++
 lib/stdckdint.in.h  |  39 ++++++++++---
 m4/stdckdint_h.m4   | 136 ++++++++++++++++++++++++++++++++++++++++++++
 modules/stdckdint-h |  21 +++----
 4 files changed, 192 insertions(+), 18 deletions(-)
 create mode 100644 m4/stdckdint_h.m4

diff --git a/ChangeLog b/ChangeLog
index 0145e21fb2..f2ccb1fb94 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2025-05-22  Collin Funk  <[email protected]>
+
+	stdckdint-h: Don't generate header if it is not needed.
+	Suggested by Paul Eggert in:
+	<https://lists.gnu.org/archive/html/bug-gnulib/2025-05/msg00216.html>.
+	* m4/stdckdint_h.m4: New file.
+	* modules/stdckdint-h (Files): Add m4/stdckdint_h.m4.
+	(configure.ac): Remove checks and just invoke gl_STDCKDINT_H.
+	(Makefile.am): Replace variables set by ./configure.
+	* lib/stdckdint.in.h: Include the compilers header if it exists.  Add
+	comment mentioning expected future standardization in C++26.
+	(ckd_add, ckd_sub, ckd_mul): Only define if the compilers definitions do
+	not work.
+
 2025-05-22  Bruno Haible  <[email protected]>
 
 	strchrnul: Update doc.
diff --git a/lib/stdckdint.in.h b/lib/stdckdint.in.h
index 83277b728e..bb9089b4a1 100644
--- a/lib/stdckdint.in.h
+++ b/lib/stdckdint.in.h
@@ -15,10 +15,30 @@
    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
-#ifndef _GL_STDCKDINT_H
-#define _GL_STDCKDINT_H
+#if __GNUC__ >= 3
+@PRAGMA_SYSTEM_HEADER@
+#endif
+@PRAGMA_COLUMNS@
 
-#include "intprops-internal.h"
+#ifndef _@GUARD_PREFIX@_STDCKDINT_H
+
+/* The include_next requires a split double-inclusion guard.  */
+#if defined __cplusplus ? @HAVE_CXX_STDCKDINT_H@ : @HAVE_C_STDCKDINT_H@
+# @INCLUDE_NEXT@ @NEXT_STDCKDINT_H@
+#endif
+
+#ifndef _@GUARD_PREFIX@_STDCKDINT_H
+#define _@GUARD_PREFIX@_STDCKDINT_H
+
+/* Do nothing but include the system header if it works properly.  */
+# if defined __cplusplus ? !@HAVE_WORKING_CXX_STDCKDINT_H@ : !@HAVE_WORKING_C_STDCKDINT_H@
+
+/* Avoid redefining macros.  */
+#  undef ckd_add
+#  undef ckd_sub
+#  undef ckd_mul
+
+#  include "intprops-internal.h"
 
 /* Store into *R the low-order bits of A + B, A - B, A * B, respectively.
    Return 1 if the result overflows, 0 otherwise.
@@ -26,10 +46,13 @@
    bit-precise integer type, or an enumeration type.
 
    These are like the standard macros introduced in C23, except that
-   arguments should not have side effects.  */
+   arguments should not have side effects.  The C++26 standard is
+   expected to add this header and it's macros.  */
 
-#define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r))
-#define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r))
-#define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r))
+#  define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r))
+#  define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r))
+#  define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r))
 
-#endif /* _GL_STDCKDINT_H */
+# endif /* defined __cplusplus ? @HAVE_WORKING_CXX_STDCKDINT_H@ : @HAVE_WORKING_C_STDCKDINT_H@ */
+#endif /* _@GUARD_PREFIX@_STDCKDINT_H */
+#endif /* _@GUARD_PREFIX@_STDCKDINT_H */
diff --git a/m4/stdckdint_h.m4 b/m4/stdckdint_h.m4
new file mode 100644
index 0000000000..d269faa5c9
--- /dev/null
+++ b/m4/stdckdint_h.m4
@@ -0,0 +1,136 @@
+# stdckdint_h.m4
+# serial 1
+dnl Copyright 2025 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl This file is offered as-is, without any warranty.
+
+dnl Written by Collin Funk.
+
+AC_DEFUN_ONCE([gl_STDCKDINT_H],
+[
+  gl_CHECK_NEXT_HEADERS([stdckdint.h])
+  if test $ac_cv_header_stdckdint_h = yes; then
+    HAVE_STDCKDINT_H=1
+  else
+    HAVE_STDCKDINT_H=0
+  fi
+  AC_SUBST([HAVE_STDCKDINT_H])
+
+  if test $HAVE_STDCKDINT_H = 1; then
+    AC_CACHE_CHECK([whether stdckdint.h can be included in C],
+      [gl_cv_header_c_stdckdint_h],
+      [AC_COMPILE_IFELSE(
+         [AC_LANG_PROGRAM(
+            [[#include <stdckdint.h>
+            ]])],
+         [gl_cv_header_c_stdckdint_h=yes],
+         [gl_cv_header_c_stdckdint_h=no])])
+    if test $gl_cv_header_c_stdckdint_h = yes; then
+      HAVE_C_STDCKDINT_H=1
+      AC_CACHE_CHECK([checking for an ISO C23 compliant stdckdint.h in C],
+        [gl_cv_header_c_stdckdint_h_works],
+        [AC_COMPILE_IFELSE(
+           [AC_LANG_PROGRAM(
+              [[#include <stdckdint.h>
+              ]],
+              [[int r;
+                int a = 1;
+                int b = 1;
+                return !!(ckd_add (&r, a, b) || ckd_sub (&r, a, b)
+                          || ckd_mul (&r, a, b));
+              ]])],
+           [gl_cv_header_c_stdckdint_h_works=yes],
+           [gl_cv_header_c_stdckdint_h_works=no])])
+      if test $gl_cv_header_c_stdckdint_h_works = yes; then
+        HAVE_WORKING_C_STDCKDINT_H=1
+      else
+        HAVE_WORKING_C_STDCKDINT_H=0
+      fi
+    else
+      HAVE_C_STDCKDINT_H=0
+      HAVE_WORKING_C_STDCKDINT_H=0
+    fi
+    if test "$CXX" != no; then
+      AC_CACHE_CHECK([whether stdckdint.h can be included in C++],
+        [gl_cv_header_cxx_stdckdint_h],
+        [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to
+         dnl an autoconf bug <https://savannah.gnu.org/support/?110294>.
+         cat > conftest.cpp <<\EOF
+#include <stdckdint.h>
+EOF
+         gl_command="$CXX $CXXFLAGS $CPPFLAGS -c conftest.cpp"
+         if AC_TRY_EVAL([gl_command]); then
+           gl_cv_header_cxx_stdckdint_h=yes
+         else
+           gl_cv_header_cxx_stdckdint_h=no
+         fi
+         rm -fr conftest*
+        ])
+      if test $gl_cv_header_cxx_stdckdint_h = yes; then
+        HAVE_CXX_STDCKDINT_H=1
+        AC_CACHE_CHECK([checking for an ISO C++26 compliant stdckdint.h in C++],
+          [gl_cv_header_cxx_stdckdint_h_works],
+          [dnl We can't use AC_LANG_PUSH([C++]) and AC_LANG_POP([C++]) here, due to
+           dnl an autoconf bug <https://savannah.gnu.org/support/?110294>.
+           cat > conftest.cpp <<\EOF
+#include <stdckdint.h>
+int
+main (void)
+{
+  int r;
+  int a = 1;
+  int b = 1;
+  return !!(ckd_add (&r, a, b) || ckd_sub (&r, a, b) || ckd_mul (&r, a, b));
+}
+EOF
+           gl_command="$CXX $CXXFLAGS $CPPFLAGS -c conftest.cpp"
+           if AC_TRY_EVAL([gl_command]); then
+             gl_cv_header_cxx_stdckdint_h_works=yes
+           else
+             gl_cv_header_cxx_stdckdint_h_works=no
+           fi
+           rm -fr conftest*
+          ])
+        if test $gl_cv_header_cxx_stdckdint_h_works = yes; then
+          HAVE_WORKING_CXX_STDCKDINT_H=1
+        else
+          HAVE_WORKING_CXX_STDCKDINT_H=0
+        fi
+      else
+        HAVE_CXX_STDCKDINT_H=0
+        HAVE_WORKING_CXX_STDCKDINT_H=0
+      fi
+    fi
+  else
+    HAVE_C_STDCKDINT_H=0
+    HAVE_WORKING_C_STDCKDINT_H=0
+    HAVE_CXX_STDCKDINT_H=0
+    HAVE_WORKING_CXX_STDCKDINT_H=0
+  fi
+  AC_SUBST([HAVE_C_STDCKDINT_H])
+  AC_SUBST([HAVE_WORKING_C_STDCKDINT_H])
+  AC_SUBST([HAVE_CXX_STDCKDINT_H])
+  AC_SUBST([HAVE_WORKING_CXX_STDCKDINT_H])
+
+  if test "$CXX" != no; then
+    dnl We might need the header for C or C++.
+    if test $HAVE_C_STDCKDINT_H = 1 \
+       && test $HAVE_WORKING_C_STDCKDINT_H = 1 \
+       && test $HAVE_CXX_STDCKDINT_H = 1 \
+       && test $HAVE_WORKING_CXX_STDCKDINT_H = 1; then
+      GL_GENERATE_STDCKDINT_H=false
+    else
+      GL_GENERATE_STDCKDINT_H=true
+    fi
+  else
+    dnl We don't care about C++ here.
+    if test $HAVE_C_STDCKDINT_H = 1 \
+       && test $HAVE_WORKING_C_STDCKDINT_H = 1; then
+      GL_GENERATE_STDCKDINT_H=false
+    else
+      GL_GENERATE_STDCKDINT_H=true
+    fi
+  fi
+])
diff --git a/modules/stdckdint-h b/modules/stdckdint-h
index ff777d8d62..7f7c612bce 100644
--- a/modules/stdckdint-h
+++ b/modules/stdckdint-h
@@ -2,6 +2,7 @@ Description:
 An <stdckdint.h> that is like C23.
 
 Files:
+m4/stdckdint_h.m4
 lib/stdckdint.in.h
 lib/intprops-internal.h
 
@@ -10,16 +11,7 @@ gen-header
 bool
 
 configure.ac:
-AC_CHECK_HEADERS_ONCE([stdckdint.h])
-if test $ac_cv_header_stdckdint_h = yes; then
-  if test -n "$CXX" && test "$CXX" != no; then
-    GL_GENERATE_STDCKDINT_H=true
-  else
-    GL_GENERATE_STDCKDINT_H=false
-  fi
-else
-  GL_GENERATE_STDCKDINT_H=true
-fi
+gl_STDCKDINT_H
 gl_CONDITIONAL_HEADER([stdckdint.h])
 AC_PROG_MKDIR_P
 
@@ -32,6 +24,15 @@ if GL_GENERATE_STDCKDINT_H
 stdckdint.h: stdckdint.in.h $(top_builddir)/config.status
 @NMD@	$(AM_V_GEN)$(MKDIR_P) '%reldir%'
 	$(gl_V_at)$(SED_HEADER_STDOUT) \
+	      -e 's|@''GUARD_PREFIX''@|${gl_include_guard_prefix}|g' \
+	      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
+	      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
+	      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
+	      -e 's|@''NEXT_STDCKDINT_H''@|$(NEXT_STDCKDINT_H)|g' \
+	      -e 's|@''HAVE_C_STDCKDINT_H''@|$(HAVE_C_STDCKDINT_H)|g' \
+	      -e 's|@''HAVE_WORKING_C_STDCKDINT_H''@|$(HAVE_WORKING_C_STDCKDINT_H)|g' \
+	      -e 's|@''HAVE_CXX_STDCKDINT_H''@|$(HAVE_CXX_STDCKDINT_H)|g' \
+	      -e 's|@''HAVE_WORKING_CXX_STDCKDINT_H''@|$(HAVE_WORKING_CXX_STDCKDINT_H)|g' \
 	  $(srcdir)/stdckdint.in.h > $@-t
 	$(AM_V_at)mv $@-t $@
 else
-- 
2.49.0

Reply via email to