Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Jul 2013 09:46:17 +0100
From:      David Chisnall <theraven@FreeBSD.org>
To:        Bruce Evans <brde@optusnet.com.au>
Cc:        Garrett Wollman <wollman@csail.mit.edu>, Tijl Coosemans <tijl@FreeBSD.org>, FreeBSD CURRENT <freebsd-current@FreeBSD.org>, freebsd-standards@FreeBSD.org, freebsd-toolchain@FreeBSD.org
Subject:   Re: CURRENT: CLANG 3.3 and -stad=c++11 and -stdlib=libc++: isnan()/isninf() oddity
Message-ID:  <FD768A6B-8B72-44A1-BC1C-14FF44CB4643@FreeBSD.org>
In-Reply-To: <20130711130043.R920@besplex.bde.org>
References:  <20130710155809.0f589c22@thor.walstatt.dyndns.org> <CD51F125-AE9E-4461-916D-CF583002B47D@FreeBSD.org> <20130710183315.725dfde0@thor.walstatt.dyndns.org> <C8C94CF2-7D5A-471B-AD63-8E961AED6274@FreeBSD.org> <20130710203200.5359fd18@thor.walstatt.dyndns.org> <51DDC04B.6040209@FreeBSD.org> <20957.49978.73666.392417@khavrinen.csail.mit.edu> <20130711130043.R920@besplex.bde.org>

index | next in thread | previous in thread | raw e-mail

[-- Attachment #1 --]
Hi Bruce,

You're joining in this discussion starting in the middle, so you probably missed the earlier explanation.

On 11 Jul 2013, at 05:21, Bruce Evans <brde@optusnet.com.au> wrote:

> I don't see how any conforming program can access the isnan() function
> directly.  It is just as protected as __isnan() would be.  (isnan)()
> gives the function (the function prototype uses this), but conforming
> programs can't do that since the function might not exist.  Maybe some
> non-conforming program like autoconfig reads <math.h> or libm.a and
> creates a bug for C++.

The cmath header defines a template function isnan that invokes the isnan macro, but then undefines the isnan macro.  This causes a problem because when someone does something along the lines of using namespace std then they end up with two functions called isnan and the compiler gets to pick the one to use.  Unfortunately, std::isnan() returns a bool, whereas isnan() returns an int.  

The C++ headers are not required to be conforming C code, because they are not C, and our math.h causes namespace pollution in C++ when included from <cmath>.

> The FreeBSD isnan() implementation would be broken by removing the
> isnan() function from libm.a or ifdefing it in <math.h>.  Changing the
> function to __isnan() would cause compatibility problems.  The function
> is intentionally named isnan() to reduce compatibility problems.


On OS X this is avoided because their isnan() macro expands to call one of the __-prefixed inline functions (which adopt your suggestion of being implemented as x != x, for all types).  I am not sure that this is required for standards conformance, but it is certainly cleaner.  Your statement that having the function not called isnan() causes compatibility problems is demonstrably false, as neither OS X nor glibc has a function called isnan() and, unlike us, they do not experience problems with this macro.  

It would also be nice to implement these macros using _Generic when compiling in C11 mode, as it will allow the compiler to produce more helpful warning messages.  I would propose this implementation:


#if __has_builtin(__builtin_isnan)
#define isnan(x) __builtin_isnan(x)
#else
static __inline int
__isnanf(float __x)
{
        return (__x != __x);
}
static __inline int
__isnand(double __x)
{
        return (__x != __x);
}
static __inline int
__isnanl(long double __x)
{
        return (__x != __x);
}
#if __STDC_VERSION__ >= 201112L
#define isnan(x) _Generic((x),     \
        float: __isnanf(x),        \
        double: __isnand(x),       \
        long double: __isnanl(x))
#else
#define isnan(x)                                                \
        ((sizeof (x) == sizeof (float)) ? __isnanf(x)           \
             : (sizeof (x) == sizeof (double)) ? __isnand(x)    \
             : __isnanl(x))
#endif
#endif

For a trivial example of why this is an improvement in terms of error reporting, consider this trivial piece of code:

int is(int x)
{
        return isnan(x);
}

With our current implementation, this compiles and links without any warnings, although it will have somewhat interesting results at run time.  With the __builtin_isnan() version, clang reports this error:

isnan.c:35:15: error: floating point classification requires argument of
      floating point type (passed in 'int')
        return isnan(x);
                     ^
(and then some more about the macro expansion)

With the C11 version, it reports this error:

isnan.c:35:15: error: controlling expression type 'int' not compatible with any
      generic association type
        return isnan(x);
                     ^



David


[-- Attachment #2 --]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.0.18 (Darwin)
Comment: GPGTools - http://gpgtools.org

iQIcBAEBAgAGBQJR3nDZAAoJEKx65DEEsqIdT0UP/R3/DJeYYumScK0sTI0u0f/K
zr03X2Nn8rHa4xk8avxANTaYYK8QfutKvViv11G1JH/gTGMNh8LxxdoRhsVx4bOe
rAjYY+NDplfLqKTBva+zf25FiQNOn08NnOZDd9l0ApyAK1u2J2dp7Q9yqZbRU7Kj
bACBptR3dREJzSZgIbQcJ5WE3BDsBztW0Az3/WcyDtmILmZ8psVLs+R39qe4yjeV
NxNQRDJuJmccxi8Jx6sjQaUrXVLZ4VWc0Cbr7+0SasHY1avtqoHr6H5pt3ltUtfF
Ld0wQHG8MUuuqZd9j1tQDHSKWmjeDQdOwu8IjEbGP/IXjJI/lK93+K07qMgQPp5G
DJzPoSxJEKTVudNVBuv8sA6iToWMli9ZI/h4YL0Lc0G5vOwLbPHcX1ctEb+g118z
676x26Xdr/vawe0rddCUW2z+CVHj7q1eKY37Za9xVlmchUYWMMzqE8m9MdlQGvmi
y60IDPDcwCiIoZZQ2VbE+wqrgWevEi0nASFttrgqrS7HEBy/rszm8Cdy1wZqUKSe
xi2CwevaMWSfTc9MIwGId5y89UjQ5bSzAPBFWonFZkd/KDN6rRQ1LZvyVrMuZMlX
q/6/2ksNXFHzonOw66/913m+JjYYEaSjmndL0w30qN5HKdNw8C6d+Y9EMrQRMK1A
cjNdMjwrwk2pdBNsVo1d
=FIry
-----END PGP SIGNATURE-----
help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?FD768A6B-8B72-44A1-BC1C-14FF44CB4643>