[Lldb-commits] [lldb] [lldb][Expression] Emit a 'Note' diagnostic that indicates the language used for expression evaluation (PR #161688)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Thu Oct 9 01:19:10 PDT 2025
https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/161688
>From b35fda979bd1be47f8bf943a70dc38549d371f51 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 6 Oct 2025 09:48:28 +0100
Subject: [PATCH 1/8] [lldb][Language] Make SourceLanguage::GetDescription for
language version
This makes sure we also include the version number in the description.
For `C++17`, this would, e.g., now return `"C++17"` instead of `"ISO C++"`.
---
lldb/unittests/Target/LanguageTest.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lldb/unittests/Target/LanguageTest.cpp b/lldb/unittests/Target/LanguageTest.cpp
index 720863bda68e4..a882d70b7e120 100644
--- a/lldb/unittests/Target/LanguageTest.cpp
+++ b/lldb/unittests/Target/LanguageTest.cpp
@@ -40,8 +40,10 @@ TEST_F(LanguageTest, SourceLanguage_GetDescription) {
EXPECT_EQ(SourceLanguage(eLanguageTypeC_plus_plus_20).GetDescription(),
"C++20");
- EXPECT_EQ(SourceLanguage(eLanguageTypeC).GetDescription(), "C (K&R and ISO)");
- EXPECT_EQ(SourceLanguage(eLanguageTypeC89).GetDescription(), "C89");
+ EXPECT_EQ(SourceLanguage(eLanguageTypeC).GetDescription(),
+ "C (K&R and ISO)");
+ EXPECT_EQ(SourceLanguage(eLanguageTypeC89).GetDescription(),
+ "C89");
EXPECT_EQ(SourceLanguage(eLanguageTypeObjC).GetDescription(), "Objective C");
EXPECT_EQ(SourceLanguage(eLanguageTypeMipsAssembler).GetDescription(),
>From c8497da2dcaaaa7a6d722998758a53027458312a Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 2 Oct 2025 16:24:12 +0100
Subject: [PATCH 2/8] [lldb][Expression] Emit a 'Note' diagnistc that indicates
the language used for expression evaluation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Since it's a 'Note' diagnostic it would only show up when expression
evaluation actually failed. This helps with expression evaluation
failure reports in mixed language environments where it's not quite clear
what language the expression ran as. It may also reduce confusion around
why the expression evaluator ran an expression in a language it wasn't
asked to run (a softer alternative to what I attempted in https://github.com/llvm/llvm-project/pull/156648).
Here are some example outputs:
```
(lldb) expr -l c -- blah
˄
╰─ error: use of undeclared identifier 'blah'
note: Requested expression evaluation as 'c' but fell back to 'c++'.
(lldb) expr -l c++ -- blah
˄
╰─ error: use of undeclared identifier 'blah'
note: Requested expression evaluation as c++
(lldb) expr -l objc -- blah
˄
╰─ error: use of undeclared identifier 'blah'
note: Requested expression evaluation as 'objective-c' but fell back to 'objective-c++'.
(lldb) expr -l rust -- blah
˄
╰─ error: use of undeclared identifier 'blah'
note: Requested expression evaluation as rust
```
I didn't put the diagnostic on the same line as the inline diagnostic
for now because of implementation convenience, but if reviewers deem
that a blocker I can take a stab at that again.
Also, other language plugins (namely Swift), won't immediately benefit
from this and will have to emit their own diagnistc. I played around
with having a virtual API on `UserExpression` or `ExpressionParser` that
will be called consistently, but by the time we're about to parse the
expression we are already several frames deep into the plugin. Before
(and at the beginning of) the generic `UserExpression::Parse` call we
don't have enough information to notify which language we're going to
parse in (at least for the C++ plugin).
rdar://160297649
---
.../Clang/ClangExpressionParser.cpp | 29 ++++++++++++++++---
.../Clang/ClangExpressionParser.h | 1 +
.../Clang/ClangFunctionCaller.cpp | 4 +--
.../Clang/ClangUserExpression.cpp | 4 +--
.../Clang/ClangUtilityFunction.cpp | 2 +-
5 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 3c49c911108a3..b3aebfcc77039 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -74,6 +74,7 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
+#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRInterpreter.h"
#include "lldb/Host/File.h"
@@ -527,7 +528,8 @@ static void SetupTargetOpts(CompilerInstance &compiler,
static void SetupLangOpts(CompilerInstance &compiler,
ExecutionContextScope &exe_scope,
- const Expression &expr) {
+ const Expression &expr,
+ DiagnosticManager &diagnostic_manager) {
Log *log = GetLog(LLDBLog::Expressions);
// If the expression is being evaluated in the context of an existing stack
@@ -547,6 +549,8 @@ static void SetupLangOpts(CompilerInstance &compiler,
: lldb::eLanguageTypeUnknown),
lldb_private::Language::GetNameForLanguageType(language));
+ lldb::LanguageType language_for_note = language;
+
LangOptions &lang_opts = compiler.getLangOpts();
switch (language) {
@@ -560,12 +564,14 @@ static void SetupLangOpts(CompilerInstance &compiler,
// family language, because the expression parser uses features of C++ to
// capture values.
lang_opts.CPlusPlus = true;
+ language_for_note = lldb::eLanguageTypeC_plus_plus;
break;
case lldb::eLanguageTypeObjC:
lang_opts.ObjC = true;
// FIXME: the following language option is a temporary workaround,
// to "ask for ObjC, get ObjC++" (see comment above).
lang_opts.CPlusPlus = true;
+ language_for_note = lldb::eLanguageTypeObjC_plus_plus;
// Clang now sets as default C++14 as the default standard (with
// GNU extensions), so we do the same here to avoid mismatches that
@@ -610,6 +616,21 @@ static void SetupLangOpts(CompilerInstance &compiler,
break;
}
+ if (language_for_note != language)
+ diagnostic_manager.AddDiagnostic(
+ llvm::formatv(
+ "Requested expression evaluation as '{0}' but fell back to '{1}'.",
+ lldb_private::Language::GetNameForLanguageType(language),
+ lldb_private::Language::GetNameForLanguageType(language_for_note))
+ .str(),
+ lldb::Severity::eSeverityInfo, DiagnosticOrigin::eDiagnosticOriginLLDB);
+ else
+ diagnostic_manager.AddDiagnostic(
+ llvm::formatv("Requested expression evaluation as '{0}'",
+ lldb_private::Language::GetNameForLanguageType(language))
+ .str(),
+ lldb::Severity::eSeverityInfo, DiagnosticOrigin::eDiagnosticOriginLLDB);
+
lang_opts.Bool = true;
lang_opts.WChar = true;
lang_opts.Blocks = true;
@@ -687,8 +708,8 @@ static void SetupImportStdModuleLangOpts(CompilerInstance &compiler,
ClangExpressionParser::ClangExpressionParser(
ExecutionContextScope *exe_scope, Expression &expr,
- bool generate_debug_info, std::vector<std::string> include_directories,
- std::string filename)
+ bool generate_debug_info, DiagnosticManager &diagnostic_manager,
+ std::vector<std::string> include_directories, std::string filename)
: ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(),
m_pp_callbacks(nullptr),
m_include_directories(std::move(include_directories)),
@@ -754,7 +775,7 @@ ClangExpressionParser::ClangExpressionParser(
}
// 4. Set language options.
- SetupLangOpts(*m_compiler, *exe_scope, expr);
+ SetupLangOpts(*m_compiler, *exe_scope, expr, diagnostic_manager);
auto *clang_expr = dyn_cast<ClangUserExpression>(&m_expr);
if (clang_expr && clang_expr->DidImportCxxModules()) {
LLDB_LOG(log, "Adding lang options for importing C++ modules");
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
index 93e0b007dbcc8..734ad51c9646e 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
@@ -65,6 +65,7 @@ class ClangExpressionParser : public ExpressionParser {
/// diagnostics (i.e. errors, warnings or notes from Clang).
ClangExpressionParser(ExecutionContextScope *exe_scope, Expression &expr,
bool generate_debug_info,
+ DiagnosticManager &diagnostic_manager,
std::vector<std::string> include_directories = {},
std::string filename = "<clang expression>");
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
index e4a094f3aa512..d2db319afb7a0 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
@@ -189,8 +189,8 @@ ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp,
lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
if (jit_process_sp) {
const bool generate_debug_info = true;
- auto *clang_parser = new ClangExpressionParser(jit_process_sp.get(), *this,
- generate_debug_info);
+ auto *clang_parser = new ClangExpressionParser(
+ jit_process_sp.get(), *this, generate_debug_info, diagnostic_manager);
num_errors = clang_parser->Parse(diagnostic_manager);
m_parser.reset(clang_parser);
} else {
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index 6b743e29e21f6..e8d5ec3c7fd96 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -574,7 +574,7 @@ bool ClangUserExpression::TryParse(
m_parser = std::make_unique<ClangExpressionParser>(
exe_ctx.GetBestExecutionContextScope(), *this, generate_debug_info,
- m_include_directories, m_filename);
+ diagnostic_manager, m_include_directories, m_filename);
unsigned num_errors = m_parser->Parse(diagnostic_manager);
@@ -818,7 +818,7 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx,
}
ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,
- false);
+ false, diagnostic_manager);
// We have to find the source code location where the user text is inside
// the transformed expression code. When creating the transformed text, we
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
index 1f44200c4cff8..e6983066a12fa 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
@@ -120,7 +120,7 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager,
const bool generate_debug_info = true;
ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,
- generate_debug_info);
+ generate_debug_info, diagnostic_manager);
unsigned num_errors = parser.Parse(diagnostic_manager);
>From abb1328582f3e6c9f66b419a27a6b6c98fe9eee8 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Fri, 3 Oct 2025 09:29:17 +0100
Subject: [PATCH 3/8] fixup! reword diagnostic; use
GetDisplayNameForLanguageType
---
.../ExpressionParser/Clang/ClangExpressionParser.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index b3aebfcc77039..a94bf475e0ece 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -619,15 +619,15 @@ static void SetupLangOpts(CompilerInstance &compiler,
if (language_for_note != language)
diagnostic_manager.AddDiagnostic(
llvm::formatv(
- "Requested expression evaluation as '{0}' but fell back to '{1}'.",
- lldb_private::Language::GetNameForLanguageType(language),
- lldb_private::Language::GetNameForLanguageType(language_for_note))
+ "Requested expression evaluation in '{0}' is not supported. Used '{1}' instead.",
+ lldb_private::Language::GetDisplayNameForLanguageType(language),
+ lldb_private::Language::GetDisplayNameForLanguageType(language_for_note))
.str(),
lldb::Severity::eSeverityInfo, DiagnosticOrigin::eDiagnosticOriginLLDB);
else
diagnostic_manager.AddDiagnostic(
- llvm::formatv("Requested expression evaluation as '{0}'",
- lldb_private::Language::GetNameForLanguageType(language))
+ llvm::formatv("Requested expression evaluation as '{0}'.",
+ lldb_private::Language::GetDisplayNameForLanguageType(language))
.str(),
lldb::Severity::eSeverityInfo, DiagnosticOrigin::eDiagnosticOriginLLDB);
>From 4022bdc511c5876184972209e749c2bb53b32f38 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Fri, 3 Oct 2025 09:30:05 +0100
Subject: [PATCH 4/8] fixup! clang-format
---
.../ExpressionParser/Clang/ClangExpressionParser.cpp | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index a94bf475e0ece..347dfd166be95 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -619,15 +619,18 @@ static void SetupLangOpts(CompilerInstance &compiler,
if (language_for_note != language)
diagnostic_manager.AddDiagnostic(
llvm::formatv(
- "Requested expression evaluation in '{0}' is not supported. Used '{1}' instead.",
+ "Requested expression evaluation in '{0}' is not supported. Used "
+ "'{1}' instead.",
lldb_private::Language::GetDisplayNameForLanguageType(language),
- lldb_private::Language::GetDisplayNameForLanguageType(language_for_note))
+ lldb_private::Language::GetDisplayNameForLanguageType(
+ language_for_note))
.str(),
lldb::Severity::eSeverityInfo, DiagnosticOrigin::eDiagnosticOriginLLDB);
else
diagnostic_manager.AddDiagnostic(
- llvm::formatv("Requested expression evaluation as '{0}'.",
- lldb_private::Language::GetDisplayNameForLanguageType(language))
+ llvm::formatv(
+ "Requested expression evaluation as '{0}'.",
+ lldb_private::Language::GetDisplayNameForLanguageType(language))
.str(),
lldb::Severity::eSeverityInfo, DiagnosticOrigin::eDiagnosticOriginLLDB);
>From 7e5f166182ae2e72977d372dd55805220043f405 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Sat, 4 Oct 2025 00:42:34 +0100
Subject: [PATCH 5/8] fixup! fix tests+reword diagnostics
---
.../Clang/ClangExpressionParser.cpp | 34 ++++++-------
.../diagnostics/TestExprDiagnostics.py | 10 ++--
.../interpreter/TestCommandInterpreterAPI.py | 48 +++++++++++++++----
3 files changed, 62 insertions(+), 30 deletions(-)
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 347dfd166be95..7eb13dc8e9dd5 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -97,6 +97,7 @@
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
#include "Plugins/Platform/MacOSX/PlatformDarwin.h"
#include "lldb/Utility/XcodeSDK.h"
+#include "lldb/lldb-enumerations.h"
#include <cctype>
#include <memory>
@@ -550,6 +551,7 @@ static void SetupLangOpts(CompilerInstance &compiler,
lldb_private::Language::GetNameForLanguageType(language));
lldb::LanguageType language_for_note = language;
+ llvm::StringRef language_fallback_reason;
LangOptions &lang_opts = compiler.getLangOpts();
@@ -564,14 +566,20 @@ static void SetupLangOpts(CompilerInstance &compiler,
// family language, because the expression parser uses features of C++ to
// capture values.
lang_opts.CPlusPlus = true;
+
language_for_note = lldb::eLanguageTypeC_plus_plus;
+ language_fallback_reason =
+ "Expression evaluation in pure C not supported. ";
break;
case lldb::eLanguageTypeObjC:
lang_opts.ObjC = true;
// FIXME: the following language option is a temporary workaround,
// to "ask for ObjC, get ObjC++" (see comment above).
lang_opts.CPlusPlus = true;
+
language_for_note = lldb::eLanguageTypeObjC_plus_plus;
+ language_fallback_reason =
+ "Expression evaluation in pure Objective-C not supported. ";
// Clang now sets as default C++14 as the default standard (with
// GNU extensions), so we do the same here to avoid mismatches that
@@ -613,26 +621,18 @@ static void SetupLangOpts(CompilerInstance &compiler,
lang_opts.CPlusPlus = true;
lang_opts.CPlusPlus11 = true;
compiler.getHeaderSearchOpts().UseLibcxx = true;
+
+ language_for_note = lldb::eLanguageTypeObjC_plus_plus;
+ language_fallback_reason = "Using default language. ";
break;
}
- if (language_for_note != language)
- diagnostic_manager.AddDiagnostic(
- llvm::formatv(
- "Requested expression evaluation in '{0}' is not supported. Used "
- "'{1}' instead.",
- lldb_private::Language::GetDisplayNameForLanguageType(language),
- lldb_private::Language::GetDisplayNameForLanguageType(
- language_for_note))
- .str(),
- lldb::Severity::eSeverityInfo, DiagnosticOrigin::eDiagnosticOriginLLDB);
- else
- diagnostic_manager.AddDiagnostic(
- llvm::formatv(
- "Requested expression evaluation as '{0}'.",
- lldb_private::Language::GetDisplayNameForLanguageType(language))
- .str(),
- lldb::Severity::eSeverityInfo, DiagnosticOrigin::eDiagnosticOriginLLDB);
+ diagnostic_manager.AddDiagnostic(
+ llvm::formatv("{0}Ran expression as '{1}'.", language_fallback_reason,
+ lldb_private::Language::GetDisplayNameForLanguageType(
+ language_for_note))
+ .str(),
+ lldb::Severity::eSeverityInfo, DiagnosticOrigin::eDiagnosticOriginLLDB);
lang_opts.Bool = true;
lang_opts.WChar = true;
diff --git a/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py b/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py
index 0cc505aedc4be..5150ba6a630ad 100644
--- a/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py
+++ b/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py
@@ -215,8 +215,12 @@ def check_error(diags):
details = diags.GetValueForKey("details")
- # Detail 1/2: undeclared 'a'
+ # Detail 1/3: note: requested expression language
diag = details.GetItemAtIndex(0)
+ self.assertEqual(str(diag.GetValueForKey("severity")), "note")
+
+ # Detail 2/3: undeclared 'a'
+ diag = details.GetItemAtIndex(1)
severity = diag.GetValueForKey("severity")
message = diag.GetValueForKey("message")
@@ -234,8 +238,8 @@ def check_error(diags):
self.assertFalse(hidden.GetBooleanValue())
self.assertTrue(in_user_input.GetBooleanValue())
- # Detail 1/2: undeclared 'b'
- diag = details.GetItemAtIndex(1)
+ # Detail 3/3: undeclared 'b'
+ diag = details.GetItemAtIndex(2)
message = diag.GetValueForKey("message")
self.assertIn("undeclared identifier 'b'", str(message))
diff --git a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
index 1029bdc3096d0..74ae46b50774d 100644
--- a/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
+++ b/lldb/test/API/python_api/interpreter/TestCommandInterpreterAPI.py
@@ -156,13 +156,15 @@ def test_get_transcript(self):
self.assertEqual(transcript[0]["error"], "")
# (lldb) an-unknown-command
- self.assertEqual(transcript[1],
+ self.assertEqual(
+ transcript[1],
{
"command": "an-unknown-command",
# Unresolved commands don't have "commandName"/"commandArguments"
"output": "",
"error": "error: 'an-unknown-command' is not a valid command.\n",
- })
+ },
+ )
# (lldb) br s -f main.c -l <line>
self.assertEqual(transcript[2]["command"], "br s -f main.c -l %d" % self.line)
@@ -175,14 +177,17 @@ def test_get_transcript(self):
self.assertEqual(transcript[2]["error"], "")
# (lldb) p a
- self.assertEqual(transcript[3],
+ self.assertEqual(
+ transcript[3],
{
"command": "p a",
"commandName": "dwim-print",
"commandArguments": "-- a",
"output": "",
- "error": "error: <user expression 0>:1:1: use of undeclared identifier 'a'\n 1 | a\n | ^\n",
- })
+ "error": "note: Using default language. Ran expression as 'Objective C++'.\n"
+ "error: <user expression 0>:1:1: use of undeclared identifier 'a'\n 1 | a\n | ^\n",
+ },
+ )
# (lldb) statistics dump
self.assertEqual(transcript[4]["command"], "statistics dump")
@@ -203,7 +208,10 @@ def test_save_transcript_setting_default(self):
self.assertTrue(ci, VALID_COMMAND_INTERPRETER)
# The setting's default value should be "false"
- self.runCmd("settings show interpreter.save-transcript", "interpreter.save-transcript (boolean) = false\n")
+ self.runCmd(
+ "settings show interpreter.save-transcript",
+ "interpreter.save-transcript (boolean) = false\n",
+ )
def test_save_transcript_setting_off(self):
ci = self.dbg.GetCommandInterpreter()
@@ -250,17 +258,37 @@ def test_get_transcript_returns_copy(self):
structured_data_1 = ci.GetTranscript()
self.assertTrue(structured_data_1.IsValid())
self.assertEqual(structured_data_1.GetSize(), 1)
- self.assertEqual(structured_data_1.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100), "version")
+ self.assertEqual(
+ structured_data_1.GetItemAtIndex(0)
+ .GetValueForKey("command")
+ .GetStringValue(100),
+ "version",
+ )
# Run some more commands and get the transcript as structured data again
self.runCmd("help")
structured_data_2 = ci.GetTranscript()
self.assertTrue(structured_data_2.IsValid())
self.assertEqual(structured_data_2.GetSize(), 2)
- self.assertEqual(structured_data_2.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100), "version")
- self.assertEqual(structured_data_2.GetItemAtIndex(1).GetValueForKey("command").GetStringValue(100), "help")
+ self.assertEqual(
+ structured_data_2.GetItemAtIndex(0)
+ .GetValueForKey("command")
+ .GetStringValue(100),
+ "version",
+ )
+ self.assertEqual(
+ structured_data_2.GetItemAtIndex(1)
+ .GetValueForKey("command")
+ .GetStringValue(100),
+ "help",
+ )
# Now, the first structured data should remain unchanged
self.assertTrue(structured_data_1.IsValid())
self.assertEqual(structured_data_1.GetSize(), 1)
- self.assertEqual(structured_data_1.GetItemAtIndex(0).GetValueForKey("command").GetStringValue(100), "version")
+ self.assertEqual(
+ structured_data_1.GetItemAtIndex(0)
+ .GetValueForKey("command")
+ .GetStringValue(100),
+ "version",
+ )
>From 194b53f34e3bc77424cce01c23e9329800bb9fc4 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 9 Oct 2025 07:52:37 +0100
Subject: [PATCH 6/8] fixup! adjust diagnostic message
---
.../ExpressionParser/Clang/ClangExpressionParser.cpp | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 7eb13dc8e9dd5..6cabd84002155 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -551,7 +551,7 @@ static void SetupLangOpts(CompilerInstance &compiler,
lldb_private::Language::GetNameForLanguageType(language));
lldb::LanguageType language_for_note = language;
- llvm::StringRef language_fallback_reason;
+ std::string language_fallback_reason;
LangOptions &lang_opts = compiler.getLangOpts();
@@ -623,7 +623,13 @@ static void SetupLangOpts(CompilerInstance &compiler,
compiler.getHeaderSearchOpts().UseLibcxx = true;
language_for_note = lldb::eLanguageTypeObjC_plus_plus;
- language_fallback_reason = "Using default language. ";
+ if (language != lldb::eLanguageTypeUnknown)
+ language_fallback_reason = llvm::formatv(
+ "Expression evaluation in {0} not supported. ",
+ lldb_private::Language::GetDisplayNameForLanguageType(language));
+
+ language_fallback_reason +=
+ llvm::formatv("Falling back to default language. ");
break;
}
>From f8fbdbb71dca6cc43cb0553a0e2e153f2a99985f Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 9 Oct 2025 07:58:32 +0100
Subject: [PATCH 7/8] fixup! adjust structured diagnostics test
---
.../expression/diagnostics/TestExprDiagnostics.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py b/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py
index 5150ba6a630ad..ec208f2c32503 100644
--- a/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py
+++ b/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py
@@ -218,6 +218,16 @@ def check_error(diags):
# Detail 1/3: note: requested expression language
diag = details.GetItemAtIndex(0)
self.assertEqual(str(diag.GetValueForKey("severity")), "note")
+ self.assertEqual(
+ str(diag.GetValueForKey("message")), "Ran expression as 'C++11'."
+ )
+ self.assertEqual(
+ str(diag.GetValueForKey("rendered")), "Ran expression as 'C++11'."
+ )
+ self.assertEqual(str(diag.GetValueForKey("source_location")), "")
+ self.assertEqual(str(diag.GetValueForKey("file")), "")
+ self.assertFalse(diag.GetValueForKey("hidden").GetBooleanValue())
+ self.assertFalse(diag.GetValueForKey("in_user_input").GetBooleanValue())
# Detail 2/3: undeclared 'a'
diag = details.GetItemAtIndex(1)
>From 6ae18a745221e92c1feb17815dc377fe02681c75 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 9 Oct 2025 09:16:14 +0100
Subject: [PATCH 8/8] fixup! add more tests; adjust default language diagnostic
---
.../Clang/ClangExpressionParser.cpp | 16 ++--
.../test/Shell/Expr/TestExprLanguageNote.test | 77 +++++++++++++++++++
2 files changed, 86 insertions(+), 7 deletions(-)
create mode 100644 lldb/test/Shell/Expr/TestExprLanguageNote.test
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 6cabd84002155..6b121c934dfbb 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -623,13 +623,15 @@ static void SetupLangOpts(CompilerInstance &compiler,
compiler.getHeaderSearchOpts().UseLibcxx = true;
language_for_note = lldb::eLanguageTypeObjC_plus_plus;
- if (language != lldb::eLanguageTypeUnknown)
- language_fallback_reason = llvm::formatv(
- "Expression evaluation in {0} not supported. ",
- lldb_private::Language::GetDisplayNameForLanguageType(language));
-
- language_fallback_reason +=
- llvm::formatv("Falling back to default language. ");
+ if (language != language_for_note) {
+ if (language != lldb::eLanguageTypeUnknown)
+ language_fallback_reason = llvm::formatv(
+ "Expression evaluation in {0} not supported. ",
+ lldb_private::Language::GetDisplayNameForLanguageType(language));
+
+ language_fallback_reason +=
+ llvm::formatv("Falling back to default language. ");
+ }
break;
}
diff --git a/lldb/test/Shell/Expr/TestExprLanguageNote.test b/lldb/test/Shell/Expr/TestExprLanguageNote.test
new file mode 100644
index 0000000000000..a1fa447f9c30a
--- /dev/null
+++ b/lldb/test/Shell/Expr/TestExprLanguageNote.test
@@ -0,0 +1,77 @@
+# RUN: split-file %s %t
+# RUN: %clang_host -g %t/main.cpp -o %t.out
+#
+# RUN: %lldb -x -b -o "settings set interpreter.stop-command-source-on-error false" \
+# RUN: -s %t/no-target.input 2>&1 | FileCheck %s --check-prefix=CHECK-NO-TARGET
+#
+# RUN: %lldb %t.out -x -b -o "settings set interpreter.stop-command-source-on-error false" \
+# RUN: -s %t/with-target.input 2>&1 | FileCheck %s --check-prefix=CHECK-TARGET
+
+#--- main.cpp
+
+int main() {
+ int x = 10;
+ __builtin_debugtrap();
+}
+
+#--- with-target.input
+
+expr blah
+
+# CHECK-TARGET: (lldb) expr
+# CHECK-TARGET: note: Falling back to default language. Ran expression as 'Objective C++'.
+
+run
+
+expr blah
+
+# CHECK-TARGET: (lldb) expr
+# CHECK-TARGET: note: Ran expression as 'C++14'.
+
+expr -l objc -- blah
+
+# CHECK-TARGET: (lldb) expr
+# CHECK-TARGET: note: Expression evaluation in pure Objective-C not supported. Ran expression as 'Objective C++'.
+
+expr -l c -- blah
+
+# CHECK-TARGET: (lldb) expr
+# CHECK-TARGET: note: Expression evaluation in pure C not supported. Ran expression as 'ISO C++'.
+
+expr -l c++14 -- blah
+
+# CHECK-TARGET: (lldb) expr
+# CHECK-TARGET: note: Ran expression as 'C++14'
+
+expr -l c++20 -- blah
+
+# CHECK-TARGET: (lldb) expr
+# CHECK-TARGET: note: Ran expression as 'C++20'
+
+expr -l objective-c++ -- blah
+
+# CHECK-TARGET: (lldb) expr
+# CHECK-TARGET: note: Ran expression as 'Objective C++'
+
+# D uses TypeSystemClang but running expressions in it isn't supported. Test that we warn about this.
+expr -l D -- blah
+
+# CHECK-TARGET: (lldb) expr
+# CHECK-TARGET: note: Expression evaluation in D not supported. Falling back to default language. Ran expression as 'Objective C++'.
+
+expr -l c++17 -- x = 5
+
+# CHECK-TARGET: (lldb) expr
+# CHECK-TARGET-NOT: note:
+
+#--- no-target.input
+
+expr blah
+
+# CHECK-NO-TARGET: (lldb) expr
+# CHECK-NO-TARGET: note: Falling back to default language. Ran expression as 'Objective C++'.
+
+expr -l c++ -- 1 + 1
+
+# CHECK-NO-TARGET: (lldb) expr
+# CHECK-NO-TARGET-NOT: note:
More information about the lldb-commits
mailing list