Bug 48891 - std functions conflicts with C functions when building with c++0x support (and using namespace std)
Summary: std functions conflicts with C functions when building with c++0x support (an...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.6.0
: P3 normal
Target Milestone: 6.0
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
: 60407 68984 (view as bug list)
Depends on:
Blocks:
 
Reported: 2011-05-05 21:32 UTC by Alexis Menard
Modified: 2016-02-08 15:23 UTC (History)
9 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 4.8.3, 4.9.2, 5.0
Last reconfirmed: 2015-04-09 00:00:00


Attachments
Small test case. (152 bytes, text/x-c++src)
2011-05-05 21:32 UTC, Alexis Menard
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Alexis Menard 2011-05-05 21:32:46 UTC
Created attachment 24193 [details]
Small test case.

Hello,

I'm not sure it's a real bug (though that example builds fine with gcc 4.5.0) but at least perhaps I'll get help.

Consider :

#include <stdlib.h>
#include <cmath>
#include <stdio.h>

using namespace std;

int main(int argc, char** argv)
{
    double number = 0;
    if (isnan(number))
    {
        printf("Nan\n");
    }
    return 0;
}

and build it with : g++ main.cpp -std=c++0x -std=gnu++0x -o test

It fails to compile : 

main.cpp: In function ‘int main(int, char**)’:
main.cpp:10:21: error: call of overloaded ‘isnan(double&)’ is ambiguous
main.cpp:10:21: note: candidates are:
/usr/include/bits/mathcalls.h:235:1: note: int isnan(double)
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../include/c++/4.6.0/cmath:558:3: note: bool std::isnan(long double)
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../include/c++/4.6.0/cmath:554:3: note: bool std::isnan(double)
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../include/c++/4.6.0/cmath:550:3: note: bool std::isnan(float)

If I deactivate the c++0x support it works.

The real issue is that the c++0x standard removes the prohibition on C++ headers declaring C names in the global namespace. The problem here is that math.h is included therefore the declarations are in the global namespace.

I'm not really sure how the compiler can solve that but this new "feature" of c++0x seems to be very annoying. I could solve it by not using namespace std but let say the project is huge, it will requires lot of modifications.

Basically any time you use using namespace std, you may have conflicts with the underlaying C libraries, it's even more annoying with your own namespace because your functions can conflict with all the stuff in the global namespace put by C libraries and it's very common in a cpp file to use "using namespace foo;"

Any suggestions on how I could "workaround" that?
Comment 1 Alexis Menard 2011-05-05 21:35:55 UTC
glibc 2.13-5.
binutils 2.21-7

Archlinux.
Comment 2 Jonathan Wakely 2011-05-05 22:03:55 UTC
(In reply to comment #0)
> 
> and build it with : g++ main.cpp -std=c++0x -std=gnu++0x -o test

There's no point specifying two -std options, only the last one takes effect.

> If I deactivate the c++0x support it works.

Because in C++98 there is no std::isnan, so you only get the version in the global namespace from <math.h>
 
> The real issue is that the c++0x standard removes the prohibition on C++
> headers declaring C names in the global namespace. The problem here is that
> math.h is included therefore the declarations are in the global namespace.

I don't think that's the problem, because libstdc++ has always declared the names in the global namespace even though it wasn't valid in C++03 - we haven't changed that for C++0x (all that happened is the standard was relaxed to reflect the reality of actual implementations)

 
> I'm not really sure how the compiler can solve that but this new "feature" of
> c++0x seems to be very annoying. I could solve it by not using namespace std
> but let say the project is huge, it will requires lot of modifications.
> 
> Basically any time you use using namespace std, you may have conflicts with the
> underlaying C libraries, it's even more annoying with your own namespace
> because your functions can conflict with all the stuff in the global namespace
> put by C libraries and it's very common in a cpp file to use "using namespace
> foo;"
> 
> Any suggestions on how I could "workaround" that?

Qualify isnan explicitly, by calling either ::isnan or std::isnan
Comment 3 Alexis Menard 2011-05-05 22:17:36 UTC
(In reply to comment #2)
> (In reply to comment #0)
> > 
> > and build it with : g++ main.cpp -std=c++0x -std=gnu++0x -o test
> 
> There's no point specifying two -std options, only the last one takes effect.
> 
> > If I deactivate the c++0x support it works.
> 
> Because in C++98 there is no std::isnan, so you only get the version in the
> global namespace from <math.h>

That explain.

> 
> > The real issue is that the c++0x standard removes the prohibition on C++
> > headers declaring C names in the global namespace. The problem here is that
> > math.h is included therefore the declarations are in the global namespace.
> 
> I don't think that's the problem, because libstdc++ has always declared the
> names in the global namespace even though it wasn't valid in C++03 - we haven't
> changed that for C++0x (all that happened is the standard was relaxed to
> reflect the reality of actual implementations)
> 

Sorry for my ignorance.

> 
> > I'm not really sure how the compiler can solve that but this new "feature" of
> > c++0x seems to be very annoying. I could solve it by not using namespace std
> > but let say the project is huge, it will requires lot of modifications.
> > 
> > Basically any time you use using namespace std, you may have conflicts with the
> > underlaying C libraries, it's even more annoying with your own namespace
> > because your functions can conflict with all the stuff in the global namespace
> > put by C libraries and it's very common in a cpp file to use "using namespace
> > foo;"
> > 
> > Any suggestions on how I could "workaround" that?
> 
> Qualify isnan explicitly, by calling either ::isnan or std::isnan

Well that requires me to modify my entire project, namely WebKit :(. But the more I'm stuck on that issue, the more it seems to be the only solution.
Comment 4 Paolo Carlini 2011-05-05 22:46:39 UTC
Just wanted to add that the real reason the issue is more subtle now in C++0x mode than it used to be (and still is) in C++03 mode as an extension, is that we now provide the functions in namespace std with the mandated return type, that is bool, whereas in C++03 mode, as an extension, the return type is int, like in C99. Frankly, *given* the usual, well known, limits of our way of dealing with the underlying *.h C headers (included as implementation detail anyway), I don't see any reasonably simple way of solving this family of problems.

Actually, anyway, modulo a C++ front-end issue I filed some time ago, I think the <cmath> header isn't *that* far from dispensing with including math.h, the most important blocking issue being the constants FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, which, the last time I asked, Joseph, if I remember correctly, said are very tricky to obtain outside math.h...

Anyway, given the different return types in C++0x and C99, the problem would resurface quite unavoidably with:

#include <cmath>
#include <math.h>

using namespace std;

of course, if we only fix <cmath> still without fully controlling math.h. Don't hold your breath ;)
Comment 5 Paolo Carlini 2011-05-05 23:13:43 UTC
Jakub, wrt my Comment #4, would it make sense in your opinion to implement a mechanism requiring cooperation between glibc & libstdc++ similar to the __CORRECT_ISO_CPP_STRING_H_PROTO mechanism you implemented for memchr & co back in 2009-01-30?
Comment 6 Marc Glisse 2012-04-29 13:15:40 UTC
I don't think it matters that much whether the return type is int or bool, compared to the inconvenience of having 2 functions that conflict.

The constexpr qualifier is nice, but not required by the standard, and not even by gcc which recognizes that extern "C" int isnan(double) is a builtin (note that it doesn't recognize it anymore if you change the return type to bool, that should be fixed).

For the same reason (recognized as a builtin), there is no performance advantage to having it inline.

So I think:
* glibc could change the return type of isnan to bool in C++ (there would be a regression in that ::isnan wouldn't be constexpr and inline until g++ is taught the right prototype)
* libstdc++ could import ::isnan in std::, assuming isnan exists. Maybe that requires a configure test. Maybe that test would be rather fragile (depends on feature macros). Maybe that's where this stops being a good idea :-(
Comment 7 Jonathan Wakely 2016-01-07 13:16:15 UTC
*** Bug 68984 has been marked as a duplicate of this bug. ***
Comment 8 Jonathan Wakely 2016-01-07 13:16:39 UTC
*** Bug 60407 has been marked as a duplicate of this bug. ***
Comment 9 Jonathan Wakely 2016-01-07 13:20:49 UTC
There are various ways to hit this issue, some of which mean it can be considered a regression, because the same code compiled with older releases (before we added the C++11 definitions of isinf/isnan) or with -std=gnu++98 (and since the default changed to -std=gnu++14 that means code that worked with the default options now doesn't compile).

(In reply to Marc Glisse from comment #6)
> * glibc could change the return type of isnan to bool in C++ (there would be
> a regression in that ::isnan wouldn't be constexpr and inline until g++ is
> taught the right prototype)

I think glibc should just not declare those functions in C++ (as Joseph said in Bug 54130 comment 14 they are from Unix98 and not part of C99 anyway, because C99 requires generic macros).

> * libstdc++ could import ::isnan in std::, assuming isnan exists. Maybe that
> requires a configure test. Maybe that test would be rather fragile (depends
> on feature macros). Maybe that's where this stops being a good idea :-(

I'm going to take this approach for now, and try to get glibc to change for the future.
Comment 10 Adhemerval Zanella 2016-01-11 19:17:57 UTC
It is being tracked by https://sourceware.org/bugzilla/show_bug.cgi?id=19439 and has been fixed by d9b965fa56350d6eea9f7f438a0714c7ffbb183f. It will be included in GLIBC 2.23.
Comment 11 Jonathan Wakely 2016-01-13 16:26:28 UTC
Author: redi
Date: Wed Jan 13 16:25:56 2016
New Revision: 232327

URL: https://gcc.gnu.org/viewcvs?rev=232327&root=gcc&view=rev
Log:
Use ::isinf and ::isnan if libc defines them

	PR libstdc++/48891
	* acinclude.m4 (GLIBCXX_CHECK_MATH11_PROTO): Check for obsolete isinf
	and isnan functions.
	* config.h.in: Regenerate.
	* configure: Regenerate.
	* include/c_global/cmath (isinf(double), isnan(double))
	[_GLIBCXX_HAVE_OBSOLETE_ISINF_ISNAN]: Import via using-directive.
	* testsuite/26_numerics/headers/cmath/48891.cc: New.

Added:
    trunk/libstdc++-v3/testsuite/26_numerics/headers/cmath/48891.cc
Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/acinclude.m4
    trunk/libstdc++-v3/config.h.in
    trunk/libstdc++-v3/configure
    trunk/libstdc++-v3/include/c_global/cmath
Comment 12 Jonathan Wakely 2016-01-13 16:31:09 UTC
Fixed on trunk.
Comment 13 Jonathan Wakely 2016-02-08 15:23:03 UTC
Author: redi
Date: Mon Feb  8 15:22:32 2016
New Revision: 233214

URL: https://gcc.gnu.org/viewcvs?rev=233214&root=gcc&view=rev
Log:
Enable isinf/isnan checks for all targets

	PR libstdc++/48891
	* acinclude.m4 (GLIBCXX_CHECK_MATH11_PROTO): Enable isinf and isnan
	checks for all targets except *-*-solaris2.* and ensure we find the
	libc math.h header not our own.
	* configure: Regenerate.

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/acinclude.m4
    trunk/libstdc++-v3/configure