From 760d5ec69ab9c8969f09ac920143eccc69a641b8 Mon Sep 17 00:00:00 2001 From: Brayden Lee Date: Fri, 19 Dec 2025 22:45:43 -0500 Subject: [PATCH 1/8] Added Unreachable --- imgui.h | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index a336ccd06570..99a736c409e2 100644 --- a/imgui.h +++ b/imgui.h @@ -43,7 +43,7 @@ Index of this file: // [SECTION] Dear ImGui end-user API functions // [SECTION] Flags & Enumerations // [SECTION] Tables API flags and structures (ImGuiTableFlags, ImGuiTableColumnFlags, ImGuiTableRowFlags, ImGuiTableBgTarget, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) -// [SECTION] Helpers: Debug log, Memory allocations macros, ImVector<> +// [SECTION] Helpers: Debug log, Memory allocations macros, ImVector<>, Unreachable // [SECTION] ImGuiStyle // [SECTION] ImGuiIO // [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) @@ -2150,7 +2150,7 @@ struct ImGuiTableColumnSortSpecs }; //----------------------------------------------------------------------------- -// [SECTION] Helpers: Debug log, memory allocations macros, ImVector<> +// [SECTION] Helpers: Debug log, memory allocations macros, ImVector<>, Unreachable //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -2255,6 +2255,37 @@ struct ImVector }; IM_MSVC_RUNTIME_CHECKS_RESTORE +//----------------------------------------------------------------------------- +// ImGui::Unreachable() +// Provides an equivalent for std::unreachable() for C++<23. This signals to the compiler that a region is unreachable, allowing optimizations. +//----------------------------------------------------------------------------- +// If you are using C++>=23, use std::unreachable() in , and you may also define STD_UNREACHABLE_IS_AVAILABLE to substitute definitions. +// Code is from: https://en.cppreference.com/w/cpp/utility/unreachable.html +// Inclusion in the ImGUI namespace is chosen to avoid possible namespace collisions with stdlib >= 23. +//----------------------------------------------------------------------------- +namespace ImGui +{ +//#define STD_UNREACHABLE_IS_AVAILABLE +#ifdef STD_UNREACHABLE_IS_AVAILABLE + #include + constexpr const auto Unreachable = ::std::unreachable; + #undef STD_UNREACHABLE_IS_AVAILABLE +#else + [[noreturn]] inline void Unreachable() + { + // Uses compiler specific extensions if possible. + // Even if no extension is used, undefined behavior is still raised by + // an empty function body and the noreturn attribute. + #if defined(_MSC_VER) && !defined(__clang__) // MSVC + __assume(false); + #else // GCC, Clang + __builtin_unreachable(); + #endif + } +#endif + +} // namespace ImGui + //----------------------------------------------------------------------------- // [SECTION] ImGuiStyle //----------------------------------------------------------------------------- From e269a23a8337131557405d7ee31eff7fa9807739 Mon Sep 17 00:00:00 2001 From: Brayden Lee Date: Sat, 20 Dec 2025 00:51:28 -0500 Subject: [PATCH 2/8] Rewrote ImVec2 subscripting to remove undefined behavior --- imgui.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index 99a736c409e2..90a3fdf31581 100644 --- a/imgui.h +++ b/imgui.h @@ -287,6 +287,7 @@ typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints() typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() +namespace ImGui { [[noreturn]] inline void Unreachable(); }; // Function signature for ImGui::Unreachable() // ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type] // - This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. @@ -297,8 +298,15 @@ struct ImVec2 float x, y; constexpr ImVec2() : x(0.0f), y(0.0f) { } constexpr ImVec2(float _x, float _y) : x(_x), y(_y) { } - float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(void*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine. - float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const void*)(const char*)this)[idx]; } + #define SUBSCRIPT_OPERATION \ + switch (idx % 2) { \ + case 0: return x; \ + case 1: return y; \ + default: ImGui::Unreachable(); /* Compiler hint: ensures optimization is taken and removes a false positive non-returning branch. */ \ + }; + float& operator[] (size_t idx) { SUBSCRIPT_OPERATION; } + float operator[] (size_t idx) const { SUBSCRIPT_OPERATION; } + #undef SUBSCRIPT_OPERATION #ifdef IM_VEC2_CLASS_EXTRA IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. #endif @@ -2261,7 +2269,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- // If you are using C++>=23, use std::unreachable() in , and you may also define STD_UNREACHABLE_IS_AVAILABLE to substitute definitions. // Code is from: https://en.cppreference.com/w/cpp/utility/unreachable.html -// Inclusion in the ImGUI namespace is chosen to avoid possible namespace collisions with stdlib >= 23. +// Inclusion in the ImGUI namespace is chosen to avoid possible namespace collisions. //----------------------------------------------------------------------------- namespace ImGui { From 6be31c0824cbad50142d6a35eadc284d257b2916 Mon Sep 17 00:00:00 2001 From: Brayden Lee Date: Mon, 22 Dec 2025 22:51:33 -0500 Subject: [PATCH 3/8] Revert "Rewrote ImVec2 subscripting to remove undefined behavior" This reverts commit e269a23a8337131557405d7ee31eff7fa9807739. --- imgui.h | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/imgui.h b/imgui.h index f0d381e385cf..6cecb3a60c47 100644 --- a/imgui.h +++ b/imgui.h @@ -287,7 +287,6 @@ typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints() typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() -namespace ImGui { [[noreturn]] inline void Unreachable(); }; // Function signature for ImGui::Unreachable() // ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type] // - This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. @@ -298,15 +297,8 @@ struct ImVec2 float x, y; constexpr ImVec2() : x(0.0f), y(0.0f) { } constexpr ImVec2(float _x, float _y) : x(_x), y(_y) { } - #define SUBSCRIPT_OPERATION \ - switch (idx % 2) { \ - case 0: return x; \ - case 1: return y; \ - default: ImGui::Unreachable(); /* Compiler hint: ensures optimization is taken and removes a false positive non-returning branch. */ \ - }; - float& operator[] (size_t idx) { SUBSCRIPT_OPERATION; } - float operator[] (size_t idx) const { SUBSCRIPT_OPERATION; } - #undef SUBSCRIPT_OPERATION + float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(void*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine. + float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const void*)(const char*)this)[idx]; } #ifdef IM_VEC2_CLASS_EXTRA IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. #endif @@ -2271,7 +2263,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- // If you are using C++>=23, use std::unreachable() in , and you may also define STD_UNREACHABLE_IS_AVAILABLE to substitute definitions. // Code is from: https://en.cppreference.com/w/cpp/utility/unreachable.html -// Inclusion in the ImGUI namespace is chosen to avoid possible namespace collisions. +// Inclusion in the ImGUI namespace is chosen to avoid possible namespace collisions with stdlib >= 23. //----------------------------------------------------------------------------- namespace ImGui { From 231305ac4725ae7777bb6e859f99c328f0064ce3 Mon Sep 17 00:00:00 2001 From: Brayden Lee Date: Mon, 22 Dec 2025 22:52:20 -0500 Subject: [PATCH 4/8] Revert "Added Unreachable" This reverts commit 760d5ec69ab9c8969f09ac920143eccc69a641b8. --- imgui.h | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/imgui.h b/imgui.h index 6cecb3a60c47..2c8fecef6cd8 100644 --- a/imgui.h +++ b/imgui.h @@ -43,7 +43,7 @@ Index of this file: // [SECTION] Dear ImGui end-user API functions // [SECTION] Flags & Enumerations // [SECTION] Tables API flags and structures (ImGuiTableFlags, ImGuiTableColumnFlags, ImGuiTableRowFlags, ImGuiTableBgTarget, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) -// [SECTION] Helpers: Debug log, Memory allocations macros, ImVector<>, Unreachable +// [SECTION] Helpers: Debug log, Memory allocations macros, ImVector<> // [SECTION] ImGuiStyle // [SECTION] ImGuiIO // [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) @@ -2152,7 +2152,7 @@ struct ImGuiTableColumnSortSpecs }; //----------------------------------------------------------------------------- -// [SECTION] Helpers: Debug log, memory allocations macros, ImVector<>, Unreachable +// [SECTION] Helpers: Debug log, memory allocations macros, ImVector<> //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -2257,37 +2257,6 @@ struct ImVector }; IM_MSVC_RUNTIME_CHECKS_RESTORE -//----------------------------------------------------------------------------- -// ImGui::Unreachable() -// Provides an equivalent for std::unreachable() for C++<23. This signals to the compiler that a region is unreachable, allowing optimizations. -//----------------------------------------------------------------------------- -// If you are using C++>=23, use std::unreachable() in , and you may also define STD_UNREACHABLE_IS_AVAILABLE to substitute definitions. -// Code is from: https://en.cppreference.com/w/cpp/utility/unreachable.html -// Inclusion in the ImGUI namespace is chosen to avoid possible namespace collisions with stdlib >= 23. -//----------------------------------------------------------------------------- -namespace ImGui -{ -//#define STD_UNREACHABLE_IS_AVAILABLE -#ifdef STD_UNREACHABLE_IS_AVAILABLE - #include - constexpr const auto Unreachable = ::std::unreachable; - #undef STD_UNREACHABLE_IS_AVAILABLE -#else - [[noreturn]] inline void Unreachable() - { - // Uses compiler specific extensions if possible. - // Even if no extension is used, undefined behavior is still raised by - // an empty function body and the noreturn attribute. - #if defined(_MSC_VER) && !defined(__clang__) // MSVC - __assume(false); - #else // GCC, Clang - __builtin_unreachable(); - #endif - } -#endif - -} // namespace ImGui - //----------------------------------------------------------------------------- // [SECTION] ImGuiStyle //----------------------------------------------------------------------------- From 75b044c690277bb1c2cd15c15ede4acaaf79754d Mon Sep 17 00:00:00 2001 From: Brayden Lee Date: Mon, 22 Dec 2025 22:54:06 -0500 Subject: [PATCH 5/8] Improve ImVec2 subscript helper --- imgui.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 2c8fecef6cd8..2fd76277e8f1 100644 --- a/imgui.h +++ b/imgui.h @@ -297,8 +297,8 @@ struct ImVec2 float x, y; constexpr ImVec2() : x(0.0f), y(0.0f) { } constexpr ImVec2(float _x, float _y) : x(_x), y(_y) { } - float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(void*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine. - float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const void*)(const char*)this)[idx]; } + float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return idx == 0 ? x : y; } // We very rarely use this [] operator, so the assert overhead is fine. + float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return idx == 0 ? x : y; } #ifdef IM_VEC2_CLASS_EXTRA IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. #endif From 4707b7e732cc35439657e985d8c9a3740a804193 Mon Sep 17 00:00:00 2001 From: Brayden Lee Date: Tue, 23 Dec 2025 14:53:22 -0500 Subject: [PATCH 6/8] Revert "Improve ImVec2 subscript helper" This reverts commit 75b044c690277bb1c2cd15c15ede4acaaf79754d. --- imgui.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 2fd76277e8f1..2c8fecef6cd8 100644 --- a/imgui.h +++ b/imgui.h @@ -297,8 +297,8 @@ struct ImVec2 float x, y; constexpr ImVec2() : x(0.0f), y(0.0f) { } constexpr ImVec2(float _x, float _y) : x(_x), y(_y) { } - float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return idx == 0 ? x : y; } // We very rarely use this [] operator, so the assert overhead is fine. - float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return idx == 0 ? x : y; } + float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(void*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine. + float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const void*)(const char*)this)[idx]; } #ifdef IM_VEC2_CLASS_EXTRA IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. #endif From 4b022e571c522070369bc2b976b5cbfd41e8e89a Mon Sep 17 00:00:00 2001 From: Brayden Lee Date: Tue, 23 Dec 2025 15:08:00 -0500 Subject: [PATCH 7/8] Compile-time check for correct padding and alignment in ImVec2 --- imgui.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 2c8fecef6cd8..3039231042a6 100644 --- a/imgui.h +++ b/imgui.h @@ -76,7 +76,7 @@ Index of this file: // Includes #include // FLT_MIN, FLT_MAX #include // va_list, va_start, va_end -#include // ptrdiff_t, NULL +#include // ptrdiff_t, NULL, offsetof #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp // Define attributes of all API symbols declarations (e.g. for DLL under Windows) @@ -303,6 +303,8 @@ struct ImVec2 IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. #endif }; +static_assert(offsetof(ImVec2, y) - offsetof(ImVec2, x) == sizeof(float), "Cannot compile ImVec2 due to an alignment/padding violation.\ + Please reply to (or start) the issue with your compiler version and flags at https://github.com/ocornut/imgui/issues."); // ImVec4: 4D vector used to store clipping rectangles, colors etc. [Compile-time configurable type] struct ImVec4 From 60a6c7be9800d81c43c251af6fbc9fd47d31a8f9 Mon Sep 17 00:00:00 2001 From: Brayden Lee Date: Tue, 23 Dec 2025 16:30:36 -0500 Subject: [PATCH 8/8] Factor out error message to IM_PADDING_CHECK_FAIL_MSG and check the padding on ImVec4 --- imgui.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 3039231042a6..04772fd2ad56 100644 --- a/imgui.h +++ b/imgui.h @@ -152,6 +152,10 @@ Index of this file: #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif + +#define IM_PADDING_CHECK_FAIL_MSG(TypeName) "Cannot compile "## #TypeName ##" due to an padding assumption violation. \ +Please reply to (or start) the issue with your compiler version and flags at https://github.com/ocornut/imgui/issues." + //----------------------------------------------------------------------------- // [SECTION] Forward declarations and basic types //----------------------------------------------------------------------------- @@ -303,8 +307,7 @@ struct ImVec2 IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. #endif }; -static_assert(offsetof(ImVec2, y) - offsetof(ImVec2, x) == sizeof(float), "Cannot compile ImVec2 due to an alignment/padding violation.\ - Please reply to (or start) the issue with your compiler version and flags at https://github.com/ocornut/imgui/issues."); +static_assert(offsetof(ImVec2, y) - offsetof(ImVec2, x) == sizeof(float), IM_PADDING_CHECK_FAIL_MSG(ImVec2)); // ImVec4: 4D vector used to store clipping rectangles, colors etc. [Compile-time configurable type] struct ImVec4 @@ -316,6 +319,9 @@ struct ImVec4 IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4. #endif }; +// It is guaranteed that struct fields are in order of declaration, i.e. addressof(x) < addressof(y) < addressof(z) < addressof(w) +// This check uses the guarantee to ensure our padding assumption is correct for all members with only one comparison (concise, less error-prone). +static_assert(offsetof(ImVec4, w) - offsetof(ImVec4, x) == 3 * sizeof(float), IM_PADDING_CHECK_FAIL_MSG(ImVec4)); IM_MSVC_RUNTIME_CHECKS_RESTORE //-----------------------------------------------------------------------------