Skip to content

__builtin_nansq("") in a template becomes a call to the nonexistent nansq (undefined reference at link) #444

Open

Description

@mborland

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.txt file in my .zip or .tar.gz upload. If I included a LICENSE.txt file, any tests created using the reproducing source code will be governed by the terms of the license I provided instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions