Describe the bug
Just including imgui_internal.h (Dear ImGui v1.92.9b) spins "forever", 100% CPU, memory flat at 54 MB.
| compiler |
|
| oneAPI 2025.1 / .2 / .3 |
ok ~1.5 s |
| v6.2.0 |
ok 0.9 s |
| v7.0.0 |
killed at 300 s |
| nightly-2026-08-17 |
killed at 90 s, i.e. not fixed upstream |
To reproduce
git clone --depth 1 --branch v1.92.9b https://github.com/ocornut/imgui.git
echo '#include "imgui_internal.h"' > repro.cpp
clang++ -fsycl -fsycl-device-only -fsyntax-only -Iimgui repro.cpp
Device pass only. -fsycl-is-host and plain C++ 0.2 s, preprocessing unaffected.
Up to v7.0.0 one cc1 flag on the host triple suffices, no SYCL headers: clang++ -fsyntax-only -Xclang -fsycl-is-device -Iimgui repro.cpp.
Newer nightlies reject a non-SPIR-V triple there, so use -fsycl -fsycl-device-only for cross-version runs.
Including imgui.h alone is fine. Needs the dense mutually-referential graph of ImGuiContext/ImGuiWindow.
Attaching files failed, minimal self-contained (no #include) repro by reducing the header, ill-formed by design (-ferror-limit=0): 0.1 s v6.2.0 vs 2.0 s v7.0.0, 20x slowdown (not hanging):
typedef signed short ImS16;
typedef unsigned short ImU16;
typedef signed int ImS32;
typedef unsigned int ImU32;
typedef signed long long ImS64;
typedef unsigned long long ImU64;
struct ImDrawChannel;
struct ImDrawCmd;
struct ImDrawData;
struct ImDrawList;
struct ImDrawListSharedData;
struct ImDrawListSplitter;
struct ImDrawVert;
struct ImFont;
struct ImFontAtlas;
struct ImFontAtlasBuilder;
struct ImFontConfig;
struct ImFontGlyph;
struct ImFontGlyphRangesBuilder;
struct ImFontLoader;
struct ImTextureData;
struct ImTextureRect;
struct ImGuiSelectionExternalStorage;
struct ImGuiSelectionRequest;
struct ImGuiSizeCallbackData;
struct ImGuiStorage;
enum ImGuiDir : int;
enum ImGuiKey : int;
enum ImGuiMouseSource : int;
enum ImGuiSortDirection : ImU8;
typedef int ImGuiCol;
typedef int ImGuiListClipperFlags;
typedef unsigned short ImWchar16;
template <typename T> struct ImVector {
int Size;
int Capacity;
T *Data;
ImVec2 WindowTitleAlign;
ImGuiDir WindowMenuButtonPosition;
float ChildRounding;
float ChildBorderSize;
float PopupRounding;
ImVec2 DisplayWindowPadding;
ImVec2 DisplaySafeAreaPadding;
float MouseCursorScale;
bool AntiAliasedLines;
bool AntiAliasedLinesUseTex;
bool AntiAliasedFill;
float CurveTessellationTol;
float CircleTessellationMaxError;
ImVec4 Colors[ImGuiCol_COUNT];
float HoverStationaryDelay;
float HoverDelayShort;
float HoverDelayNormal;
ImGuiHoveredFlags HoverFlagsForTooltipMouse;
ImGuiHoveredFlags HoverFlagsForTooltipNav;
ImFontAtlas *Fonts;
ImFont *FontDefault;
void SetStatus(ImTextureStatus status) {
Status = status;
if (status == ImTextureStatus_Destroyed && !WantDestroyNextFrame &&
Pixels != nullptr)
Status = ImTextureStatus_WantCreate;
}
ImFont *DstFont;
const ImFontLoader *FontLoader;
void *FontLoaderData;
ImFontAtlasFlags_NoBakedLines = 1 << 2,
};
struct ImFontAtlas {
ImFontAtlas();
~ImFontAtlas();
ImFont *AddFont(const ImFontConfig *font_cfg);
ImFont *AddFontDefault(const ImFontConfig *font_cfg = 0);
ImVector<ImTextureData *> TexList;
bool RendererHasTextures;
bool TexIsBuilt;
ImVec2 TexUvWhitePixel;
ImVector<ImFont *> Fonts;
ImVector<ImFontConfig> Sources;
ImVec4 TexUvLines[(32) + 1];
int TexNextUniqueID;
int FontNextUniqueID;
ImVector<ImDrawListSharedData *> DrawListSharedDatas;
ImFontAtlasBuilder *Builder;
const ImFontLoader *FontLoader;
const char *FontLoaderName;
void *FontLoaderData;
int RefCount;
ImGuiContext *OwnerContext;
ImVector<float> IndexAdvanceX;
float FallbackAdvanceX;
float Size;
float RasterizerDensity;
ImVector<ImU16> IndexLookup;
ImVector<ImFontGlyph> Glyphs;
int FallbackGlyphIndex;
float Ascent, Descent;
unsigned int MetricsTotalSurface : 26;
unsigned int WantDestroy : 1;
unsigned int LoadNoFallback : 1;
unsigned int LoadNoRenderOnLayout : 1;
int LastUsedFrame;
ImGuiID BakedId;
ImFont *OwnerFont;
};
struct ImFont {
ImFontBaked *LastBaked;
ImFontAtlas *OwnerAtlas;
ImFontFlags Flags;
float CurrentRasterizerDensity;
ImVector<ImFontConfig *> Sources;
}
}
;
struct ImRect {
ImVec2 Min;
ImVec2 Max;
ImVector<ImVec2> TempBuffer;
ImVector<ImDrawList *> DrawLists;
ImVector<ImFontAtlas *> FontAtlases;
ImFont *Font;
ImVector<float> ItemWidthStack;
ImVector<float> TextWrapPosStack;
};
struct ImGuiWindow {
ImGuiWindowFlags Flags;
ImRect OuterRectClipped;
ImRect InnerRect;
ImRect InnerClipRect;
ImRect WorkRect;
ImRect ParentWorkRect;
ImRect ClipRect;
ImGuiWindow *ParentWindow;
ImGuiWindow *ParentWindowInBeginStack;
ImGuiWindow *RootWindow;
ImGuiWindow *RootWindowPopupTree;
};
ImGuiWindow *OuterWindow;
Environment
- OS: independent
- Target device and vendor: N/A, frontend only
- DPC++ version: bisected
last good: nightly-2025-09-24 3276ddd75dae5563f336737daddcbb151484702b
first bad: nightly-2025-09-30 0ff1a5c2b4e4bc56799ec2dd17a89c3c57608890
Additional context
Hypothesis from Claude:
checkSYCLType() in clang/lib/Sema/SemaSYCL.cpp, from SemaSYCL::checkSYCLDeviceVarDecl, device mode only. Walks all fields, follows pointers/arrays into the pointee's fields. Visited passed by value => memoizes per DFS path, not globally => enumerates simple paths instead of visiting each type once. See #17313 (open, wants checkSYCLType merged into Sema::checkTypeSupport); mentions no perf impact, but same function.
Exponential in both versions: on v6.2.0, nesting struct W { ImGuiContext* a; ImGuiContext* b; };
N deep multiplies time by ~1.8/level (0.7, 0.9, 1.3, 2.0, 3.7 s). So not a new loop — something in the Sept 2025 window weakened dedup enough to push ImGui's graph past any usable threshold;
v6.2.0 needs ~9 extra doublings to reach v7.0.0.
Describe the bug
Just including
imgui_internal.h(Dear ImGui v1.92.9b) spins "forever", 100% CPU, memory flat at 54 MB.To reproduce
Device pass only.
-fsycl-is-hostand plain C++ 0.2 s, preprocessing unaffected.Up to v7.0.0 one cc1 flag on the host triple suffices, no SYCL headers:
clang++ -fsyntax-only -Xclang -fsycl-is-device -Iimgui repro.cpp.Newer nightlies reject a non-SPIR-V triple there, so use
-fsycl -fsycl-device-onlyfor cross-version runs.Including
imgui.halone is fine. Needs the dense mutually-referential graph ofImGuiContext/ImGuiWindow.Attaching files failed, minimal self-contained (no
#include) repro by reducing the header, ill-formed by design (-ferror-limit=0): 0.1 s v6.2.0 vs 2.0 s v7.0.0, 20x slowdown (not hanging):Environment
Additional context
Hypothesis from Claude:
checkSYCLType()in clang/lib/Sema/SemaSYCL.cpp, fromSemaSYCL::checkSYCLDeviceVarDecl, device mode only. Walks all fields, follows pointers/arrays into the pointee's fields.Visitedpassed by value => memoizes per DFS path, not globally => enumerates simple paths instead of visiting each type once. See #17313 (open, wants checkSYCLType merged intoSema::checkTypeSupport); mentions no perf impact, but same function.Exponential in both versions: on v6.2.0, nesting
struct W { ImGuiContext* a; ImGuiContext* b; };N deep multiplies time by ~1.8/level (0.7, 0.9, 1.3, 2.0, 3.7 s). So not a new loop — something in the Sept 2025 window weakened dedup enough to push ImGui's graph past any usable threshold;
v6.2.0 needs ~9 extra doublings to reach v7.0.0.