This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] support: Add TEST_COMPARE macro


Florian Weimer wrote:
comparisons between actual and expected values often have differing types.  Concrete types vary between architectures, and not just their sizes (e.g., 32-bit architectures use longs where 64-bit architectures use int).

Yes, but I'm still not seeing the motivation for doing this via a run-time test rather than a compile-time test. Can you show an example or two of problems that the signedness part of this macro will fix?

Also, why can't we rely on -Wsign-compare to warn about these problems?

As for what I have in mind for a compile-time test, please see the attached code. This also checks for floating-point types, and it avoids a false alarm in some cases when a narrower-than-int unsigned type is promoted (that's what the "+ (a)" and "+ (b)" are for). Finally, it suppresses -Wtype-limits since those GCC warnings are counterproductive in this kind of code.
#pragma GCC diagnostic ignored "-Wtype-limits"

#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
#define TYPE_IS_SIGNED(t) ((t) -1 < (t) 0)
#define TYPE_FITS_IN_LONG_LONG(t) \
  (sizeof (t) <= sizeof (long long) && TYPE_IS_INTEGER (t))

#define TEST_COMPARE(a, b)						\
  ({                                                                    \
    typedef __typeof__ (a) __ta;					\
    typedef __typeof__ (b) __tb;					\
    __ta __va = (a);							\
    __tb __vb = (b);							\
									\
    /* Prevent accidental use with types that do not fit in long long.  */ \
    _Static_assert (TYPE_FITS_IN_LONG_LONG (__ta),			\
                    "left value fits into long long");                  \
    _Static_assert (TYPE_FITS_IN_LONG_LONG (__tb),			\
                    "right value fits into long long");                 \
									\
    /* Prevent accidental use with types that might not be compared
       numerically.  The comparison is safe if the signedness of A and
       B agree or if the unsigned value is narrower than the promoted
       signed value.  */						\
    _Static_assert							\
     ((TYPE_IS_SIGNED (__ta) == TYPE_IS_SIGNED (__tb)			\
       || (TYPE_IS_SIGNED (__ta) && sizeof (__tb) < sizeof + (a))	\
       || (TYPE_IS_SIGNED (__tb) && sizeof (__ta) < sizeof + (b))),	\
      "TEST_COMPARE args might not compare numerically");		\
									\
    /* Report an error at run-time if A does not equal B.  */		\
    if (__va != __vb)							\
      support_test_compare_failure                                      \
        (__FILE__, __LINE__,                                            \
         #a, __va, __va < 0,						\
         #b, __vb, __vb < 0);						\
  })

void support_test_compare_failure (const char *file, int line,
                                   const char *left_expr,
                                   long long left_value,
                                   _Bool left_negative,
                                   const char *right_expr,
                                   long long right_value,
                                   _Bool right_negative);
int main (void)
{
  TEST_COMPARE (0, 1);
  TEST_COMPARE (0u, 1);
  TEST_COMPARE ((unsigned short) 0, 1);
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]