llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Jonas Rembser (guitargeek)
<details>
<summary>Changes</summary>
convertExprToValue() strips the ExprWithCleanups of the printed expression and
builds the call of __clang_Interpreter_SetValue* around the subexpression,
without the cleanups. The temporaries of the expression then belong to no
full-expression: CodeGen destroys them at the end of the function that runs the
top-level statements, which it finishes after it has emitted the deferred
declarations, so their destructors are referenced but never emitted:
clang-repl> struct S { ~S() {} };
clang-repl> int f(S) { return 42; }
clang-repl> f(S())
JIT session error: Symbols not found: [ _ZN1SD1Ev ]
(with an assertions build, moveLazyEmissionStates() asserts instead).
Put the cleanups back around the result, so that the temporaries are destroyed
at the end of their statement. If the call cannot be built, return the original
expression with its cleanups.
Assisted-by: Claude Opus 5.5
---
Full diff: https://github.com/llvm/llvm-project/pull/229675.diff
2 Files Affected:
- (modified) clang/lib/Interpreter/InterpreterValuePrinter.cpp (+16-5)
- (added) clang/test/Interpreter/value-print-temporaries.cpp (+25)
``````````diff
diff --git a/clang/lib/Interpreter/InterpreterValuePrinter.cpp
b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
index 6842656e87f44..666d078ccd83e 100644
--- a/clang/lib/Interpreter/InterpreterValuePrinter.cpp
+++ b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
@@ -528,8 +528,10 @@ llvm::Expected<Expr *>
Interpreter::convertExprToValue(Expr *E) {
// Build `__clang_Interpreter_SetValue*` call.
- // Get rid of ExprWithCleanups.
- if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(E))
+ // Get rid of ExprWithCleanups; it is put back around the result below.
+ Expr *FullExpr = E;
+ auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(E);
+ if (EWC)
E = EWC->getSubExpr();
QualType Ty = E->IgnoreImpCasts()->getType();
@@ -630,9 +632,18 @@ llvm::Expected<Expr *>
Interpreter::convertExprToValue(Expr *E) {
// It could fail, like printing an array type in C. (not supported)
if (SetValueE.isInvalid())
- return E;
-
- return SetValueE.get();
+ return FullExpr;
+
+ // The temporaries of E must be destroyed at the end of the statement.
+ // Without the cleanups, CodeGen destroys them at the end of the function
+ // running the top-level statements, which it finishes after emitting the
+ // deferred declarations: their destructors would not be emitted.
+ Expr *Result = SetValueE.get();
+ if (EWC && !isa<ExprWithCleanups>(Result))
+ Result = ExprWithCleanups::Create(Ctx, Result,
+ EWC->cleanupsHaveSideEffects(),
+ EWC->getObjects());
+ return Result;
}
} // namespace clang
diff --git a/clang/test/Interpreter/value-print-temporaries.cpp
b/clang/test/Interpreter/value-print-temporaries.cpp
new file mode 100644
index 0000000000000..e826636a4a30c
--- /dev/null
+++ b/clang/test/Interpreter/value-print-temporaries.cpp
@@ -0,0 +1,25 @@
+// The temporaries of a printed expression are destroyed at the end of its
+// statement, and their destructors are emitted.
+//
+// RUN: cat %s | clang-repl | FileCheck %s
+
+int Dtors = 0;
+struct S { ~S() { ++Dtors; } };
+int f(S) { return 42; }
+
+f(S())
+// CHECK: (int) 42
+
+Dtors
+// CHECK-NEXT: (int) 1
+
+struct R { int I; ~R() { ++Dtors; } };
+R g(const S &) { return R{7}; }
+
+g(S()).I
+// CHECK-NEXT: (int) 7
+
+Dtors
+// CHECK-NEXT: (int) 3
+
+%quit
``````````
</details>
https://github.com/llvm/llvm-project/pull/229675
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits