Repository navigation
qualify isnan() with std namespace - #565
Conversation
When a program that depends on implot includes <implot.h>, we have this sequence of includes: <implot.h> -> <implot_internal.h> -> <imgui_internal.h> -> <math.h> Inside <implot_internal.h>'s source code, there's an unqualified call to isnan(). By doing so, it relies on <imgui_internal.h> having isnan() in the global namespace, which <math.h> is guaranteed to do. However, it's possible that implot's user included <cmath> first, which is not guaranteed to put isnan() in the global namespace, and may prevent a later <math.h> from putting isnan() in the global namespace. On NetBSD 10.0 i386, <cmath> doesn't put isnan() in the global namespace and prevents <math.h> from doing so, causing a compile error. Qualify the call to fix it.
The NetBSD port will only work after epezent/implot#565 is merged and Dolphin updates to a version with the fix. In the meantime, you can apply the fix yourself to a Dolphin checkout.
The NetBSD port will only work after epezent/implot#565 is merged and Dolphin updates to a version with the fix. In the meantime, you can apply the fix yourself to a Dolphin checkout.
|
@guijan is this still an issue with the latest ImGui? I thought |
|
I can confirm that this still happens with master. I just came across this issue while trying to cross-compile from x64 to ARM64 on Linux while using glibc in particular. |
|
Oh... I've moved the issue to high priority :) Are you able to reproduce the issue by modifying the |
|
I've narrowed it down quite a lot, so much so that I can place the reproduction program here: #include <cmath>
#include "implot.h"
#include "implot_internal.h"
int main() { return 0; }Here is what happens when I try to compile this program using glibc and gcc/g++ from x64 to ARM64: Log OutputIt seems including cmath before implot_internal.h causes the issue to show up. This issue does not happen when compiling without a sysroot and cross-compiler, though. |
Yep, that looks pretty narrow to me... |
|
I was planning to close this issue since I can't reproduce it, but I've got an idea. Can someone (@guijan @JoshuaVandaele) try to add #ifndef IMPLOT_VERSION
#error Must include implot.h before implot_internal.h
#endif
#ifndef IMGUI_DISABLE
#include <time.h>
+#include <math.h>
#include "imgui_internal.h"
// Support for pre-1.84 versions. ImPool's GetSize() -> GetBufSize()
#if (IMGUI_VERSION_NUM < 18303)
#define GetBufSize GetSize
#endif
|
Sadly this does not fix the issue. Using either |
std::isnan alone still fails in the configuration that broke the original isnan: when the C library's <math.h> is found before the C++ standard library's (a sysroot or system include directory passed with -I), isnan stays a macro and std::isnan expands to the invalid std::__builtin_isnan, and with libc++ std::isnan is not declared at all unless <cmath> is included first. Including <cmath> ourselves is not enough either, since libc++ rejects that include order outright. ImNan and ImNanOrInf now copy the double into an ImU64 and test the IEEE-754 exponent and mantissa, which needs no <cmath> and no isnan macro or function. Unlike isnan, std::isnan or val != val, the bit test also keeps working under -ffast-math and /fp:fast, where the compiler may fold floating-point NaN checks to false and NaN gaps in plots silently disappear. Under -ffinite-math-only an empty asm statement hides the bits from the optimizer, because clang otherwise folds the exponent test to false as well.
|
What was wrong. What the fix does. I added a commit on top of yours that stops asking the compiler "is this NaN?". It reads the 64 bits of the static inline bool ImNan(double val) { return (ImDoubleBits(val) & 0x7FFFFFFFFFFFFFFFull) > 0x7FF0000000000000ull; }This needs no math header, so include order doesn't matter. GCC treats it as plain integer math, so fast-math leaves it alone. Clang would still fold it away, so the commit adds a tiny optimizer barrier that is only active in fast-math builds. How I tested it.
I'll port the same change to ImPlot3D. Let me know if you guys still experience the issue! |
ImNan called the unqualified isnan, which fails to build when <cmath> is included before ImPlot3D and the C library's <math.h> is found ahead of the C++ one (a sysroot or system include directory passed with -I): isnan is then neither a macro nor a global function. Switching to std::isnan only moves the failure to other setups, such as libc++ without <cmath>. ImNan and ImNanOrInf now copy the double into an ImU64 and test the IEEE-754 exponent and mantissa, so they need no math header, and unlike isnan or val != val they keep detecting NaN under -ffast-math and /fp:fast, where the compiler may delete floating-point NaN checks. Under -ffinite-math-only an empty asm statement hides the bits from the optimizer, since clang otherwise folds the exponent test to false. Mirrors the same fix in ImPlot (epezent/implot#565).
See the commit message for details. I've tested this change on NetBSD only.
Found while porting dolphin-emu/dolphin to NetBSD: