https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103949
Bug ID: 103949 Summary: gcc fails to provide a standard conforming C11 or C++17 environment even when specifying -std=c11 or -std=c++17 Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: driver Assignee: unassigned at gcc dot gnu.org Reporter: manx-bugzilla at problemloesungsmaschine dot de Target Milestone: --- Consider the following simple C11 program: ``` #include <math.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #if !defined(__STDC_NO_THREADS) #include <threads.h> #endif #if !defined(__STDC_NO_THREADS) static int mythread(void * arg) { int param = *(int*)arg; double value = pow((double)param, (double)param); printf("%f\n", value); return 1; } bool test(int param) { thrd_t t; memset(&t, 0, sizeof(thrd_t)); if (thrd_create(&t, &mythread, ¶m) != thrd_success) { return false; } int result = 0; if (thrd_join(t, &result) != thrd_success) { return false; } return (result != 0); } #else bool test(int param) { double value = pow((double)param, (double)param); printf("%f\n", value); return true; } #endif int main(int argc, const char * argv []) { (void)argv; return test(argc) ? EXIT_SUCCESS : EXIT_FAILURE; } ``` When I invoke `gcc -std=c11`, it fails to build the program: ``` manx@appendix:~/tmp$ gcc -std=c11 -O3 -Wall -Wextra -Wpedantic c11.c -o test /usr/bin/ld: /tmp/ccxASC6u.o: in function `mythread': c11.c:(.text+0x11): undefined reference to `pow' /usr/bin/ld: /tmp/ccxASC6u.o: in function `test': c11.c:(.text+0x53): undefined reference to `thrd_create' /usr/bin/ld: c11.c:(.text+0x7b): undefined reference to `thrd_join' collect2: error: ld returned 1 exit status manx@appendix:~/tmp$ ``` (gcc (Debian 11.2.0-13) 11.2.0 on a amd64 Debian Testing system, as of today). It works when I invoke gcc as `gcc -std=c11 -pthread -lm`: ``` manx@appendix:~/tmp$ gcc -std=c11 -O3 -Wall -Wextra -Wpedantic c11.c -lm -pthread -o test manx@appendix:~/tmp$ ``` Looking at C++, g++ is slightly better in that it does not barf for math, however it also fails for threads: ``` manx@appendix:~/tmp$ cat cxx17.cpp #if defined(__STDCPP_THREADS__) && (__STDCPP_THREADS__ == 1) #include <iostream> #include <thread> #include <cmath> static void mythread(double param) { double value = std::pow(param, param); std::cout << value << std::endl; return; } bool test(int param) { { std::thread t{&mythread, static_cast<double>(param)}; t.join(); } return true; } int main(int argc, const char * argv []) { static_cast<void>(argv); return test(argc) ? 0 : 1; } #else #error "no threads" #endif manx@appendix:~/tmp$ g++ -std=c++17 -O3 -Wall -Wextra -Wpedantic cxx17.cpp -o test /usr/bin/ld: /tmp/cc1ItNk0.o: in function `test(int)': cxx17.cpp:(.text+0xd7): undefined reference to `pthread_create' collect2: error: ld returned 1 exit status manx@appendix:~/tmp$ g++ -std=c++17 -O3 -Wall -Wextra -Wpedantic cxx17.cpp -pthread -o test manx@appendix:~/tmp$ ``` For MinGW, it's just confused: ``` manx@appendix:~/tmp$ i686-w64-mingw32-g++-posix -std=c++17 -O3 -Wall -Wextra -Wpedantic -mthreads cxx17.cpp -o test cxx17.cpp:30:2: error: #error "no threads" 30 | #error "no threads" | ^~~~~ manx@appendix:~/tmp$ i686-w64-mingw32-g++-posix -std=c++17 -O3 -Wall -Wextra -Wpedantic -mthreads -D__STDCPP_THREADS__=1 cxx17.cpp -o test manx@appendix:~/tmp$ i686-w64-mingw32-g++-posix --version i686-w64-mingw32-g++-posix (GCC) 10-posix 20210110 Copyright (C) 2020 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. manx@appendix:~/tmp$ ``` The C11 as well as the C++17 standards both include both, math and threads, yet gcc fails to provide a complete implementation without adding baroque options. Even more so, gcc *claims* to support threads, when it actually does not. Now, I am aware of historic reasons why things came to be the way they currently (which is ~50 years later) still are, however I completely fail to see why it is really necessary to still complicate building standard conforming programs for modern users. The original reasons are irrelevant to the common case nowadays. I am also aware of embedded situations where the fragmented behavior *could* be desirable. I therefore suggest: 1. Implicitly link anything mandated by the respective standard for a complete implementation when the user requests standard-compliance via -std= switch. 2. Add compiler option -fno-math, which (optionally) cuts off linking some standard libraries by default if possible on the respective platform. 3. Add compiler option -fno-threads, which (optionally) cuts off linking some standard libraries by default if possible on the respective platform, and which implies setting __STDC_NO_THREADS as per C11 standard or unsetting __STDCPP_THREADS__ as per C++ standard. 4. Deprecate and warn about -lm. 5. Deprecate and warn about -pthread, -pthreads, -mthread, -mthreads, and -threads. 6. Fix the inconsistency for MinGW, which does not claim __STDCPP_THREADS__ even when using Posix threading model, where it actually supports threads. I do not care jack what gcc does when the user specifies -std=gnu11 or -std=gnu++17. If you still think these quirks make sense there, leave them as they are for GNU standards. I am also aware that -lm is not strictly speaking gcc's business and might be better suited for a bug report against the C library (glibc in my case), however it's the compiler that I am requesting C11 support from, thus it IMHO is the compiler's responsibility to provide an adequate implementation. I somewhat expect you may be tempted to disregard or close this bug report as irrelevant or maybe a duplicate, but I honestly urge you to reconsider gcc's utterly quirky behavior here. It makes no sense, and it's about time to actually fix the problem. The re-iterate the problem for a last concise time: When I request -std=c11, I expect to get a working C11 environment, which if !__STDC_NO_THREADS provides adequate support for multi-threaded programs. The same applies for C++, and also for the MinGW case (see -mthreads). The defaults must adhere to the standard.