Add stdckdint.h header for C23
This patch adds <stdckdint.h> 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 <stdckdint.h> 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 <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.
This commit is contained in:
parent
9890f37701
commit
8441841a1b
4 changed files with 197 additions and 0 deletions
|
@ -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@
|
||||
|
|
40
gcc/ginclude/stdckdint.h
Normal file
40
gcc/ginclude/stdckdint.h
Normal file
|
@ -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 */
|
61
gcc/testsuite/gcc.dg/stdckdint-1.c
Normal file
61
gcc/testsuite/gcc.dg/stdckdint-1.c
Normal file
|
@ -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 ();
|
||||
}
|
95
gcc/testsuite/gcc.dg/stdckdint-2.c
Normal file
95
gcc/testsuite/gcc.dg/stdckdint-2.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
/* 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;
|
||||
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" } */
|
||||
}
|
Loading…
Add table
Reference in a new issue