From: Jakub Jelinek Date: Sat, 12 Aug 2023 07:42:58 +0000 (+0200) Subject: Add stdckdint.h header for C23 X-Git-Tag: basepoints/gcc-15~6961 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8441841a1b985d68245954af1ff023db121b0635;p=thirdparty%2Fgcc.git Add stdckdint.h header for C23 This patch adds header, which defines ckd_{add,sub,mul} using __builtin_{add,sub,mul}_overflow. As requested, it doesn't pedantically diagnose things which work just fine, e.g. inputs with plain char, bool, bit-precise integer or enumerated types and result pointer to plain char or bit-precise integer. The header will #include_next so that C library can supply its part if the header implementation in the future needs to be split between parts under the control of the compiler and parts under the control of C library. 2023-08-12 Jakub Jelinek * 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. --- diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 2429128cbf2f..a17191435e35 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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@ diff --git a/gcc/ginclude/stdckdint.h b/gcc/ginclude/stdckdint.h new file mode 100644 index 000000000000..bcb1a25c900c --- /dev/null +++ b/gcc/ginclude/stdckdint.h @@ -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 +. */ + +/* ISO C23: 7.20 Checked Integer Arithmetic . */ + +#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 () +# include_next +#endif + +#endif /* stdckdint.h */ diff --git a/gcc/testsuite/gcc.dg/stdckdint-1.c b/gcc/testsuite/gcc.dg/stdckdint-1.c new file mode 100644 index 000000000000..1525a35c51e8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/stdckdint-1.c @@ -0,0 +1,61 @@ +/* Test C23 Checked Integer Arithmetic macros in . */ +/* { dg-do run } */ +/* { dg-options "-std=c2x" } */ + +#include + +#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 (); +} diff --git a/gcc/testsuite/gcc.dg/stdckdint-2.c b/gcc/testsuite/gcc.dg/stdckdint-2.c new file mode 100644 index 000000000000..f83e3d7123de --- /dev/null +++ b/gcc/testsuite/gcc.dg/stdckdint-2.c @@ -0,0 +1,95 @@ +/* Test C23 Checked Integer Arithmetic macros in . */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + +#include + +int +main () +{ + char a; + bool b; + enum E { E1, E2 } c = E1; + int d; + int *e; + float f; + double g; + long double h; + const int v = 42; + volatile const short w = 5; + 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" } */ + ckd_add (&v, 1, 1); /* { dg-error "has pointer to 'const' type" } */ + ckd_sub (&v, 1, 1); /* { dg-error "has pointer to 'const' type" } */ + ckd_mul (&v, 1, 1); /* { dg-error "has pointer to 'const' type" } */ + ckd_add (&w, 1, 1); /* { dg-error "has pointer to 'const' type" } */ + ckd_sub (&w, 1, 1); /* { dg-error "has pointer to 'const' type" } */ + ckd_mul (&w, 1, 1); /* { dg-error "has pointer to 'const' type" } */ +}