mailing list of musl libc
 help / color / mirror / code / Atom feed
* type verification for number macros
@ 2014-11-25 14:45 Jens Gustedt
  2014-11-26 13:06 ` Jens Gustedt
  0 siblings, 1 reply; 2+ messages in thread
From: Jens Gustedt @ 2014-11-25 14:45 UTC (permalink / raw)
  To: musl


[-- Attachment #1.1: Type: text/plain, Size: 1325 bytes --]

Hello,

after a recent discussion about DR 456, I noticed that the types and
properties of the numerical macros that the C standard requires are
not always completely trivial. Basically there are three distinct
cases:

  (1) the standard requires that the type of an integer constant is the
      promoted type

  (2) the standard requires that the type of an integer constant is the
      exact type

  (3) the standard requires that the type of a floating point constant
      is the exact type *and* that it must be suitable to initialize a
      static varialble.

Joint is a program that checks all of these. This exposes 3 different
bugs for musl:

  - [U]INTxx_C(x) macros don't have the exact type
  - WINT_MIN must have type wint_t, that is unsigned for musl
  - CMPLX(x, y) and friends must be usable for initialization

The later makes the compilation of the program fail with musl :(

In a follow up I will send 4 patches that address issues with this
types of macros.

Jens


-- 
:: INRIA Nancy Grand Est ::: AlGorille ::: ICube/ICPS :::
:: ::::::::::::::: office Strasbourg : +33 368854536   ::
:: :::::::::::::::::::::: gsm France : +33 651400183   ::
:: ::::::::::::::: gsm international : +49 15737185122 ::
:: http://icube-icps.unistra.fr/index.php/Jens_Gustedt ::



[-- Attachment #1.2: test_number_macros.c --]
[-- Type: text/x-csrc, Size: 22788 bytes --]

/**
 ** copyright © 2014, Jens Gustedt
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without
 ** modification, are permitted provided that the following conditions
 ** are met:
 **
 ** 1. Redistributions of source code must retain the above copyright
 ** notice, this list of conditions and the following disclaimer.
 **
 ** 2. Redistributions in binary form must reproduce the above
 ** copyright notice, this list of conditions and the following
 ** disclaimer in the documentation and/or other materials provided
 ** with the distribution.
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 ** CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
 ** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 ** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 ** ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 ** TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 ** THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 ** SUCH DAMAGE.
 **/

/**
 ** @file
 ** @brief Test C standard numerical macros for their size and type
 **
 ** The C standard imposes types for a lot of numerical values, such
 ** as minimum and maximum values of certain types.
 **
 ** Before C11, only the size and sometimes the signedness of a
 ** integer or floating point literal have been observable. With C11
 ** the type itself becomes observable through _Generic
 ** expressions. Portability requires then that the types of the
 ** macros are exactly what the standard defines.
 **
 ** There are basically three forms of restrictions by the
 ** standard.
 **
 ** The first is an exact definition of integer constants, e.g
 ** <code>UINT16_C(1)</code> must be of type
 ** <code>uint_least16_t</code>. These must all be suitable for
 ** evaluation in the preprocessor, so we also test them for that.
 **
 ** The second form is a prescription of the promoted type. These are
 ** e.g the minimum and maximum values of signed integer types. So the
 ** promotion rules apply for them: for narrow types the resulting
 ** type for the constant is int (most of the times) for wide types it
 ** that same wide types. E.g <code>SHORT_MAX</code> is usually of
 ** type <code>int</code>, <code>LONG_MAX</code> is <code>long</code>.
 ** They also must be suitable for evaluation in the preprocessor, so
 ** we also test them for that.
 **
 ** The third is an exact definition of floating point constants, e.g
 ** <code>_Complex_I</code> must be of type <code>_Complex
 ** double</code>. These can't be used in the preprocessor, so we
 ** don't test that, but must be suitable in initializers of static
 ** variables. So we test for that.
 **
 ** This program implements tests on two different levels. The first
 ** should work with any C99 compatible compiler. It checks that the
 ** sizes are correct, for signedness when that is possible, that is
 ** when the type doesn't promote, and if the constant is suitable for
 ** initialization of static objects.
 **
 ** When compiled with a C11 compiler and additional check for the
 ** type is made. The program prints all findings and a summary.
 **
 ** @return is @c EXIT_SUCCESS if all sizes and types were
 ** correct. Otherwise @c EXIT_FAILURE is returned.
 **/


#ifndef __STDC_NO_COMPLEX__
# include <complex.h>
#endif
#include <float.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>

/* some utilities to use with _Generic for type identification */

enum cls {
  c_def,
  c_b,
  c_c,
  c_hhi,
  c_hhu,
  c_hi,
  c_hu,
  c_i,
  c_u,
  c_li,
  c_lu,
  c_lli,
  c_llu,
  c_f,
  c_lf,
  c_llf,
  c_cf,
  c_clf,
  c_cllf,
};

#ifndef __STDC_NO_COMPLEX__
# define COMPLEX_TYPES _Complex float: c_cf, _Complex double: c_clf, _Complex long double: c_cllf
#else
# define COMPLEX_TYPES
#endif

#define TYPEID(X)                                                       \
_Generic((X),                                                           \
         default: c_def,                                                \
         _Bool: c_b,                                                    \
         char: c_c, signed char: c_hhi, unsigned char: c_hhu,           \
         signed short: c_hi, unsigned short: c_hu,                      \
         signed: c_i, unsigned: c_u,                                    \
         signed long: c_li, unsigned long: c_lu,                        \
         signed long long: c_lli, unsigned long long: c_llu,            \
         float: c_f, double: c_lf, long double: c_llf,                  \
         COMPLEX_TYPES)

#define TYPENAME(X)                             \
(char const*[]){                                \
    [c_def]  = "<unknown type>",                \
    [c_b] = "_Bool",                            \
    [c_c] = "char",                             \
    [c_hhi] = "signed char",                    \
    [c_hhu] = "unsigned char",                  \
    [c_hi] = "signed short int",                \
    [c_hu] = "unsigned short int",              \
    [c_i] = "signed int",                       \
    [c_u] = "unsigned int",                     \
    [c_li] = "signed long int",                 \
    [c_lu] = "unsigned long int",               \
    [c_lli] = "signed long long int",           \
    [c_llu] = "unsigned long long int",         \
    [c_f] = "float",                            \
    [c_lf] = "double",                          \
    [c_llf] = "long double",                    \
    [c_cf] = "_Complex float",                  \
    [c_clf] = "_Complex double",                \
    [c_cllf] = "_Complex long double",          \
      }[(X)]

/* Counters to track the number of bugs. */

static size_t size_right;
static size_t size_wrong;
static size_t sign_right;
static size_t sign_wrong;
static size_t type_right;
static size_t type_wrong;
static size_t missing;

#define CHECK_EXACT_SIZE(T, X, ST, SX)                  \
do {                                                    \
  if (sizeof(X) == sizeof(T)) {                         \
    ++size_right;                                       \
    printf("%20s, %20s:\tright size\n", SX, ST);        \
  } else {                                              \
    ++size_wrong;                                       \
    printf("%20s, %20s:\twrong size, %s, %zu != %zu\n", \
           SX, ST, #X, sizeof(X), sizeof(T));           \
  }                                                     \
 } while(0)

#define CHECK_EXACT_TYPE(T, X, ST, SX)                                  \
do {                                                                    \
  int type_x = TYPEID(X);                                               \
  int type_unpromoted = TYPEID((T)0);                                   \
  if (_Generic((X), T: 1, default: 0)) {                                \
    ++type_right;                                                       \
    printf("%20s, %20s:\tright type \"%s\"\n", SX, ST,                  \
           TYPENAME(type_x));                                           \
  } else {                                                              \
    ++type_wrong;                                                       \
    printf("%20s, %20s:\twrong type \"%s\", should be \"%s\"\n",        \
           SX, ST, TYPENAME(type_x), TYPENAME(type_unpromoted));        \
  }                                                                     \
 } while(0)

#define CHECK_SIGN(T, X, ST, SX)                                        \
do {                                                                    \
  _Bool ispromoted = (sizeof(T) != sizeof(+(T)0));                      \
  if (!ispromoted) {                                                    \
    _Bool issinged_T = (0 > (T)-1);                                     \
    _Bool issinged_x = (0 > (1 ? -1 : (X)));                            \
    if (issinged_x == issinged_T) {                                     \
      ++sign_right;                                                     \
    } else {                                                            \
      ++sign_wrong;                                                     \
      printf("%20s, %20s:\twrong sign, %ssigned instead of %ssigned\n", \
             SX, ST,                                                    \
             (issinged_x ? "" : "un"),                                  \
             (issinged_T ? "" : "un"));                                 \
    }                                                                   \
  }                                                                     \
 } while(0)

#if __STDC_VERSION__ > 201100L
# define CHECK_EXACT(T, X)                      \
  do {                                          \
    CHECK_EXACT_SIZE(T, X, #T, #X);             \
    CHECK_SIGN(T, X, #T, #X);                   \
    CHECK_EXACT_TYPE(T, X, #T, #X);             \
  } while (0)
#else
# define CHECK_EXACT(T, X)                      \
  do {                                          \
    CHECK_EXACT_SIZE(T, X, #T, #X);             \
    CHECK_SIGN(T, X, #T, #X);                   \
  } while (0)
#endif

#define CHECK_CONSTANT(T, X, ST, SX)            \
do {                                            \
  static T volatile const obj = X;              \
  (void)obj;                                    \
 } while (0)

#if __STDC_VERSION__ > 201100L
# define CHECK_UNORDERED(T, X)                  \
  do {                                          \
    CHECK_CONSTANT(T, X, #T, #X);               \
    CHECK_EXACT_SIZE(T, X, #T, #X);             \
    CHECK_EXACT_TYPE(T, X, #T, #X);             \
  } while (0)
#else
# define CHECK_UNORDERED(T, X)                  \
  do {                                          \
    CHECK_CONSTANT(T, X, #T, #X);               \
    CHECK_EXACT_SIZE(T, X, #T, #X);             \
  } while (0)
#endif

#define CHECK_PROMOTED_SIZE(T, X, ST, SX)               \
do {                                                    \
  if (sizeof(X) == sizeof(+(T)0)) {                     \
    ++size_right;                                       \
    printf("%20s, %20s:\tright size\n", SX, ST);        \
  } else {                                              \
    ++size_wrong;                                       \
    printf("%20s, %20s:\twrong size, %s, %zu != %zu\n", \
           SX, ST, #X, sizeof(X), sizeof(+(T)0));       \
  }                                                     \
 } while(0)

#define CHECK_PROMOTED_TYPE(T, X, ST, SX)                               \
do {                                                                    \
  bool unpromoted = _Generic(+(T)0, T: true, default: false);           \
  int type_x = TYPEID(X);                                               \
  int type_promoted = TYPEID(+(T)0);                                    \
  int type_unpromoted = TYPEID((T)0);                                   \
  bool correct = (unpromoted                                            \
                  /* an unpromoted type must match */                   \
                  ? _Generic((X), T: 1, default: 0)                     \
                  /* an promoted type mustn't */                        \
                  : type_x == type_promoted);                           \
  if (correct) {                                                        \
    ++type_right;                                                       \
    printf("%20s, %20s:\tright %spromoted type \"%s\"\n", SX, ST,       \
           (unpromoted ? "un" : ""),                                    \
           TYPENAME(type_promoted));                                    \
  } else {                                                              \
    ++type_wrong;                                                       \
    printf("%20s, %20s:\twrong type, has type \"%s\" should be %spromoted type \"%s\"\n", \
           SX, ST, TYPENAME(type_x),                                    \
           (unpromoted ? "un" : ""),                                    \
           (unpromoted                                                  \
            ? TYPENAME(type_unpromoted)                                 \
            : TYPENAME(type_promoted)));                                \
  }                                                                     \
 } while(0)

#if __STDC_VERSION__ > 201100L
# define CHECK_PROMOTED(T, X)                   \
  do {                                          \
  CHECK_PROMOTED_SIZE(T, X, #T, #X);            \
  CHECK_SIGN(T, X, #T, #X);                     \
  CHECK_PROMOTED_TYPE(T, X, #T, #X);            \
  } while (0)
#else
# define CHECK_PROMOTED(T, X)                   \
  do {                                          \
  CHECK_PROMOTED_SIZE(T, X, #T, #X);            \
  CHECK_SIGN(T, X, #T, #X);                     \
  } while (0)
#endif

int main(void) {

  /* types that must be unsigned */

#if false+1
  CHECK_PROMOTED(bool, false);
#endif
#if true+1
  CHECK_PROMOTED(bool, true);
#endif

#if UINT8_C(1) > 0
  CHECK_EXACT(uint_least8_t, UINT8_C(1));
#endif
#if UINT16_C(1) > 0
  CHECK_EXACT(uint_least16_t, UINT16_C(1));
#endif
#if UINT32_C(1) > 0
  CHECK_EXACT(uint_least32_t, UINT32_C(1));
#endif
#if UINT64_C(1) > 0
  CHECK_EXACT(uint_least64_t, UINT64_C(1));
#endif

#if UCHAR_MAX > 0
  CHECK_PROMOTED(unsigned char, UCHAR_MAX);
#endif
#if USHRT_MAX > 0
  CHECK_PROMOTED(unsigned short, USHRT_MAX);
#endif
#if UINT_MAX > 0
  CHECK_EXACT(unsigned int, UINT_MAX);
#endif
#if ULONG_MAX > 0
  CHECK_EXACT(unsigned long, ULONG_MAX);
#endif
#if ULLONG_MAX > 0
  CHECK_EXACT(unsigned long long, ULLONG_MAX);
#endif


#if UINT8_MAX > 0
  CHECK_PROMOTED(uint8_t, UINT8_MAX);
#endif
#if UINT16_MAX > 0
  CHECK_PROMOTED(uint16_t, UINT16_MAX);
#endif
#if UINT32_MAX > 0
  CHECK_PROMOTED(uint32_t, UINT32_MAX);
#endif
#if UINT64_MAX > 0
  CHECK_PROMOTED(uint64_t, UINT64_MAX);
#endif
#if UINT_LEAST8_MAX > 0
  CHECK_PROMOTED(uint_least8_t, UINT_LEAST8_MAX);
#endif
#if UINT_LEAST16_MAX > 0
  CHECK_PROMOTED(uint_least16_t, UINT_LEAST16_MAX);
#endif
#if UINT_LEAST32_MAX > 0
  CHECK_PROMOTED(uint_least32_t, UINT_LEAST32_MAX);
#endif
#if UINT_LEAST64_MAX > 0
  CHECK_PROMOTED(uint_least64_t, UINT_LEAST64_MAX);
#endif
#if UINT_FAST8_MAX > 0
  CHECK_PROMOTED(uint_fast8_t, UINT_FAST8_MAX);
#endif
#if UINT_FAST16_MAX > 0
  CHECK_PROMOTED(uint_fast16_t, UINT_FAST16_MAX);
#endif
#if UINT_FAST32_MAX > 0
  CHECK_PROMOTED(uint_fast32_t, UINT_FAST32_MAX);
#endif
#if UINT_FAST64_MAX > 0
  CHECK_PROMOTED(uint_fast64_t, UINT_FAST64_MAX);
#endif

#if UINTMAX_MAX > 0
  CHECK_EXACT(uintmax_t, UINTMAX_MAX);
#endif
#if UINPTR_MAX > 0
  CHECK_PROMOTED(uintptr_t, UINTPTR_MAX);
#endif
#if SIZE_MAX > 0
  CHECK_PROMOTED(size_t, SIZE_MAX);
#endif

  /* types that that maybe signed */

#if INT8_C(1) > 0
  CHECK_EXACT(int_least8_t, INT8_C(1));
#endif
#if INT16_C(1) > 0
  CHECK_EXACT(int_least16_t, INT16_C(1));
#endif
#if INT32_C(1) > 0
  CHECK_EXACT(int_least32_t, INT32_C(1));
#endif
#if INT64_C(1) > 0
  CHECK_EXACT(int_least64_t, INT64_C(1));
#endif

#if CHAR_MAX > 0
  CHECK_PROMOTED(char, CHAR_MAX);
#endif
#if SCHAR_MAX > 0
  CHECK_PROMOTED(signed char, SCHAR_MAX);
#endif
#if SHRT_MAX > 0
  CHECK_PROMOTED(signed short, SHRT_MAX);
#endif
#if INT_MAX > 0
  CHECK_EXACT(signed int, INT_MAX);
#endif
#if LONG_MAX > 0
  CHECK_EXACT(signed long, LONG_MAX);
#endif
#if LLONG_MAX > 0
  CHECK_EXACT(signed long long, LLONG_MAX);
#endif

#if INT8_MAX > 0
  CHECK_PROMOTED(int8_t, INT8_MAX);
#endif
#if INT16_MAX > 0
  CHECK_PROMOTED(int16_t, INT16_MAX);
#endif
#if INT32_MAX > 0
  CHECK_PROMOTED(int32_t, INT32_MAX);
#endif
#if INT64_MAX > 0
  CHECK_PROMOTED(int64_t, INT64_MAX);
#endif
#if INT_LEAST8_MAX > 0
  CHECK_PROMOTED(int_least8_t, INT_LEAST8_MAX);
#endif
#if INT_LEAST16_MAX > 0
  CHECK_PROMOTED(int_least16_t, INT_LEAST16_MAX);
#endif
#if INT_LEAST32_MAX > 0
  CHECK_PROMOTED(int_least32_t, INT_LEAST32_MAX);
#endif
#if INT_LEAST64_MAX > 0
  CHECK_PROMOTED(int_least64_t, INT_LEAST64_MAX);
#endif
#if INT_FAST8_MAX > 0
  CHECK_PROMOTED(int_fast8_t, INT_FAST8_MAX);
#endif
#if INT_FAST16_MAX > 0
  CHECK_PROMOTED(int_fast16_t, INT_FAST16_MAX);
#endif
#if INT_FAST32_MAX > 0
  CHECK_PROMOTED(int_fast32_t, INT_FAST32_MAX);
#endif
#if INT_FAST64_MAX > 0
  CHECK_PROMOTED(int_fast64_t, INT_FAST64_MAX);
#endif

#if INTMAX_MAX > 0
  CHECK_PROMOTED(intmax_t, INTMAX_MAX);
#endif
#if UINPTR_MAX > 0
  CHECK_PROMOTED(intptr_t, INTPTR_MAX);
#endif
#if PTRDIFF_MAX > 0
  CHECK_PROMOTED(ptrdiff_t, PTRDIFF_MAX);
#endif
#if SIG_ATOMIC_MAX > 0
  CHECK_PROMOTED(sig_atomic_t, SIG_ATOMIC_MAX);
#endif
#if WCHAR_MAX > 0
  CHECK_PROMOTED(wchar_t, WCHAR_MAX);
#endif
#if WINT_MAX > 0
  /* wint_t should not promote */
  CHECK_EXACT(wint_t, WINT_MAX);
#endif

#if CHAR_MIN < 1
  CHECK_PROMOTED(char, CHAR_MIN);
#endif
#if SCHAR_MIN < 1
  CHECK_PROMOTED(signed char, SCHAR_MIN);
#endif
#if SHRT_MIN < 1
  CHECK_PROMOTED(signed short, SHRT_MIN);
#endif
#if INT_MIN < 1
  CHECK_EXACT(signed int, INT_MIN);
#endif
#if LONG_MIN < 1
  CHECK_EXACT(signed long, LONG_MIN);
#endif
#if LLONG_MIN < 1
  CHECK_EXACT(signed long long, LLONG_MIN);
#endif

#if INT8_MIN < 1
  CHECK_PROMOTED(int8_t, INT8_MIN);
#endif
#if INT16_MIN < 1
  CHECK_PROMOTED(int16_t, INT16_MIN);
#endif
#if INT32_MIN < 1
  CHECK_PROMOTED(int32_t, INT32_MIN);
#endif
#if INT64_MIN < 1
  CHECK_PROMOTED(int64_t, INT64_MIN);
#endif
#if INT_LEAST8_MIN < 1
  CHECK_PROMOTED(int_least8_t, INT_LEAST8_MIN);
#endif
#if INT_LEAST16_MIN < 1
  CHECK_PROMOTED(int_least16_t, INT_LEAST16_MIN);
#endif
#if INT_LEAST32_MIN < 1
  CHECK_PROMOTED(int_least32_t, INT_LEAST32_MIN);
#endif
#if INT_LEAST64_MIN < 1
  CHECK_PROMOTED(int_least64_t, INT_LEAST64_MIN);
#endif
#if INT_FAST8_MIN < 1
  CHECK_PROMOTED(int_fast8_t, INT_FAST8_MIN);
#endif
#if INT_FAST16_MIN < 1
  CHECK_PROMOTED(int_fast16_t, INT_FAST16_MIN);
#endif
#if INT_FAST32_MIN < 1
  CHECK_PROMOTED(int_fast32_t, INT_FAST32_MIN);
#endif
#if INT_FAST64_MIN < 1
  CHECK_PROMOTED(int_fast64_t, INT_FAST64_MIN);
#endif

#if INTMAX_MIN < 1
  CHECK_PROMOTED(intmax_t, INTMAX_MIN);
#endif
#if UINPTR_MIN < 1
  CHECK_PROMOTED(intptr_t, INTPTR_MIN);
#endif
#if PTRDIFF_MIN < 1
  CHECK_PROMOTED(ptrdiff_t, PTRDIFF_MIN);
#endif
#if SIG_ATOMIC_MIN < 1
  CHECK_PROMOTED(sig_atomic_t, SIG_ATOMIC_MIN);
#endif
#if WCHAR_MIN < 1
  CHECK_PROMOTED(wchar_t, WCHAR_MIN);
#endif
#if EOF < 1 || EOF > 0
  CHECK_EXACT(int, EOF);
#endif
#if WINT_MIN < 1
  /* wint_t should not promote */
  CHECK_EXACT(wint_t, WINT_MIN);
#endif
#if WEOF < 1 || WEOF > 0
  /* wint_t should not promote */
  CHECK_EXACT(wint_t, WEOF);
#endif

  CHECK_UNORDERED(float, FLT_MAX);
  CHECK_UNORDERED(float, FLT_MIN);
  CHECK_UNORDERED(float, FLT_TRUE_MIN);
  CHECK_UNORDERED(float, FLT_EPSILON);
  CHECK_UNORDERED(float, HUGE_VALF);
  CHECK_UNORDERED(float, INFINITY);
#ifdef NAN
  CHECK_UNORDERED(float, NAN);
#endif

  CHECK_UNORDERED(double, DBL_MAX);
  CHECK_UNORDERED(double, DBL_MIN);
  CHECK_UNORDERED(double, DBL_TRUE_MIN);
  CHECK_UNORDERED(double, DBL_EPSILON);
  CHECK_UNORDERED(double, HUGE_VAL);

  CHECK_UNORDERED(long double, LDBL_MAX);
  CHECK_UNORDERED(long double, LDBL_MIN);
  CHECK_UNORDERED(long double, LDBL_TRUE_MIN);
  CHECK_UNORDERED(long double, LDBL_EPSILON);
  CHECK_UNORDERED(long double, HUGE_VALL);

#ifndef __STDC_NO_COMPLEX__
# ifdef imaginary
  CHECK_UNORDERED(_Imaginary float, I);
# else
  CHECK_UNORDERED(_Complex float, I);
# endif
  /* Notwithstanding the provisions of 7.1.3, a program may undefine
     and perhaps then redefine the macros complex, imaginary, and
     I. */
# undef imaginary
# undef complex
# undef I
  /* Try to invent the most stupid choices that an application could
     ever make. */
# define imaginary long double
# define complex long double
# define I 1.4L
  /* Now all other macros should still work. */
# ifdef _Imaginary_I
  CHECK_UNORDERED(_Imaginary float, _Imaginary_I);
# endif
  CHECK_UNORDERED(_Complex float, _Complex_I);
  CHECK_UNORDERED(_Complex float, 1.0F + _Complex_I);
  CHECK_UNORDERED(_Complex double, 1.0 + _Complex_I);
  CHECK_UNORDERED(_Complex long double, 1.0L + _Complex_I);
# ifdef CMPLXF
  CHECK_UNORDERED(_Complex float, CMPLXF(1.0L, 1.0L));
# else
  ++missing;
  puts("macro CMPLXF is missing");
# endif
# ifdef CMPLX
  CHECK_UNORDERED(_Complex double, CMPLX(1.0L, 1.0L));
# else
  ++missing;
  puts("macro CMPLX is missing");
# endif
# ifdef CMPLXL
  CHECK_UNORDERED(_Complex long double, CMPLXL(1.0F, 1.0F));
# else
  ++missing;
  puts("macro CMPLXL is missing");
# endif
#endif

  printf("\nSummary:\t%zu/%zu sizes wrong\n", size_wrong, size_wrong+size_right);
  printf("\t\t%zu/%zu signedness wrong\n", sign_wrong, sign_wrong+sign_right);
#if __STDC_VERSION__ > 201100L
  printf("\t\t%zu/%zu types wrong\n", type_wrong, type_wrong+type_right);
#endif
  printf("\t\t%zu macros are missing\n", missing);

  puts("\ncheck a set of literals that all should work, independent of the C library");
  CHECK_EXACT(int, 'a');
  CHECK_EXACT(wchar_t, L'a');
#if __STDC_VERSION__ > 201100L
  CHECK_EXACT(uint_least16_t, u'a');
  CHECK_EXACT(uint_least32_t, U'A');
#endif
#ifdef __SIZEOF_INT128__
  CHECK_EXACT(__int128, (__int128)0);
#endif
  CHECK_UNORDERED(float, 0.0F);
  CHECK_UNORDERED(double, 0.0);
  CHECK_UNORDERED(long double, 0.0L);

  int ret = type_wrong + size_wrong + sign_wrong + missing;

  puts("\ncheck a set of mismatches that should error, independent of the C library");
  CHECK_UNORDERED(double, 0LL);
  CHECK_PROMOTED(double, 0LL);
#ifdef __SIZEOF_INT128__
  CHECK_EXACT(__int128, 0LL);
#endif

  return ret ? EXIT_FAILURE : EXIT_SUCCESS;
}

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: type verification for number macros
  2014-11-25 14:45 type verification for number macros Jens Gustedt
@ 2014-11-26 13:06 ` Jens Gustedt
  0 siblings, 0 replies; 2+ messages in thread
