[cfe-dev] LibC++ v3.8 - Problems with ISO C wrapper headers
Martin J. O'Riordan via cfe-dev
cfe-dev at lists.llvm.org
Sat Jan 23 05:50:03 PST 2016
While getting our implementation of the compiler ready for v3.8 we came
across a significant problem in the new implementation of LibC++'s handling
of the ISO C Standard headers that needs to be fixed before the v3.8
release.
We discovered the problem when running some tests that were derived from
real-world code. The initial example involved a C++ program including
'<math.h>' and using 'fabs' but the issue applies equally to the other
headers, for example:
#include <math.h>
...
__fp16 y; // We use FP16 a lot
fabs(y); // really -> fabs((double)y);
In C there is only one 'fabs' with the signature:
double fabs(double)
With the new implementation of the headers for LibC++, there is now a file
named 'c++/math.h' that includes the C version and then supplements it for
C++. When I use this, the above use of 'fabs' above results in an overload
ambiguity error.
It's easy to say "It's C++, use '<cmath>'", but in the real-world C++
programmers very commonly use the C headers whether they should or not. In
any case, '<math.h>' does not belong to C++ and the C++ implementation
should not interfere with the interface expressed by a foreign header when
that header is included directly.
After looking further into this I realised that there is an inadvertent bug
in the new implementation rather than an intent to interfere with the C
interface. It also breaks C++'s '<cmath>' interface requirements. The
supplementary elements used to be in '<cmath>' itself, but since they were
extracted they are in the global namespace and not in 'namespace std' where
they are intended to be, and they are consequently introducing overloads
into the C usage. I will describe this for 'fabs' but the pattern appears
to be in all of the new ISO C wrapper headers. In 'c++/math.h' we have
(abbreviated for illustration):
#ifndef _LIBCPP_MATH_H
#define _LIBCPP_MATH_H
#include <__config>
#include_next <math.h>
#ifdef __cplusplus
// Missing: _LIBCPP_BEGIN_NAMESPACE_STD
#if !(defined(_LIBCPP_MSVCRT) || defined(_AIX))
inline _LIBCPP_INLINE_VISIBILITY float fabs(float __lcpp_x) _NOEXCEPT
{return fabsf(__lcpp_x);}
inline _LIBCPP_INLINE_VISIBILITY long double fabs(long double __lcpp_x)
_NOEXCEPT {return fabsl(__lcpp_x);}
#endif
template <class _A1>
inline _LIBCPP_INLINE_VISIBILITY
typename std::enable_if<std::is_integral<_A1>::value, double>::type
fabs(_A1 __lcpp_x) _NOEXCEPT {return fabs((double)__lcpp_x);}
// Missing: _LIBCPP_END_NAMESPACE_STD
#endif // __cplusplus
#endif // _LIBCPP_MATH_H
but because this is no longer between '_LIBCPP_BEGIN_NAMESPACE_STD' and
'_LIBCPP_END_NAMESPACE_STD', the new declarations introduce overloads at the
global namespace and not in the 'std' namespace.
Now when '<math.h>' is included explicitly you get 'fabs' as follows:
double ::fabs(double) // From 'include/math.h'
float ::fabs(float) // From 'include/c++/math.h'
long double ::fabs(long double) // Also from 'include/c++/math.h'
With the namespace correction explicitly including '<math.h>' would produce:
double ::fabs(double) // From 'include/math.h'
float std::fabs(float) // From 'include/c++/math.h'
long double std::fabs(long double) // Also from 'include/c++/math.h'
Which will not break the C compatible use case.
However, I think that using the ISO C math header explicitly like this
should not be supplemented with partial ISO C++math header requirements,
it's neither C's '<math.h>' nor C++'s '<cmath>' and has odd incongruities
such as:
#include <math.h>
float (*pf)(float) = std::fabs; // Okay, we have this
long double (*pld)(long double) = std::fabs; // Okay, we have this too
double (*pd)(double) = std::fabs; // Oops, no such function
This is not as serious as the namespace bug, but it is strangely
inconsistent and shouldn't really be there. What I propose for this is an
equally simple change. In '<cmath>' replace:
#include <math.h>
with:
#define _LIBCPP_INCLUDING_STDC_HEADER
#include <math.h>
#undef _LIBCPP_INCLUDING_STDC_HEADER
and then in 'c++/math.h', replace:
#ifdef __cplusplus
with:
#ifdef _LIBCPP_INCLUDING_STDC_HEADER
I've only referred to 'fabs' and '<math.h>', but of course it is all the
overloaded "from C" functions in the 'std::' namespace that are affected,
and the same problem is present in the other ISO C wrapper headers.
I will work on this over the weekend and hope to be able to submit a tested
patch file on Monday or Tuesday that will correct this. I'm at SVN revision
#258500 for the v3.8 branch at the moment, but I will update and merge to
the most recent version before I submit a patch file for your consideration.
Thanks,
MartinO
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20160123/ed125726/attachment.html>
More information about the cfe-dev
mailing list