[clang] [Clang][Sema] Fix crash in __builtin_dump_struct with immediate callables (PR #192880)

Vladislav Semykin via cfe-commits cfe-commits at lists.llvm.org
Sun May 3 09:24:30 PDT 2026


https://github.com/ViNN280801 updated https://github.com/llvm/llvm-project/pull/192880

>From 46368365bef159edc85b8e1e68def67a93db9889 Mon Sep 17 00:00:00 2001
From: ViNN280801 <vladislav.semykin at gmail.com>
Date: Mon, 20 Apr 2026 23:02:07 +0300
Subject: [PATCH 1/2] [Clang][Sema] Fix crash in __builtin_dump_struct with
 immediate callables

__builtin_dump_struct binds its record argument to an OpaqueValueExpr
inside a PseudoObjectExpr. When the callable is immediate-escalated,
ComplexRemove (used to strip nested immediate-invocation wrappers) is
rooted at the synthesized CallExpr within the PSE's semantic form and
reaches the OVE without traversing the PSE's binding, triggering the
assert in TreeTransform::TransformOpaqueValueExpr.

Override TransformOpaqueValueExpr in ComplexRemove to return the OVE
unchanged; the PSE owner preserves the binding.

Fixes #192846

Signed-off-by: ViNN280801 <vladislav.semykin at gmail.com>
---
 clang/docs/ReleaseNotes.rst                   |  2 ++
 clang/lib/Sema/SemaExpr.cpp                   |  9 ++++++++
 .../SemaCXX/builtin-dump-struct-immediate.cpp | 21 +++++++++++++++++++
 3 files changed, 32 insertions(+)
 create mode 100644 clang/test/SemaCXX/builtin-dump-struct-immediate.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 638a813ca105b..8df1469ec8c78 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -527,6 +527,8 @@ Miscellaneous Clang Crashes Fixed
 - Fixed an assertion failure when parsing an invalid out-of-line enum definition with template parameters. (#GH187909)
 - Fixed an assertion failure on invalid template template parameter during typo correction. (#GH183983)
 - Fixed an assertion failure in ``isAtEndOfMacroExpansion`` on macro expansions crossing the boundary of two fileIDs. (#GH115007), (#GH21755)
+- Fixed an assertion failure when ``__builtin_dump_struct`` is used with an
+  immediate-escalated callable. (#GH192846)
 
 OpenACC Specific Changes
 ------------------------
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index cf235095d489d..ad8908a5c0c0f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18463,6 +18463,15 @@ static void RemoveNestedImmediateInvocation(
       // Lambdas have already been processed inside their eval contexts.
       return E;
     }
+
+    // Default TransformOpaqueValueExpr asserts on OVEs that have a SourceExpr.
+    // __builtin_dump_struct binds the record pointer in an OpaqueValueExpr
+    // inside a PseudoObjectExpr; ComplexRemove can root inside the PSE's
+    // semantic form and reach that OVE without the binding setup the assert
+    // expects. The PSE owns the binding; nothing under ComplexRemove needs to
+    // rebuild the OVE's source here.
+    ExprResult TransformOpaqueValueExpr(OpaqueValueExpr *E) { return E; }
+
     bool AlwaysRebuild() { return false; }
     bool ReplacingOriginal() { return true; }
     bool AllowSkippingCXXConstructExpr() {
diff --git a/clang/test/SemaCXX/builtin-dump-struct-immediate.cpp b/clang/test/SemaCXX/builtin-dump-struct-immediate.cpp
new file mode 100644
index 0000000000000..79a24882f6df6
--- /dev/null
+++ b/clang/test/SemaCXX/builtin-dump-struct-immediate.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// Regression test for GH192846: the default TransformOpaqueValueExpr
+// asserts on OVEs bound by __builtin_dump_struct when the printing
+// callback is immediate-escalated. ComplexRemove must not reach that
+// path.
+
+struct S {};
+
+consteval void F(S &out, const char *fmt, ...) {}
+
+template <class T>
+class C { T value = {}; };
+
+constexpr C<int> g_c{};
+
+void bar() {
+  S s;
+  __builtin_dump_struct(&g_c, F, s);
+}

>From 23663c637cce6c8e2a9a03efb6c7d9802658d3ca Mon Sep 17 00:00:00 2001
From: Vladislav Semykin <34096407+ViNN280801 at users.noreply.github.com>
Date: Sun, 3 May 2026 19:24:20 +0300
Subject: [PATCH 2/2] Update clang/lib/Sema/SemaExpr.cpp

Co-authored-by: Corentin Jabot <corentinjabot at gmail.com>
---
 clang/lib/Sema/SemaExpr.cpp | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ad8908a5c0c0f..4548f5c3c18e3 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18464,12 +18464,8 @@ static void RemoveNestedImmediateInvocation(
       return E;
     }
 
-    // Default TransformOpaqueValueExpr asserts on OVEs that have a SourceExpr.
-    // __builtin_dump_struct binds the record pointer in an OpaqueValueExpr
-    // inside a PseudoObjectExpr; ComplexRemove can root inside the PSE's
-    // semantic form and reach that OVE without the binding setup the assert
-    // expects. The PSE owns the binding; nothing under ComplexRemove needs to
-    // rebuild the OVE's source here.
+    // We do not have enough information to transform opaque expressions and
+    // assume they do not contain immediate subexpressions.
     ExprResult TransformOpaqueValueExpr(OpaqueValueExpr *E) { return E; }
 
     bool AlwaysRebuild() { return false; }



More information about the cfe-commits mailing list