From: Jens Gustedt @ 2014-11-26 13:06 UTC (permalink / raw)
  To: musl


[-- Attachment #1.1: Type: text/plain, Size: 1706 bytes --]

Hello,
 here is a new version of the test that also takes the correctness of
the CMPLX macros for special values into consideration.

I will follow up in the other thread with a new version of patch 1/4
that takes nsz' remarks into account.

Am Dienstag, den 25.11.2014, 15:45 +0100 schrieb Jens Gustedt:
> Hello,
> 
> after a recent discussion about DR 456, I noticed that the types and
> properties of the numerical macros that the C standard requires are
> not always completely trivial. Basically there are three distinct
> cases:
> 
>   (1) the standard requires that the type of an integer constant is the
>       promoted type
> 
>   (2) the standard requires that the type of an integer constant is the
>       exact type
> 
>   (3) the standard requires that the type of a floating point constant
>       is the exact type *and* that it must be suitable to initialize a
>       static varialble.
> 
> Joint is a program that checks all of these. This exposes 3 different
> bugs for musl:
> 
>   - [U]INTxx_C(x) macros don't have the exact type
>   - WINT_MIN must have type wint_t, that is unsigned for musl
>   - CMPLX(x, y) and friends must be usable for initialization
> 
> The later makes the compilation of the program fail with musl :(
> 
> In a follow up I will send 4 patches that address issues with this
> types of macros.
> 
> Jens
> 
> 


-- 
:: INRIA Nancy Grand Est ::: AlGorille ::: ICube/ICPS :::
:: ::::::::::::::: office Strasbourg : +33 368854536   ::
:: :::::::::::::::::::::: gsm France : +33 651400183   ::
:: ::::::::::::::: gsm international : +49 15737185122 ::
:: http://icube-icps.unistra.fr/index.php/Jens_Gustedt ::



[-- Attachment #1.2: test_number_macros.c --]
[-- Type: text/x-csrc, Size: 24036 bytes --]

/**
 ** copyright © 2014, Jens Gustedt
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without
 ** modification, are permitted provided that the following conditions
 ** are met:
 **
 ** 1. Redistributions of source code must retain the above copyright
 ** notice, this list of conditions and the following disclaimer.
 **
 ** 2. Redistributions in binary form must reproduce the above
 ** copyright notice, this list of conditions and the following
 ** disclaimer in the documentation and/or other materials provided
 ** with the distribution.
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 ** CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
 ** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 ** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 ** ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 ** TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 ** THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 ** SUCH DAMAGE.
 **/

/**
 ** @file
 ** @brief Test C standard numerical macros for their size and type
 **
 ** The C standard imposes types for a lot of numerical values, such
 ** as minimum and maximum values of certain types.
 **
 ** Before C11, only the size and sometimes the signedness of a
 ** integer or floating point literal have been observable. With C11
 ** the type itself becomes observable through _Generic
 ** expressions. Portability requires then that the types of the
 ** macros are exactly what the standard defines.
 **
 ** There are basically three forms of restrictions by the
 ** standard.
 **
 ** The first is an exact definition of integer constants, e.g
 ** <code>UINT16_C(1)</code> must be of type
 ** <code>uint_least16_t</code>. These must all be suitable for
 ** evaluation in the preprocessor, so we also test them for that.
 **
 ** The second form is a prescription of the promoted type. These are
 ** e.g the minimum and maximum values of signed integer types. So the
 ** promotion rules apply for them: for narrow types the resulting
 ** type for the constant is int (most of the times) for wide types it
 ** that same wide types. E.g <code>SHORT_MAX</code> is usually of
 ** type <code>int</code>, <code>LONG_MAX</code> is <code>long</code>.
 ** They also must be suitable for evaluation in the preprocessor, so
 ** we also test them for that.
 **
 ** The third is an exact definition of floating point constants, e.g
 ** <code>_Complex_I</code> must be of type <code>_Complex
 ** double</code>. These can't be used in the preprocessor, so we
 ** don't test that, but must be suitable in initializers of static
 ** variables. So we test for that.
 **
 ** This program implements tests on two different levels. The first
 ** should work with any C99 compatible compiler. It checks that the
 ** sizes are correct, for signedness when that is possible, that is
 ** when the type doesn't promote, and if the constant is suitable for
 ** initialization of static objects.
 **
 ** When compiled with a C11 compiler and additional check for the
 ** type is made. The program prints all findings and a summary.
 **
 ** @return is @c EXIT_SUCCESS if all sizes and types were
 ** correct. Otherwise @c EXIT_FAILURE is returned.
 **/


#ifndef __STDC_NO_COMPLEX__
# include <complex.h>
#endif
#include <float.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>

/* some utilities to use with _Generic for type identification */

enum cls {
  c_def,
  c_b,
  c_c,
  c_hhi,
  c_hhu,
  c_hi,
  c_hu,
  c_i,
  c_u,
  c_li,
  c_lu,
  c_lli,
  c_llu,
  c_f,
  c_lf,
  c_llf,
  c_cf,
  c_clf,
  c_cllf,
};

#ifndef __STDC_NO_COMPLEX__
# define COMPLEX_TYPES _Complex float: c_cf, _Complex double: c_clf, _Complex long double: c_cllf
#else
# define COMPLEX_TYPES
#endif

#define TYPEID(X)                                                       \
_Generic((X),                                                           \
         default: c_def,                                                \
         _Bool: c_b,                                                    \
         char: c_c, signed char: c_hhi, unsigned char: c_hhu,           \
         signed short: c_hi, unsigned short: c_hu,                      \
         signed: c_i, unsigned: c_u,                                    \
         signed long: c_li, unsigned long: c_lu,                        \
         signed long long: c_lli, unsigned long long: c_llu,            \
         float: c_f, double: c_lf, long double: c_llf,                  \
         COMPLEX_TYPES)

#define TYPENAME(X)                             \
(char const*[]){                                \
    [c_def]  = "<unknown type>",                \
    [c_b] = "_Bool",                            \
    [c_c] = "char",                             \
    [c_hhi] = "signed char",                    \
    [c_hhu] = "unsigned char",                  \
    [c_hi] = "signed short int",                \
    [c_hu] = "unsigned short int",              \
    [c_i] = "signed int",                       \
    [c_u] = "unsigned int",                     \
    [c_li] = "signed long int",                 \
    [c_lu] = "unsigned long int",               \
    [c_lli] = "signed long long int",           \
    [c_llu] = "unsigned long long int",         \
    [c_f] = "float",                            \
    [c_lf] = "double",                          \
    [c_llf] = "long double",                    \
    [c_cf] = "_Complex float",                  \
    [c_clf] = "_Complex double",                \
    [c_cllf] = "_Complex long double",          \
      }[(X)]

/* Counters to track the number of bugs. */

static size_t size_right;
static size_t size_wrong;
static size_t sign_right;
static size_t sign_wrong;
static size_t type_right;
static size_t type_wrong;
static size_t missing;
static size_t mismatch;

#define CHECK_EXACT_SIZE(T, X, ST, SX)                  \
do {                                                    \
  if (sizeof(X) == sizeof(T)) {                         \
    ++size_right;                                       \
    printf("%20s, %20s:\tright size\n", SX, ST);        \
  } else {                                              \
    ++size_wrong;                                       \
    printf("%20s, %20s:\twrong size, %s, %zu != %zu\n", \
           SX, ST, #X, sizeof(X), sizeof(T));           \
  }                                                     \
 } while(0)

#define CHECK_EXACT_TYPE(T, X, ST, SX)                                  \
do {                                                                    \
  int type_x = TYPEID(X);                                               \
  int type_unpromoted = TYPEID((T)0);                                   \
  if (_Generic((X), T: 1, default: 0)) {                                \
    ++type_right;                                                       \
    printf("%20s, %20s:\tright type \"%s\"\n", SX, ST,                  \
           TYPENAME(type_x));                                           \
  } else {                                                              \
    ++type_wrong;                                                       \
    printf("%20s, %20s:\twrong type \"%s\", should be \"%s\"\n",        \
           SX, ST, TYPENAME(type_x), TYPENAME(type_unpromoted));        \
  }                                                                     \
 } while(0)

#define CHECK_SIGN(T, X, ST, SX)                                        \
do {                                                                    \
  _Bool ispromoted = (sizeof(T) != sizeof(+(T)0));                      \
  if (!ispromoted) {                                                    \
    _Bool issinged_T = (0 > (T)-1);                                     \
    _Bool issinged_x = (0 > (1 ? -1 : (X)));                            \
    if (issinged_x == issinged_T) {                                     \
      ++sign_right;                                                     \
    } else {                                                            \
      ++sign_wrong;                                                     \
      printf("%20s, %20s:\twrong sign, %ssigned instead of %ssigned\n", \
             SX, ST,                                                    \
             (issinged_x ? "" : "un"),                                  \
             (issinged_T ? "" : "un"));                                 \
    }                                                                   \
  }                                                                     \
 } while(0)

#if !defined(SKIP_GENERIC) && __STDC_VERSION__ > 201000L
# define CHECK_EXACT(T, X)                      \
  do {                                          \
    CHECK_EXACT_SIZE(T, X, #T, #X);             \
    CHECK_SIGN(T, X, #T, #X);                   \
    CHECK_EXACT_TYPE(T, X, #T, #X);             \
  } while (0)
#else
# define CHECK_EXACT(T, X)                      \
  do {                                          \
    CHECK_EXACT_SIZE(T, X, #T, #X);             \
    CHECK_SIGN(T, X, #T, #X);                   \
  } while (0)
#endif

#define CHECK_CONSTANT(T, X, ST, SX)            \
do {                                            \
  static T volatile const obj = X;              \
  (void)obj;                                    \
 } while (0)

#if !defined(SKIP_GENERIC) && __STDC_VERSION__ > 201000L
# define CHECK_UNORDERED(T, X)                  \
  do {                                          \
    CHECK_CONSTANT(T, X, #T, #X);               \
    CHECK_EXACT_SIZE(T, X, #T, #X);             \
    CHECK_EXACT_TYPE(T, X, #T, #X);             \
  } while (0)
#else
# define CHECK_UNORDERED(T, X)                  \
  do {                                          \
    CHECK_CONSTANT(T, X, #T, #X);               \
    CHECK_EXACT_SIZE(T, X, #T, #X);             \
  } while (0)
#endif

#define CHECK_PROMOTED_SIZE(T, X, ST, SX)               \
do {                                                    \
  if (sizeof(X) == sizeof(+(T)0)) {                     \
    ++size_right;                                       \
    printf("%20s, %20s:\tright size\n", SX, ST);        \
  } else {                                              \
    ++size_wrong;                                       \
    printf("%20s, %20s:\twrong size, %s, %zu != %zu\n", \
           SX, ST, #X, sizeof(X), sizeof(+(T)0));       \
  }                                                     \
 } while(0)

#define CHECK_PROMOTED_TYPE(T, X, ST, SX)                               \
do {                                                                    \
  bool unpromoted = _Generic(+(T)0, T: true, default: false);           \
  int type_x = TYPEID(X);                                               \
  int type_promoted = TYPEID(+(T)0);                                    \
  int type_unpromoted = TYPEID((T)0);                                   \
  bool correct = (unpromoted                                            \
                  /* an unpromoted type must match */                   \
                  ? _Generic((X), T: 1, default: 0)                     \
                  /* an promoted type mustn't */                        \
                  : type_x == type_promoted);                           \
  if (correct) {                                                        \
    ++type_right;                                                       \
    printf("%20s, %20s:\tright %spromoted type \"%s\"\n", SX, ST,       \
           (unpromoted ? "un" : ""),                                    \
           TYPENAME(type_promoted));                                    \
  } else {                                                              \
    ++type_wrong;                                                       \
    printf("%20s, %20s:\twrong type, has type \"%s\" should be %spromoted type \"%s\"\n", \
           SX, ST, TYPENAME(type_x),                                    \
           (unpromoted ? "un" : ""),                                    \
           (unpromoted                                                  \
            ? TYPENAME(type_unpromoted)                                 \
            : TYPENAME(type_promoted)));                                \
  }                                                                     \
 } while(0)

#if !defined(SKIP_GENERIC) && __STDC_VERSION__ > 201000L
# define CHECK_PROMOTED(T, X)                   \
  do {                                          \
  CHECK_PROMOTED_SIZE(T, X, #T, #X);            \
  CHECK_SIGN(T, X, #T, #X);                     \
  CHECK_PROMOTED_TYPE(T, X, #T, #X);            \
  } while (0)
#else
# define CHECK_PROMOTED(T, X)                   \
  do {                                          \
  CHECK_PROMOTED_SIZE(T, X, #T, #X);            \
  CHECK_SIGN(T, X, #T, #X);                     \
  } while (0)
#endif


#define TCMPLX(X, Y) (+(union { _Complex double _c; double _p[2]; }){ ._p = { [0] = (X), [1] = (Y) }}._c)

#define CHECK_COMPLEX(X, Y)                                     \
do {                                                            \
  _Complex double A = CMPLX((X), (Y));                          \
  _Complex double B = TCMPLX((X), (Y));                         \
  if (A != B) {                                                 \
    ++mismatch;                                                 \
    printf("complex (%s, %s): (%g, %g) != (%g, %g)\n",          \
           #X, #Y, creal(A), cimag(A), creal(B), cimag(B));     \
  }                                                             \
 } while(0)


int main(void) {

  /* types that must be unsigned */

#if false+1
  CHECK_PROMOTED(bool, false);
#endif
#if true+1
  CHECK_PROMOTED(bool, true);
#endif

#if UINT8_C(1) > 0
  CHECK_EXACT(uint_least8_t, UINT8_C(1));
#endif
#if UINT16_C(1) > 0
  CHECK_EXACT(uint_least16_t, UINT16_C(1));
#endif
#if UINT32_C(1) > 0
  CHECK_EXACT(uint_least32_t, UINT32_C(1));
#endif
#if UINT64_C(1) > 0
  CHECK_EXACT(uint_least64_t, UINT64_C(1));
#endif

#if UCHAR_MAX > 0
  CHECK_PROMOTED(unsigned char, UCHAR_MAX);
#endif
#if USHRT_MAX > 0
  CHECK_PROMOTED(unsigned short, USHRT_MAX);
#endif
#if UINT_MAX > 0
  CHECK_EXACT(unsigned int, UINT_MAX);
#endif
#if ULONG_MAX > 0
  CHECK_EXACT(unsigned long, ULONG_MAX);
#endif
#if ULLONG_MAX > 0
  CHECK_EXACT(unsigned long long, ULLONG_MAX);
#endif


#if UINT8_MAX > 0
  CHECK_PROMOTED(uint8_t, UINT8_MAX);
#endif
#if UINT16_MAX > 0
  CHECK_PROMOTED(uint16_t, UINT16_MAX);
#endif
#if UINT32_MAX > 0
  CHECK_PROMOTED(uint32_t, UINT32_MAX);
#endif
#if UINT64_MAX > 0
  CHECK_PROMOTED(uint64_t, UINT64_MAX);
#endif
#if UINT_LEAST8_MAX > 0
  CHECK_PROMOTED(uint_least8_t, UINT_LEAST8_MAX);
#endif
#if UINT_LEAST16_MAX > 0
  CHECK_PROMOTED(uint_least16_t, UINT_LEAST16_MAX);
#endif
#if UINT_LEAST32_MAX > 0
  CHECK_PROMOTED(uint_least32_t, UINT_LEAST32_MAX);
#endif
#if UINT_LEAST64_MAX > 0
  CHECK_PROMOTED(uint_least64_t, UINT_LEAST64_MAX);
#endif
#if UINT_FAST8_MAX > 0
  CHECK_PROMOTED(uint_fast8_t, UINT_FAST8_MAX);
#endif
#if UINT_FAST16_MAX > 0
  CHECK_PROMOTED(uint_fast16_t, UINT_FAST16_MAX);
#endif
#if UINT_FAST32_MAX > 0
  CHECK_PROMOTED(uint_fast32_t, UINT_FAST32_MAX);
#endif
#if UINT_FAST64_MAX > 0
  CHECK_PROMOTED(uint_fast64_t, UINT_FAST64_MAX);
#endif

#if UINTMAX_MAX > 0
  CHECK_EXACT(uintmax_t, UINTMAX_MAX);
#endif
#if UINPTR_MAX > 0
  CHECK_PROMOTED(uintptr_t, UINTPTR_MAX);
#endif
#if SIZE_MAX > 0
  CHECK_PROMOTED(size_t, SIZE_MAX);
#endif

  /* types that that maybe signed */

#if INT8_C(1) > 0
  CHECK_EXACT(int_least8_t, INT8_C(1));
#endif
#if INT16_C(1) > 0
  CHECK_EXACT(int_least16_t, INT16_C(1));
#endif
#if INT32_C(1) > 0
  CHECK_EXACT(int_least32_t, INT32_C(1));
#endif
#if INT64_C(1) > 0
  CHECK_EXACT(int_least64_t, INT64_C(1));
#endif

#if CHAR_MAX > 0
  CHECK_PROMOTED(char, CHAR_MAX);
#endif
#if SCHAR_MAX > 0
  CHECK_PROMOTED(signed char, SCHAR_MAX);
#endif
#if SHRT_MAX > 0
  CHECK_PROMOTED(signed short, SHRT_MAX);
#endif
#if INT_MAX > 0
  CHECK_EXACT(signed int, INT_MAX);
#endif
#if LONG_MAX > 0
  CHECK_EXACT(signed long, LONG_MAX);
#endif
#if LLONG_MAX > 0
  CHECK_EXACT(signed long long, LLONG_MAX);
#endif

#if INT8_MAX > 0
  CHECK_PROMOTED(int8_t, INT8_MAX);
#endif
#if INT16_MAX > 0
  CHECK_PROMOTED(int16_t, INT16_MAX);
#endif
#if INT32_MAX > 0
  CHECK_PROMOTED(int32_t, INT32_MAX);
#endif
#if INT64_MAX > 0
  CHECK_PROMOTED(int64_t, INT64_MAX);
#endif
#if INT_LEAST8_MAX > 0
  CHECK_PROMOTED(int_least8_t, INT_LEAST8_MAX);
#endif
#if INT_LEAST16_MAX > 0
  CHECK_PROMOTED(int_least16_t, INT_LEAST16_MAX);
#endif
#if INT_LEAST32_MAX > 0
  CHECK_PROMOTED(int_least32_t, INT_LEAST32_MAX);
#endif
#if INT_LEAST64_MAX > 0
  CHECK_PROMOTED(int_least64_t, INT_LEAST64_MAX);
#endif
#if INT_FAST8_MAX > 0
  CHECK_PROMOTED(int_fast8_t, INT_FAST8_MAX);
#endif
#if INT_FAST16_MAX > 0
  CHECK_PROMOTED(int_fast16_t, INT_FAST16_MAX);
#endif
#if INT_FAST32_MAX > 0
  CHECK_PROMOTED(int_fast32_t, INT_FAST32_MAX);
#endif
#if INT_FAST64_MAX > 0
  CHECK_PROMOTED(int_fast64_t, INT_FAST64_MAX);
#endif

#if INTMAX_MAX > 0
  CHECK_PROMOTED(intmax_t, INTMAX_MAX);
#endif
#if UINPTR_MAX > 0
  CHECK_PROMOTED(intptr_t, INTPTR_MAX);
#endif
#if PTRDIFF_MAX > 0
  CHECK_PROMOTED(ptrdiff_t, PTRDIFF_MAX);
#endif
#if SIG_ATOMIC_MAX > 0
  CHECK_PROMOTED(sig_atomic_t, SIG_ATOMIC_MAX);
#endif
#if WCHAR_MAX > 0
  CHECK_PROMOTED(wchar_t, WCHAR_MAX);
#endif
#if WINT_MAX > 0
  /* wint_t should not promote */
  CHECK_EXACT(wint_t, WINT_MAX);
#endif

#if CHAR_MIN < 1
  CHECK_PROMOTED(char, CHAR_MIN);
#endif
#if SCHAR_MIN < 1
  CHECK_PROMOTED(signed char, SCHAR_MIN);
#endif
#if SHRT_MIN < 1
  CHECK_PROMOTED(signed short, SHRT_MIN);
#endif
#if INT_MIN < 1
  CHECK_EXACT(signed int, INT_MIN);
#endif
#if LONG_MIN < 1
  CHECK_EXACT(signed long, LONG_MIN);
#endif
#if LLONG_MIN < 1
  CHECK_EXACT(signed long long, LLONG_MIN);
#endif

#if INT8_MIN < 1
  CHECK_PROMOTED(int8_t, INT8_MIN);
#endif
#if INT16_MIN < 1
  CHECK_PROMOTED(int16_t, INT16_MIN);
#endif
#if INT32_MIN < 1
  CHECK_PROMOTED(int32_t, INT32_MIN);
#endif
#if INT64_MIN < 1
  CHECK_PROMOTED(int64_t, INT64_MIN);
#endif
#if INT_LEAST8_MIN < 1
  CHECK_PROMOTED(int_least8_t, INT_LEAST8_MIN);
#endif
#if INT_LEAST16_MIN < 1
  CHECK_PROMOTED(int_least16_t, INT_LEAST16_MIN);
#endif
#if INT_LEAST32_MIN < 1
  CHECK_PROMOTED(int_least32_t, INT_LEAST32_MIN);
#endif
#if INT_LEAST64_MIN < 1
  CHECK_PROMOTED(int_least64_t, INT_LEAST64_MIN);
#endif
#if INT_FAST8_MIN < 1
  CHECK_PROMOTED(int_fast8_t, INT_FAST8_MIN);
#endif
#if INT_FAST16_MIN < 1
  CHECK_PROMOTED(int_fast16_t, INT_FAST16_MIN);
#endif
#if INT_FAST32_MIN < 1
  CHECK_PROMOTED(int_fast32_t, INT_FAST32_MIN);
#endif
#if INT_FAST64_MIN < 1
  CHECK_PROMOTED(int_fast64_t, INT_FAST64_MIN);
#endif

#if INTMAX_MIN < 1
  CHECK_PROMOTED(intmax_t, INTMAX_MIN);
#endif
#if UINPTR_MIN < 1
  CHECK_PROMOTED(intptr_t, INTPTR_MIN);
#endif
#if PTRDIFF_MIN < 1
  CHECK_PROMOTED(ptrdiff_t, PTRDIFF_MIN);
#endif
#if SIG_ATOMIC_MIN < 1
  CHECK_PROMOTED(sig_atomic_t, SIG_ATOMIC_MIN);
#endif
#if WCHAR_MIN < 1
  CHECK_PROMOTED(wchar_t, WCHAR_MIN);
#endif
#if EOF < 1 || EOF > 0
  CHECK_EXACT(int, EOF);
#endif
#if WINT_MIN < 1
  /* wint_t should not promote */
  CHECK_EXACT(wint_t, WINT_MIN);
#endif
#if WEOF < 1 || WEOF > 0
  /* wint_t should not promote */
  CHECK_EXACT(wint_t, WEOF);
#endif

  CHECK_UNORDERED(float, FLT_MAX);
  CHECK_UNORDERED(float, FLT_MIN);
  CHECK_UNORDERED(float, FLT_TRUE_MIN);
  CHECK_UNORDERED(float, FLT_EPSILON);
  CHECK_UNORDERED(float, HUGE_VALF);
  CHECK_UNORDERED(float, INFINITY);
#ifdef NAN
  CHECK_UNORDERED(float, NAN);
#endif

  CHECK_UNORDERED(double, DBL_MAX);
  CHECK_UNORDERED(double, DBL_MIN);
  CHECK_UNORDERED(double, DBL_TRUE_MIN);
  CHECK_UNORDERED(double, DBL_EPSILON);
  CHECK_UNORDERED(double, HUGE_VAL);

  CHECK_UNORDERED(long double, LDBL_MAX);
  CHECK_UNORDERED(long double, LDBL_MIN);
  CHECK_UNORDERED(long double, LDBL_TRUE_MIN);
  CHECK_UNORDERED(long double, LDBL_EPSILON);
  CHECK_UNORDERED(long double, HUGE_VALL);

#ifndef __STDC_NO_COMPLEX__
# ifdef imaginary
  CHECK_UNORDERED(_Imaginary float, I);
# else
  CHECK_UNORDERED(_Complex float, I);
# endif
  /* Notwithstanding the provisions of 7.1.3, a program may undefine
     and perhaps then redefine the macros complex, imaginary, and
     I. */
# undef imaginary
# undef complex
# undef I
  /* Try to invent the most stupid choices that an application could
     ever make. */
# define imaginary long double
# define complex long double
# define I 1.4L
  /* Now all other macros should still work. */
# ifdef _Imaginary_I
  CHECK_UNORDERED(_Imaginary float, _Imaginary_I);
# endif
  CHECK_UNORDERED(_Complex float, _Complex_I);
  CHECK_UNORDERED(_Complex float, 1.0F + _Complex_I);
  CHECK_UNORDERED(_Complex double, 1.0 + _Complex_I);
  CHECK_UNORDERED(_Complex long double, 1.0L + _Complex_I);
# ifdef CMPLXF
  CHECK_UNORDERED(_Complex float, CMPLXF(1.0L, 1.0L));
# else
  ++missing;
  puts("macro CMPLXF is missing");
# endif
# ifdef CMPLX
  CHECK_UNORDERED(_Complex double, CMPLX(1.0L, 1.0L));
# else
  ++missing;
  puts("macro CMPLX is missing");
# endif
# ifdef CMPLXL
  CHECK_UNORDERED(_Complex long double, CMPLXL(1.0F, 1.0F));
# else
  ++missing;
  puts("macro CMPLXL is missing");
# endif
#endif

  puts("\ncheck a set of literals that all should work, independent of the C library");
  CHECK_EXACT(int, 'a');
  CHECK_EXACT(wchar_t, L'a');
#if __STDC_VERSION__ > 201000L
  CHECK_EXACT(uint_least16_t, u'a');
  CHECK_EXACT(uint_least32_t, U'A');
#endif
#ifdef __SIZEOF_INT128__
  CHECK_EXACT(__int128, (__int128)0);
#endif
  CHECK_UNORDERED(float, 0.0F);
  CHECK_UNORDERED(double, 0.0);
  CHECK_UNORDERED(long double, 0.0L);

#ifdef CMPLX
  CHECK_COMPLEX(1.0, 0.0);
  CHECK_COMPLEX(0.0, 1.0);
  CHECK_COMPLEX(INFINITY, 0.0);
  CHECK_COMPLEX(0.0, INFINITY);
#endif

  printf("\nSummary:\t%zu/%zu sizes wrong\n", size_wrong, size_wrong+size_right);
  printf("\t\t%zu/%zu signedness wrong\n", sign_wrong, sign_wrong+sign_right);
#if __STDC_VERSION__ > 201000L
  printf("\t\t%zu/%zu types wrong\n", type_wrong, type_wrong+type_right);
#endif
  printf("\t\t%zu macros are missing\n", missing);
  printf("\t\t%zu mismatches of complex values\n", mismatch);

  int ret = type_wrong + size_wrong + sign_wrong + missing + mismatch;

  puts("\ncheck a set of mismatches that should error, independent of the C library");
  CHECK_UNORDERED(double, 0LL);
  CHECK_PROMOTED(double, 0LL);
#ifdef __SIZEOF_INT128__
  CHECK_EXACT(__int128, 0LL);
#endif

#if defined(NAN) && defined(CMPLX)
  puts("\nThe two following involve NAN, so comparison should always be false");
  CHECK_COMPLEX(INFINITY, NAN);
  CHECK_COMPLEX(NAN, INFINITY);
#endif

  return ret ? EXIT_FAILURE : EXIT_SUCCESS;
}

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2014-11-26 13:06 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-25 14:45 type verification for number macros Jens Gustedt
2014-11-26 13:06 ` Jens Gustedt

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).