[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:36:15 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/3] [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/3] 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; }

>From fe51b3644be5f17a8e28864770311d852a0d1919 Mon Sep 17 00:00:00 2001
From: ViNN280801 <vladislav.semykin at gmail.com>
Date: Sun, 3 May 2026 19:32:47 +0300
Subject: [PATCH 3/3] [Clang][Sema] Moved test to appropriate file

Signed-off-by: ViNN280801 <vladislav.semykin at gmail.com>
---
 .../SemaCXX/builtin-dump-struct-immediate.cpp | 21 ------------------
 clang/test/SemaCXX/cxx2a-consteval.cpp        | 22 +++++++++++++++++++
 2 files changed, 22 insertions(+), 21 deletions(-)
 delete mode 100644 clang/test/SemaCXX/builtin-dump-struct-immediate.cpp

diff --git a/clang/test/SemaCXX/builtin-dump-struct-immediate.cpp b/clang/test/SemaCXX/builtin-dump-struct-immediate.cpp
deleted file mode 100644
index 79a24882f6df6..0000000000000
--- a/clang/test/SemaCXX/builtin-dump-struct-immediate.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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);
-}
diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp
index 6440a4e85df83..5b9d720e8242d 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -1344,3 +1344,25 @@ void g() {
     f<int>();
 }
 }  // namespace GH156579
+
+namespace GH192846 {
+// Regression 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);
+}
+}  // namespace GH192846



More information about the cfe-commits mailing list