Skip to content

Conversation

AaronBallman
Copy link
Collaborator

These macros were brought in as part of the TS 18661-1 integration in C23, and then renamed in WG14 N2710.

Test coverage is being added to WG14 N3364 from C2y because that paper was fixing a bug with the way these macros are handled with unary + and

  • operators, so all the existing test coverage was there, just needed to use a header file instead of defining the macros manually.

Fixes #162830

These macros were brought in as part of the TS 18661-1 integration in
C23, and then renamed in WG14 N2710.

Test coverage is being added to WG14 N3364 from C2y because that paper
was fixing a bug with the way these macros are handled with unary + and
- operators, so all the existing test coverage was there, just needed
to use a header file instead of defining the macros manually.

Fixes llvm#162830
@AaronBallman AaronBallman added clang Clang issues not falling into any other category c23 clang:headers Headers provided by Clang, e.g. for intrinsics labels Oct 10, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 10, 2025

@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-clang

Author: Aaron Ballman (AaronBallman)

Changes

These macros were brought in as part of the TS 18661-1 integration in C23, and then renamed in WG14 N2710.

Test coverage is being added to WG14 N3364 from C2y because that paper was fixing a bug with the way these macros are handled with unary + and

  • operators, so all the existing test coverage was there, just needed to use a header file instead of defining the macros manually.

Fixes #162830


Full diff: https://github.com/llvm/llvm-project/pull/162858.diff

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+3)
  • (modified) clang/lib/Headers/float.h (+9)
  • (modified) clang/test/C/C2y/n3364.c (+15-8)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 99aa545831240..2fead354e2252 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -184,6 +184,9 @@ C2y Feature Support
 
 C23 Feature Support
 ^^^^^^^^^^^^^^^^^^^
+- Added ``FLT_SNAN``, ``DBL_SNAN``, and ``LDBL_SNAN`` to Clang's ``<float.h>``
+  header in C23 and later modes. This implements
+  `WG14 N2710 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2710.htm>`_.
 
 Non-comprehensive list of changes in this release
 -------------------------------------------------
diff --git a/clang/lib/Headers/float.h b/clang/lib/Headers/float.h
index 84551af473b28..30427c29dcdbd 100644
--- a/clang/lib/Headers/float.h
+++ b/clang/lib/Headers/float.h
@@ -89,6 +89,9 @@
     !defined(__STRICT_ANSI__)
 #  undef INFINITY
 #  undef NAN
+#  undef FLT_SNAN
+#  undef DBL_SNAN
+#  undef LDBL_SNAN
 #endif
 
 /* Characteristics of floating point types, C99 5.2.4.2.2 */
@@ -160,9 +163,15 @@
 
 #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) ||              \
     !defined(__STRICT_ANSI__)
+   /* C23 5.2.5.3.2p28 */
+#  define FLT_SNAN (__builtin_nansf(""))
+#  define DBL_SNAN (__builtin_nans(""))
+#  define LDBL_SNAN (__builtin_nansl(""))
+
    /* C23 5.2.5.3.3p29-30 */
 #  define INFINITY (__builtin_inff())
 #  define NAN (__builtin_nanf(""))
+
    /* C23 5.2.5.3.3p32 */
 #  define FLT_NORM_MAX __FLT_NORM_MAX__
 #  define DBL_NORM_MAX __DBL_NORM_MAX__
diff --git a/clang/test/C/C2y/n3364.c b/clang/test/C/C2y/n3364.c
index 277b2643edd6b..d75f17d0a7a84 100644
--- a/clang/test/C/C2y/n3364.c
+++ b/clang/test/C/C2y/n3364.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -verify -std=c2y -Wall -pedantic -emit-llvm -o - %s
-// RUN: %clang_cc1 -verify -Wall -pedantic -emit-llvm -o - %s
+// RUN: %clang_cc1 -verify -std=c2y -ffreestanding -Wall -pedantic -emit-llvm -o - %s
+// RUN: %clang_cc1 -verify -ffreestanding -Wall -pedantic -emit-llvm -o - %s
 // expected-no-diagnostics
 
 /* WG14 N3364: Yes
@@ -7,11 +7,18 @@
  *
  * Ensure that initializing from a signaling NAN (optionally with a unary + or
  * -) at translation time behaves correctly at runtime.
+ *
+ * This also serves as a test for C23's WG14 N2710 which introduces these
+ * macros into float.h in Clang 22.
  */
 
-#define FLT_SNAN __builtin_nansf("1")
-#define DBL_SNAN __builtin_nans("1")
-#define LD_SNAN __builtin_nansl("1")
+#if __STDC_VERSION__ >= 202311L
+#include <float.h>
+#else
+#define FLT_SNAN __builtin_nansf("")
+#define DBL_SNAN __builtin_nans("")
+#define LDBL_SNAN __builtin_nansl("")
+#endif
 
 float f1 = FLT_SNAN;
 float f2 = +FLT_SNAN;
