c, v4: Add stdckdint.h header for C23

Message ID ZNZwXD4oLQPO98KZ@tucnak
State Unresolved
Headers
Series c, v4: Add stdckdint.h header for C23 |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Jakub Jelinek Aug. 11, 2023, 5:31 p.m. UTC
  On Fri, Aug 11, 2023 at 01:25:38PM +0000, Joseph Myers wrote:
> On Fri, 11 Aug 2023, Jakub Jelinek wrote:
> 
> > All that is diagnosed is when result is bool or enum (any kind).  Even for
> 
> I'd suggest tests that other nonsense cases are diagnosed, such as 
> floating-point or pointer arguments or results (hopefully such cases are 
> already diagnosed and just need tests).

So like this then?

2023-08-11  Jakub Jelinek  <jakub@redhat.com>

	* Makefile.in (USER_H): Add stdckdint.h.
	* ginclude/stdckdint.h: New file.

	* gcc.dg/stdckdint-1.c: New test.
	* gcc.dg/stdckdint-2.c: New test.



	Jakub
  

Comments

Joseph Myers Aug. 11, 2023, 9:50 p.m. UTC | #1
On Fri, 11 Aug 2023, Jakub Jelinek via Gcc-patches wrote:

> On Fri, Aug 11, 2023 at 01:25:38PM +0000, Joseph Myers wrote:
> > On Fri, 11 Aug 2023, Jakub Jelinek wrote:
> > 
> > > All that is diagnosed is when result is bool or enum (any kind).  Even for
> > 
> > I'd suggest tests that other nonsense cases are diagnosed, such as 
> > floating-point or pointer arguments or results (hopefully such cases are 
> > already diagnosed and just need tests).
> 
> So like this then?

I think it should also test the diagnostic for when *result is 
const-qualified.  OK with that change.
  

Patch

--- gcc/Makefile.in.jj	2023-08-11 10:15:49.669691051 +0200
+++ gcc/Makefile.in	2023-08-11 18:48:52.829964582 +0200
@@ -469,6 +469,7 @@  USER_H = $(srcdir)/ginclude/float.h \
 	 $(srcdir)/ginclude/stdnoreturn.h \
 	 $(srcdir)/ginclude/stdalign.h \
 	 $(srcdir)/ginclude/stdatomic.h \
+	 $(srcdir)/ginclude/stdckdint.h \
 	 $(EXTRA_HEADERS)
 
 USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
--- gcc/ginclude/stdckdint.h.jj	2023-08-11 18:48:52.829964582 +0200
+++ gcc/ginclude/stdckdint.h	2023-08-11 18:48:52.829964582 +0200
@@ -0,0 +1,40 @@ 
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/* ISO C23: 7.20 Checked Integer Arithmetic <stdckdint.h>.  */
+
+#ifndef _STDCKDINT_H
+#define _STDCKDINT_H
+
+#define __STDC_VERSION_STDCKDINT_H__ 202311L
+
+#define ckd_add(r, a, b) ((_Bool) __builtin_add_overflow (a, b, r))
+#define ckd_sub(r, a, b) ((_Bool) __builtin_sub_overflow (a, b, r))
+#define ckd_mul(r, a, b) ((_Bool) __builtin_mul_overflow (a, b, r))
+
+/* Allow for the C library to add its part to the header.  */
+#if !defined (_LIBC_STDCKDINT_H) && __has_include_next (<stdckdint.h>)
+# include_next <stdckdint.h>
+#endif
+
+#endif /* stdckdint.h */
--- gcc/testsuite/gcc.dg/stdckdint-1.c.jj	2023-08-11 18:48:52.829964582 +0200
+++ gcc/testsuite/gcc.dg/stdckdint-1.c	2023-08-11 18:48:52.829964582 +0200
@@ -0,0 +1,61 @@ 
+/* Test C23 Checked Integer Arithmetic macros in <stdckdint.h>.  */
+/* { dg-do run } */
+/* { dg-options "-std=c2x" } */
+
+#include <stdckdint.h>
+
+#if __STDC_VERSION_STDCKDINT_H__ != 202311L
+# error __STDC_VERSION_STDCKDINT_H__ not defined to 202311L
+#endif
+
+extern void abort (void);
+
+int
+main ()
+{
+  unsigned int a;
+  if (ckd_add (&a, 1, 2) || a != 3)
+    abort ();
+  if (ckd_add (&a, ~2U, 2) || a != ~0U)
+    abort ();
+  if (!ckd_add (&a, ~2U, 4) || a != 1)
+    abort ();
+  if (ckd_sub (&a, 42, 2) || a != 40)
+    abort ();
+  if (!ckd_sub (&a, 11, ~0ULL) || a != 12)
+    abort ();
+  if (ckd_mul (&a, 42, 16U) || a != 672)
+    abort ();
+  if (ckd_mul (&a, ~0UL, 0) || a != 0)
+    abort ();
+  if (ckd_mul (&a, 1, ~0U) || a != ~0U)
+    abort ();
+  if (ckd_mul (&a, ~0UL, 1) != (~0UL > ~0U) || a != ~0U)
+    abort ();
+  static_assert (_Generic (ckd_add (&a, 1, 1), bool: 1, default: 0));
+  static_assert (_Generic (ckd_sub (&a, 1, 1), bool: 1, default: 0));
+  static_assert (_Generic (ckd_mul (&a, 1, 1), bool: 1, default: 0));
+  signed char b;
+  if (ckd_add (&b, 8, 12) || b != 20)
+    abort ();
+  if (ckd_sub (&b, 8UL, 12ULL) || b != -4)
+    abort ();
+  if (ckd_mul (&b, 2, 3) || b != 6)
+    abort ();
+  unsigned char c;
+  if (ckd_add (&c, 8, 12) || c != 20)
+    abort ();
+  if (ckd_sub (&c, 8UL, 12ULL) != (-4ULL > (unsigned char) -4U)
+      || c != (unsigned char) -4U)
+    abort ();
+  if (ckd_mul (&c, 2, 3) || c != 6)
+    abort ();
+  long long d;
+  if (ckd_add (&d, ~0U, ~0U) != (~0U + 1ULL < ~0U)
+      || d != (long long) (2 * (unsigned long long) ~0U))
+    abort ();
+  if (ckd_sub (&d, 0, 0) || d != 0)
+    abort ();
+  if (ckd_mul (&d, 16, 1) || d != 16)
+    abort ();
+}
--- gcc/testsuite/gcc.dg/stdckdint-2.c.jj	2023-08-11 18:48:52.829964582 +0200
+++ gcc/testsuite/gcc.dg/stdckdint-2.c	2023-08-11 19:28:50.081643961 +0200
@@ -0,0 +1,87 @@ 
+/* Test C23 Checked Integer Arithmetic macros in <stdckdint.h>.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x" } */
+
+#include <stdckdint.h>
+
+int
+main ()
+{
+  char a;
+  bool b;
+  enum E { E1, E2 } c = E1;
+  int d;
+  int *e;
+  float f;
+  double g;
+  long double h;
+  ckd_add (&a, 1, 1);
+  ckd_sub (&a, 1, 1);
+  ckd_mul (&a, 1, 1);
+  ckd_add (&b, 1, 1);		/* { dg-error "has pointer to boolean type" } */
+  ckd_sub (&b, 1, 1);		/* { dg-error "has pointer to boolean type" } */
+  ckd_mul (&b, 1, 1);		/* { dg-error "has pointer to boolean type" } */
+  ckd_add (&c, 1, 1);		/* { dg-error "has pointer to enumerated type" } */
+  ckd_sub (&c, 1, 1);		/* { dg-error "has pointer to enumerated type" } */
+  ckd_mul (&c, 1, 1);		/* { dg-error "has pointer to enumerated type" } */
+  ckd_add (&d, (char) 1, 1);
+  ckd_sub (&d, (char) 1, 1);
+  ckd_mul (&d, (char) 1, 1);
+  ckd_add (&d, false, 1);
+  ckd_sub (&d, false, 1);
+  ckd_mul (&d, false, 1);
+  ckd_add (&d, true, 1);
+  ckd_sub (&d, true, 1);
+  ckd_mul (&d, true, 1);
+  ckd_add (&d, c, 1);
+  ckd_sub (&d, c, 1);
+  ckd_mul (&d, c, 1);
+  ckd_add (&d, 1, (char) 1);
+  ckd_sub (&d, 1, (char) 1);
+  ckd_mul (&d, 1, (char) 1);
+  ckd_add (&d, 1, false);
+  ckd_sub (&d, 1, false);
+  ckd_mul (&d, 1, false);
+  ckd_add (&d, 1, true);
+  ckd_sub (&d, 1, true);
+  ckd_mul (&d, 1, true);
+  ckd_add (&d, 1, c);
+  ckd_sub (&d, 1, c);
+  ckd_mul (&d, 1, c);
+  ckd_add (&e, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_sub (&e, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_mul (&e, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_add (&f, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_sub (&f, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_mul (&f, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_add (&g, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_sub (&g, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_mul (&g, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_add (&h, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_sub (&h, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_mul (&h, 1, 1);		/* { dg-error "does not have pointer to integral type" } */
+  ckd_add (&d, 1.0f, 1);	/* { dg-error "does not have integral type" } */
+  ckd_sub (&d, 1.0f, 1);	/* { dg-error "does not have integral type" } */
+  ckd_mul (&d, 1.0f, 1);	/* { dg-error "does not have integral type" } */
+  ckd_add (&d, 1.0, 1);		/* { dg-error "does not have integral type" } */
+  ckd_sub (&d, 1.0, 1);		/* { dg-error "does not have integral type" } */
+  ckd_mul (&d, 1.0, 1);		/* { dg-error "does not have integral type" } */
+  ckd_add (&d, 1.0L, 1);	/* { dg-error "does not have integral type" } */
+  ckd_sub (&d, 1.0L, 1);	/* { dg-error "does not have integral type" } */
+  ckd_mul (&d, 1.0L, 1);	/* { dg-error "does not have integral type" } */
+  ckd_add (&d, 1, 1.0f);	/* { dg-error "does not have integral type" } */
+  ckd_sub (&d, 1, 1.0f);	/* { dg-error "does not have integral type" } */
+  ckd_mul (&d, 1, 1.0f);	/* { dg-error "does not have integral type" } */
+  ckd_add (&d, 1, 1.0);		/* { dg-error "does not have integral type" } */
+  ckd_sub (&d, 1, 1.0);		/* { dg-error "does not have integral type" } */
+  ckd_mul (&d, 1, 1.0);		/* { dg-error "does not have integral type" } */
+  ckd_add (&d, 1, 1.0L);	/* { dg-error "does not have integral type" } */
+  ckd_sub (&d, 1, 1.0L);	/* { dg-error "does not have integral type" } */
+  ckd_mul (&d, 1, 1.0L);	/* { dg-error "does not have integral type" } */
+  ckd_add (&d, (int *) 0, 1);	/* { dg-error "does not have integral type" } */
+  ckd_sub (&d, (int *) 0, 1);	/* { dg-error "does not have integral type" } */
+  ckd_mul (&d, (int *) 0, 1);	/* { dg-error "does not have integral type" } */
+  ckd_add (&d, 1, (int *) 0);	/* { dg-error "does not have integral type" } */
+  ckd_sub (&d, 1, (int *) 0);	/* { dg-error "does not have integral type" } */
+  ckd_mul (&d, 1, (int *) 0);	/* { dg-error "does not have integral type" } */
+}