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.