@@ -27,9 +34,9 @@ double d3 = -DBL_SNAN;
 // CHECK: @d2 = {{.*}}global double 0x7FF0000000000001
 // CHECK: @d3 = {{.*}}global double 0xFFF0000000000001
 
-long double ld1 = LD_SNAN;
-long double ld2 = +LD_SNAN;
-long double ld3 = -LD_SNAN;
+long double ld1 = LDBL_SNAN;
+long double ld2 = +LDBL_SNAN;
+long double ld3 = -LDBL_SNAN;
 // CHECK: @ld1 = {{.*}}global {{double 0x7FF0000000000001|x86_fp80 0xK7FFF8000000000000001|fp128 0xL00000000000000017FFF000000000000}}
 // CHECK: @ld2 = {{.*}}global {{double 0x7FF0000000000001|x86_fp80 0xK7FFF8000000000000001|fp128 0xL00000000000000017FFF000000000000}}
 // CHECK: @ld3 = {{.*}}global {{double 0xFFF0000000000001|x86_fp80 0xKFFFF8000000000000001|fp128 0xL0000000000000001FFFF000000000000}}

Copy link

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions h,c -- clang/lib/Headers/float.h clang/test/C/C2y/n3364.c

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/clang/lib/Headers/float.h b/clang/lib/Headers/float.h
index 30427c29d..9dc06c7c0 100644
--- a/clang/lib/Headers/float.h
+++ b/clang/lib/Headers/float.h
@@ -89,9 +89,9 @@
     !defined(__STRICT_ANSI__)
 #  undef INFINITY
 #  undef NAN
-#  undef FLT_SNAN
-#  undef DBL_SNAN
-#  undef LDBL_SNAN
+#undef FLT_SNAN
+#undef DBL_SNAN
+#undef LDBL_SNAN
 #endif
 
 /* Characteristics of floating point types, C99 5.2.4.2.2 */
@@ -163,12 +163,12 @@
 
 #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) ||              \
     !defined(__STRICT_ANSI__)
-   /* C23 5.2.5.3.2p28 */
-#  define FLT_SNAN (__builtin_nansf(""))
-#  define DBL_SNAN (__builtin_nans(""))
-#  define LDBL_SNAN (__builtin_nansl(""))
+/* C23 5.2.5.3.2p28 */
+#define FLT_SNAN (__builtin_nansf(""))
+#define DBL_SNAN (__builtin_nans(""))
+#define LDBL_SNAN (__builtin_nansl(""))
 
-   /* C23 5.2.5.3.3p29-30 */
+/* C23 5.2.5.3.3p29-30 */
 #  define INFINITY (__builtin_inff())
 #  define NAN (__builtin_nanf(""))
 

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a question about interpreting the standard. The standard says each of these macros "is defined if and only if the respective type contains signaling NaNs." Given that by default LLVM IR gives the compiler permission to treat all NaNs as if they were quiet NaNs, should we really be defining these macros in the default mode?

My understanding is that these built-ins will indeed produce a signaling NaN value, but the quiet/signaling behavior may not be respected by the optimizer.

@AaronBallman
Copy link
Collaborator Author

I have a question about interpreting the standard. The standard says each of these macros "is defined if and only if the respective type contains signaling NaNs." Given that by default LLVM IR gives the compiler permission to treat all NaNs as if they were quiet NaNs, should we really be defining these macros in the default mode?

I think we likely want them defined for GCC compatibility: https://godbolt.org/z/9PjdfM8hx they still define the macro even when passing -fno-signaling-nans. However, this is out of my wheelhouse, so I defer to the floating-point experts on this.

@jcranmer-intel
Copy link
Contributor

I have a question about interpreting the standard. The standard says each of these macros "is defined if and only if the respective type contains signaling NaNs." Given that by default LLVM IR gives the compiler permission to treat all NaNs as if they were quiet NaNs, should we really be defining these macros in the default mode?

My understanding is that these built-ins will indeed produce a signaling NaN value, but the quiet/signaling behavior may not be respected by the optimizer.

The way I interpret the standard, it discusses whether or not the format of the type supports sNaNs, not whether or not the current floating-point model has full sNaN operational semantics. Since the IEEE 754 types support sNaNs, then they should have sNaN support enabled for them.

Whether or not the sNaN types are actually usable is actually envisioned by the standard--there's actually a FE_SNANS_ALWAYS_SIGNAL macro in Annex F for indicating whether or not sNaNs are fully following IEEE 754 operational semantics.

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the clarifications on standard interpretation and GCC behavior, I'm happy with this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:X86 c23 clang:headers Headers provided by Clang, e.g. for intrinsics clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

C23 mode: <float.h> missing FLT_SNAN macro

4 participants