[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