diff --git a/lldb/source/Expression/UserExpression.cpp b/lldb/source/Expression/UserExpression.cpp --- a/lldb/source/Expression/UserExpression.cpp +++ b/lldb/source/Expression/UserExpression.cpp @@ -187,7 +187,12 @@ } } - if (process == nullptr || !process->CanJIT()) + // Explicitly force the IR interpreter to evaluate the expression when the + // there is no process that supports running the expression for us. Don't + // change the execution policy if we have the special top-level policy that + // doesn't contain any expression and there is nothing to interpret. + if (execution_policy != eExecutionPolicyTopLevel && + (process == nullptr || !process->CanJIT())) execution_policy = eExecutionPolicyNever; // We need to set the expression execution thread here, turns out parse can diff --git a/lldb/test/API/commands/expression/static-initializers/TestStaticInitializers.py b/lldb/test/API/commands/expression/static-initializers/TestStaticInitializers.py --- a/lldb/test/API/commands/expression/static-initializers/TestStaticInitializers.py +++ b/lldb/test/API/commands/expression/static-initializers/TestStaticInitializers.py @@ -31,3 +31,8 @@ # FIXME: This error message is not even remotely helpful. self.expect("expr -p -- struct Foo2 { Foo2() { do_abort(); } }; Foo2 f;", error=True, substrs=["error: couldn't run static initializer:"]) + + def test_without_process(self): + """ Test a static initializer without a running process. """ + self.expect("expr -p -- int i = 0; struct Foo3 { Foo3() { ++i; } }; Foo3 f;", error=True, + substrs=["Top-level code needs to be inserted into a runnable target"]) diff --git a/lldb/test/API/commands/expression/top-level/TestTopLevelExprs.py b/lldb/test/API/commands/expression/top-level/TestTopLevelExprs.py --- a/lldb/test/API/commands/expression/top-level/TestTopLevelExprs.py +++ b/lldb/test/API/commands/expression/top-level/TestTopLevelExprs.py @@ -91,3 +91,14 @@ self.assertEqual( resultFromCode, resultFromTopLevel.GetValueAsUnsigned()) + + def test_top_level_expression_without_target(self): + self.expect("expr --top-level -- void func() {}", error=True, + substrs=["Top-level code needs to be inserted into a runnable target"]) + + # FIXME: This doesn't actually generate any code, so LLDB should probably + # allow these expressions. + self.expect("expr --top-level -- template struct StructT { T m; };", error=True, + substrs=["Top-level code needs to be inserted into a runnable target"]) + self.expect("expr --top-level -- struct Struct { int i; };", error=True, + substrs=["Top-level code needs to be inserted into a runnable target"]) diff --git a/lldb/test/API/lang/cpp/elaborated-types/TestElaboratedTypes.py b/lldb/test/API/lang/cpp/elaborated-types/TestElaboratedTypes.py --- a/lldb/test/API/lang/cpp/elaborated-types/TestElaboratedTypes.py +++ b/lldb/test/API/lang/cpp/elaborated-types/TestElaboratedTypes.py @@ -34,7 +34,7 @@ # Declare a template that can actually be instantiated. # FIXME: The error message here is incorrect. self.expect("expr --top-level -- template struct $V {};", - error=True, substrs=["Couldn't find $__lldb_expr() in the module"]) + error=True, substrs=["Top-level code needs to be inserted into a runnable target"]) result = self.expect_expr("$V<::Struct> s; s", result_type="$V< ::Struct>") self.assertEqual(result.GetTypeName(), "$V")