https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/161688
>From 70209138f76ddcc59e6ee3f9a0cfac734d6db00d Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Fri, 3 Oct 2025 09:24:49 +0100 Subject: [PATCH 1/4] [lldb][Lanugage] Add Language::GetDisplayNameForLanguageType API The intention for this API is to be used when presenting language names to the user, e.g., in expression evaluation diagnostics or LLDB errors. Most uses of `GetNameForLanguageType` can be probably replaced with `GetDisplayNameForLanguageType`, but that's out of scope of this PR. This uses `llvm::dwarf::LanguageDescription` under the hood, so we would lose the version numbers in the names. If we deem those to be important, we could switch to an implementation that hardcodes a list of user-friendly names with version numbers included. --- lldb/include/lldb/Target/Language.h | 7 +++++++ lldb/source/Target/Language.cpp | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/lldb/include/lldb/Target/Language.h b/lldb/include/lldb/Target/Language.h index 3d0aa326d5a6d..48a7ac2cea42f 100644 --- a/lldb/include/lldb/Target/Language.h +++ b/lldb/include/lldb/Target/Language.h @@ -404,8 +404,15 @@ class Language : public PluginInterface { GetLanguageTypeFromString(const char *string) = delete; static lldb::LanguageType GetLanguageTypeFromString(llvm::StringRef string); + /// Returns the internal LLDB name for the specified language. When presenting + /// the language name to users, use \ref GetDisplayNameForLanguageType + /// instead. static const char *GetNameForLanguageType(lldb::LanguageType language); + /// Returns a user-friendly name for the specified language. + static llvm::StringRef + GetDisplayNameForLanguageType(lldb::LanguageType language); + static void PrintAllLanguages(Stream &s, const char *prefix, const char *suffix); diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp index 484d9badde397..f0fc48e18793b 100644 --- a/lldb/source/Target/Language.cpp +++ b/lldb/source/Target/Language.cpp @@ -270,6 +270,10 @@ const char *Language::GetNameForLanguageType(LanguageType language) { return language_names[eLanguageTypeUnknown].name; } +llvm::StringRef Language::GetDisplayNameForLanguageType(LanguageType language) { + return SourceLanguage(language).GetDescription(); +} + void Language::PrintSupportedLanguagesForExpressions(Stream &s, llvm::StringRef prefix, llvm::StringRef suffix) { >From fb4be5f7dac30810af9b0fd8c107344d955bc282 Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Thu, 2 Oct 2025 16:24:12 +0100 Subject: [PATCH 2/4] [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 924953cc43fa2..77a8afa511a6a 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 817898fa919c3fe9530acf0adf6a0415367ccf07 Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Fri, 3 Oct 2025 09:29:17 +0100 Subject: [PATCH 3/4] 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 77a8afa511a6a..faef42d34adee 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 224af5ea52df2415992a04e9424bfadb186114a7 Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Fri, 3 Oct 2025 09:30:05 +0100 Subject: [PATCH 4/4] 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 faef42d34adee..d297d32e61b9a 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); _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
