Repository navigation
__builtin_nansq("") in a template becomes a call to the nonexistent nansq (undefined reference at link) #444
Description
Issue Summary
In a function emitted as a COMDAT (a template instantiation), the C back end
gives every string literal a named weak array, including the "" argument of
__builtin_nansq / __builtin_nanq. gcc can only fold these builtins when
the argument is a string literal. Given a pointer to an array, it emits a call
to the library function nansq / nanq instead, and the link fails with an
undefined reference. g++ compiles and links the source.
The same code in a non-template function works. The double builtins aren't
affected this way because the front end folds __builtin_nans("") itself (see
the NaN-constant report for what then happens to the value). In Boost, this
makes Boost.Charconv's test_float128 fail to link.
Reproducing Source Code
template <class T> bool snan_is_nan() {
__float128 x = __builtin_nansq("");
return x != x;
}
int main() { return snan_is_nan<int>() ? 0 : 1; }Command-line Options
EDG_USE_SYSTEM_HEADERS=1 eccp --c++17 nansq_template.cpp -o nansq_template
Type of Issue
[Back End] There is a problem with the generated C code.
Additional Details
Expected: links and runs, exit status 0 (g++ 15.3.1: 0).
Actual (linux-gcc-release and linux-gcc-debug):
/usr/sbin/ld: nansq_template.o: in function `_Z11snan_is_nanIiEbv':
nansq_template.int.c:(.text+0x23): undefined reference to `nansq'
collect2: error: ld returned 1 exit status
With __builtin_nanq("") the error is undefined reference to 'nanq'.
Generated C (cpfe --c++17 --gnu_version=150301 -tused --gen_c_file_name=nansq_template.int.c nansq_template.cpp;
-tused makes a single cpfe run emit the instantiation, which eccp's
prelinker otherwise requests):
__attribute__((__weak__)) /* COMDAT group: _ZZ11snan_is_nanIiEbvEs */ char _ZZ11snan_is_nanIiEbvEs[1] = "";
...
auto __float128 __2_14_x; __2_14_x = (__builtin_nansq(((const char *)_ZZ11snan_is_nanIiEbvEs)));gcc folds __builtin_nansq("") and __builtin_nansq((const char *)"") at both
-O0 and -O2, but not a call whose argument is an array object. The fix is
probably to keep string-literal arguments of the __builtin_nan* /
__builtin_nans* builtins as literals when emitting a COMDAT function (or to
fold the __float128 variants in the front end, as for double).
Variants checked: the same body in a non-template function links and runs
(exit status 0). The double version (__builtin_nans("") in a template)
also links, because the front end folds it.
Boost: libs/charconv/test/test_float128.cpp:106-107 call
__builtin_nansq("") inside test_signaling_nan<T>(), which is emitted with
__builtin_nansq(((const char *)_ZZ18test_signaling_nanIgEvvEs_1)). The test
fails to link with undefined reference to 'nansq'.
Environment: edgcpp/dev-env Docker image (Fedora 43, GCC 15.3.1) on
x86-64, boost branch at c36e03a67c. EDG_USE_SYSTEM_HEADERS=1 makes eccp
use GCC 15's headers and pass --gnu_version=150301
(bases/docker/dev-env/gcc/edg_eccp_config).
Reproducing (Standard) Configuration(s)
linux-gcc-release
Reproducing (Non-standard) Configuration
No response
I acknowledge that:
- I have checked open issues and existing discussions before filing this report.
- The reproducing source code that I have provided does not depend on headers that I have not included with my submission.
- I have reduced the reproducing source code to the best of my ability.
- I have selected at least one standard configuration or uploaded a non-standard configuration dump.
- I understand code shared via this form is NOT confidential.
- I have permission to share the reproducing source code and grant permission for the project to use the source code (or derivatives of the source code) to create tests.
- I agree that any tests created using the reproducing source code (or deriatives of it) will be licensed under project license unless I included a
LICENSE.txtfile in my.zipor.tar.gzupload. If I included aLICENSE.txtfile, any tests created using the reproducing source code will be governed by the terms of the license I provided instead.
Activity