Skip to content

Conversation

Michael137
Copy link
Member

@Michael137 Michael137 commented Oct 2, 2025

Depends on:

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 #156648).

Here are some example outputs:

# Without target
(lldb) expr blah
note: Falling back to default language. Ran expression as 'Objective C++'.

# Stopped in target
(lldb) expr blah
note: Ran expression as 'C++14'.

(lldb) expr -l objc -- blah
note: Expression evaluation in pure Objective-C not supported. Ran expression as 'Objective C++'.

(lldb) expr -l c -- blah
note: Expression evaluation in pure C not supported. Ran expression as 'ISO C++'.

(lldb) expr -l c++14 -- blah
note: Ran expression as 'C++14'

(lldb) expr -l c++20 -- blah
note: Ran expression as 'C++20'

(lldb) expr -l objective-c++ -- blah
note: Ran expression as 'Objective C++'

(lldb) expr -l D -- blah
note: Expression evaluation in D not supported. Falling back to default language. Ran expression as 'Objective C++'.

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
rdar://159669244

@Michael137
Copy link
Member Author

Have yet to write tests for it.

@llvmbot
Copy link
Member

llvmbot commented Oct 2, 2025

@llvm/pr-subscribers-debuginfo
@llvm/pr-subscribers-llvm-binary-utilities

@llvm/pr-subscribers-lldb

Author: Michael Buch (Michael137)

Changes

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 #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
rdar://159669244


Full diff: https://github.com/llvm/llvm-project/pull/161688.diff

5 Files Affected:

  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (+25-4)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h (+1)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp (+2-2)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp (+2-2)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp (+1-1)
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);
 

@Michael137 Michael137 changed the title [lldb][Expression] Emit a 'Note' diagnistc that indicates the language used for expression evaluation [lldb][Expression] Emit a 'Note' diagnostic that indicates the language used for expression evaluation Oct 2, 2025
@adrian-prantl
Copy link
Collaborator

This going to be quite useful for diagnosing perplexing errors!

note: Requested expression evaluation as 'c' but fell back to 'c++'.

  • Do we have a table that would translate the spec names into human-readable names (objc -> Objective-C, c -> C, ...) we could use for this?
  • Is there any explanation we could offer as to why LLDB didn't honor the language the user requested?

@Michael137
Copy link
Member Author

This going to be quite useful for diagnosing perplexing errors!

note: Requested expression evaluation as 'c' but fell back to 'c++'.

  • Do we have a table that would translate the spec names into human-readable names (objc -> Objective-C, c -> C, ...) we could use for this?

Not that I'm aware of. Could try creating one

  • Is there any explanation we could offer as to why LLDB didn't honor the language the user requested?

Yea we could elaborate. I didn't want to make the note too verbose, but I'll try to expand it a bit.

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice. I looked at the example before reading the PR description and I wondered (1) if this would show up even if the expression succeeded and (2) if this would show up if the languages are the same. The answer to both is no which I believe makes sense.

@Michael137 Michael137 force-pushed the lldb/expression-language-note branch from 5e3b5e8 to 224af5e Compare October 3, 2025 08:30
Michael137 added a commit that referenced this pull request Oct 3, 2025
…1803)

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.

The intention is to use it from
#161688

Depends on #161804
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Oct 3, 2025
…pe API (#161803)

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.

The intention is to use it from
llvm/llvm-project#161688

Depends on llvm/llvm-project#161804
@Michael137 Michael137 force-pushed the lldb/expression-language-note branch 2 times, most recently from cc2ca49 to d3d00cf Compare October 6, 2025 08:58
@Michael137 Michael137 force-pushed the lldb/expression-language-note branch from d3d00cf to d5457cd Compare October 6, 2025 08:59
@Michael137 Michael137 force-pushed the lldb/expression-language-note branch from d5457cd to d62e766 Compare October 6, 2025 09:13
Copy link

github-actions bot commented Oct 6, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Michael137 added a commit that referenced this pull request Oct 8, 2025
…162048)

Currently `llvm::dwarf::LanguageDescription` returns a stringified
`DW_LNAME`. It would be useful to have an API that returns the language
name for a particular `DW_LNAME_`/version pair. LLDB's use case is that
it wants to emit diagnostics with human readable descriptions of the
language we got from debug-info (see
#161688). We could maintain a
side-table in LLDB but thought this might be generally useful and should
live next to the existing `LanguageDescription` API.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Oct 8, 2025
…r version (#162048)

Currently `llvm::dwarf::LanguageDescription` returns a stringified
`DW_LNAME`. It would be useful to have an API that returns the language
name for a particular `DW_LNAME_`/version pair. LLDB's use case is that
it wants to emit diagnostics with human readable descriptions of the
language we got from debug-info (see
llvm/llvm-project#161688). We could maintain a
side-table in LLDB but thought this might be generally useful and should
live next to the existing `LanguageDescription` API.
@Michael137 Michael137 force-pushed the lldb/expression-language-note branch from d62e766 to 6ae18a7 Compare October 9, 2025 08:19
…e used for expression evaluation

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 llvm#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
@Michael137 Michael137 merged commit e3620fe into llvm:main Oct 10, 2025
10 checks passed
@Michael137 Michael137 deleted the lldb/expression-language-note branch October 10, 2025 18:23
Michael137 added a commit to swiftlang/llvm-project that referenced this pull request Oct 10, 2025
…ge used for expression evaluation (llvm#161688)

Depends on:
* llvm#162050

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
llvm#156648).

Here are some example outputs:
```
# Without target
(lldb) expr blah
note: Falling back to default language. Ran expression as 'Objective C++'.

# Stopped in target
(lldb) expr blah
note: Ran expression as 'C++14'.

(lldb) expr -l objc -- blah
note: Expression evaluation in pure Objective-C not supported. Ran expression as 'Objective C++'.

(lldb) expr -l c -- blah
note: Expression evaluation in pure C not supported. Ran expression as 'ISO C++'.

(lldb) expr -l c++14 -- blah
note: Ran expression as 'C++14'

(lldb) expr -l c++20 -- blah
note: Ran expression as 'C++20'

(lldb) expr -l objective-c++ -- blah
note: Ran expression as 'Objective C++'

(lldb) expr -l D -- blah
note: Expression evaluation in D not supported. Falling back to default language. Ran expression as 'Objective C++'.
```

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
rdar://159669244
(cherry picked from commit e3620fe)
@slydiman
Copy link
Contributor

The buildbot lldb-x86_64-win is broken.
Please take a look.

@Michael137
Copy link
Member Author

The buildbot lldb-x86_64-win is broken.

Please take a look.

Will take a look. Seems like the default language versions are different on windows. Just have to adjust the test cases a bit

Michael137 added a commit to swiftlang/llvm-project that referenced this pull request Oct 11, 2025
…lvm#162048)

Currently `llvm::dwarf::LanguageDescription` returns a stringified
`DW_LNAME`. It would be useful to have an API that returns the language
name for a particular `DW_LNAME_`/version pair. LLDB's use case is that
it wants to emit diagnostics with human readable descriptions of the
language we got from debug-info (see
llvm#161688). We could maintain a
side-table in LLDB but thought this might be generally useful and should
live next to the existing `LanguageDescription` API.

(cherry picked from commit 030d8e6)
Michael137 added a commit to swiftlang/llvm-project that referenced this pull request Oct 11, 2025
…m#161803)

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.

The intention is to use it from
llvm#161688

Depends on llvm#161804

(cherry picked from commit 2c37244)
@Michael137
Copy link
Member Author

The buildbot lldb-x86_64-win is broken. Please take a look.

#162995

@Michael137
Copy link
Member Author

The buildbot lldb-x86_64-win is broken. Please take a look.

#162995

Seems to have fixed the API test failure. But shell test still fails. @slydiman any chance you can run the shell test command locally and post the full output:

c:\buildbot\as-builder-10\lldb-x86-64\build\bin\lldb.exe' --no-lldbinit -S 'C:/buildbot/as-builder-10/lldb-x86-64/build/tools/lldb\test\Shell\lit-lldb-init-quiet' 'C:\buildbot\as-builder-10\lldb-x86-64\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp.out' -x -b -o 'settings set interpreter.stop-command-source-on-error false' -s 'C:\buildbot\as-builder-10\lldb-x86-64\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp/with-target.input'

The test log is not enough for me to go on. We can skip it on Windows for now if you need to unblock the bots urgently.

@slydiman
Copy link
Contributor

any chance you can run the shell test command locally and post the full output:

I have executed it locally with the same setup:

(lldb) command source -s 0 'lit-lldb-init-quiet'
Executing commands in 'D:\test\lit-lldb-init-quiet'.
(lldb) command source -C --silent-run true lit-lldb-init
(lldb) target create "main.out"
Current executable set to 'D:\test\main.out' (x86_64).
(lldb) settings set interpreter.stop-command-source-on-error false
(lldb) command source -s 0 'with-target.input'
Executing commands in 'D:\test\with-target.input'.
(lldb) expr blah
            ^
            error: use of undeclared identifier 'blah'
note: Falling back to default language. Ran expression as 'Objective C++'.
(lldb) run
Process 29404 launched: 'D:\test\main.out' (x86_64)
Process 29404 stopped
* thread #1, stop reason = Exception 0x80000003 encountered at address 0x7ff7b3df7189
    frame #0: 0x00007ff7b3df718a main.out
->  0x7ff7b3df718a: xorl   %eax, %eax
    0x7ff7b3df718c: popq   %rcx
    0x7ff7b3df718d: retq   
    0x7ff7b3df718e: int3
(lldb) expr blah
            ^
            error: use of undeclared identifier 'blah'
note: Falling back to default language. Ran expression as 'Objective C++'.
(lldb) expr -l objc -- blah
                       ^
                       error: use of undeclared identifier 'blah'
note: Expression evaluation in pure Objective-C not supported. Ran expression as 'Objective C++'.
(lldb) expr -l c -- blah
                    ^
                    error: use of undeclared identifier 'blah'
note: Expression evaluation in pure C not supported. Ran expression as 'ISO C++'.
(lldb) expr -l c++14 -- blah
                        ^
                        error: use of undeclared identifier 'blah'
note: Ran expression as 'C++14'.
(lldb) expr -l c++20 -- blah
                        ^
                        error: use of undeclared identifier 'blah'
note: Ran expression as 'C++20'.
(lldb) expr -l objective-c++ -- blah
                                ^
                                error: use of undeclared identifier 'blah'
note: Ran expression as 'Objective C++'.
(lldb) expr -l D -- blah
                    ^
                    error: use of undeclared identifier 'blah'
note: Expression evaluation in D not supported. Falling back to default language. Ran expression as 'Objective C++'.
(lldb) expr -l c++17 -- x = 5
                        ^
                        error: use of undeclared identifier 'x'
note: Ran expression as 'C++17'.
(lldb) expr x = 5
            ^
            error: use of undeclared identifier 'x'
note: Falling back to default language. Ran expression as 'Objective C++'.

@Michael137
Copy link
Member Author

any chance you can run the shell test command locally and post the full output:

I have executed it locally with the same setup:

(lldb) command source -s 0 'lit-lldb-init-quiet'
Executing commands in 'D:\test\lit-lldb-init-quiet'.
(lldb) command source -C --silent-run true lit-lldb-init
(lldb) target create "main.out"
Current executable set to 'D:\test\main.out' (x86_64).
(lldb) settings set interpreter.stop-command-source-on-error false
(lldb) command source -s 0 'with-target.input'
Executing commands in 'D:\test\with-target.input'.
(lldb) expr blah
            ^
            error: use of undeclared identifier 'blah'
note: Falling back to default language. Ran expression as 'Objective C++'.
(lldb) run
Process 29404 launched: 'D:\test\main.out' (x86_64)
Process 29404 stopped
* thread #1, stop reason = Exception 0x80000003 encountered at address 0x7ff7b3df7189
    frame #0: 0x00007ff7b3df718a main.out
->  0x7ff7b3df718a: xorl   %eax, %eax
    0x7ff7b3df718c: popq   %rcx
    0x7ff7b3df718d: retq   
    0x7ff7b3df718e: int3
(lldb) expr blah
            ^
            error: use of undeclared identifier 'blah'
note: Falling back to default language. Ran expression as 'Objective C++'.
(lldb) expr -l objc -- blah
                       ^
                       error: use of undeclared identifier 'blah'
note: Expression evaluation in pure Objective-C not supported. Ran expression as 'Objective C++'.
(lldb) expr -l c -- blah
                    ^
                    error: use of undeclared identifier 'blah'
note: Expression evaluation in pure C not supported. Ran expression as 'ISO C++'.
(lldb) expr -l c++14 -- blah
                        ^
                        error: use of undeclared identifier 'blah'
note: Ran expression as 'C++14'.
(lldb) expr -l c++20 -- blah
                        ^
                        error: use of undeclared identifier 'blah'
note: Ran expression as 'C++20'.
(lldb) expr -l objective-c++ -- blah
                                ^
                                error: use of undeclared identifier 'blah'
note: Ran expression as 'Objective C++'.
(lldb) expr -l D -- blah
                    ^
                    error: use of undeclared identifier 'blah'
note: Expression evaluation in D not supported. Falling back to default language. Ran expression as 'Objective C++'.
(lldb) expr -l c++17 -- x = 5
                        ^
                        error: use of undeclared identifier 'x'
note: Ran expression as 'C++17'.
(lldb) expr x = 5
            ^
            error: use of undeclared identifier 'x'
note: Falling back to default language. Ran expression as 'Objective C++'.

Thanks that's useful! Very weird, it seems like Windows doesn't respond well to __builtin_debugtrap. I guess I'll use an explicit breakpoint instead. I'll file an issue about the debugtrap thing

@Michael137
Copy link
Member Author

any chance you can run the shell test command locally and post the full output:

I have executed it locally with the same setup:

(lldb) command source -s 0 'lit-lldb-init-quiet'
Executing commands in 'D:\test\lit-lldb-init-quiet'.
(lldb) command source -C --silent-run true lit-lldb-init
(lldb) target create "main.out"
Current executable set to 'D:\test\main.out' (x86_64).
(lldb) settings set interpreter.stop-command-source-on-error false
(lldb) command source -s 0 'with-target.input'
Executing commands in 'D:\test\with-target.input'.
(lldb) expr blah
            ^
            error: use of undeclared identifier 'blah'
note: Falling back to default language. Ran expression as 'Objective C++'.
(lldb) run
Process 29404 launched: 'D:\test\main.out' (x86_64)
Process 29404 stopped
* thread #1, stop reason = Exception 0x80000003 encountered at address 0x7ff7b3df7189
    frame #0: 0x00007ff7b3df718a main.out
->  0x7ff7b3df718a: xorl   %eax, %eax
    0x7ff7b3df718c: popq   %rcx
    0x7ff7b3df718d: retq   
    0x7ff7b3df718e: int3
(lldb) expr blah
            ^
            error: use of undeclared identifier 'blah'
note: Falling back to default language. Ran expression as 'Objective C++'.
(lldb) expr -l objc -- blah
                       ^
                       error: use of undeclared identifier 'blah'
note: Expression evaluation in pure Objective-C not supported. Ran expression as 'Objective C++'.
(lldb) expr -l c -- blah
                    ^
                    error: use of undeclared identifier 'blah'
note: Expression evaluation in pure C not supported. Ran expression as 'ISO C++'.
(lldb) expr -l c++14 -- blah
                        ^
                        error: use of undeclared identifier 'blah'
note: Ran expression as 'C++14'.
(lldb) expr -l c++20 -- blah
                        ^
                        error: use of undeclared identifier 'blah'
note: Ran expression as 'C++20'.
(lldb) expr -l objective-c++ -- blah
                                ^
                                error: use of undeclared identifier 'blah'
note: Ran expression as 'Objective C++'.
(lldb) expr -l D -- blah
                    ^
                    error: use of undeclared identifier 'blah'
note: Expression evaluation in D not supported. Falling back to default language. Ran expression as 'Objective C++'.
(lldb) expr -l c++17 -- x = 5
                        ^
                        error: use of undeclared identifier 'x'
note: Ran expression as 'C++17'.
(lldb) expr x = 5
            ^
            error: use of undeclared identifier 'x'
note: Falling back to default language. Ran expression as 'Objective C++'.

Thanks that's useful! Very weird, it seems like Windows doesn't respond well to __builtin_debugtrap. I guess I'll use an explicit breakpoint instead. I'll file an issue about the debugtrap thing

Oh actually the lack of source is probably because the DWARF gets stripped? Let me try requiring LLD.

@Michael137
Copy link
Member Author

@slydiman hmm still failing after my attempted fix. Any chance you could provide the output again (on the new version of the test)?

DharuniRAcharya pushed a commit to DharuniRAcharya/llvm-project that referenced this pull request Oct 13, 2025
…ge used for expression evaluation (llvm#161688)

Depends on:
* llvm#162050

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
llvm#156648).

Here are some example outputs:
```
# Without target
(lldb) expr blah
note: Falling back to default language. Ran expression as 'Objective C++'.

# Stopped in target
(lldb) expr blah
note: Ran expression as 'C++14'.

(lldb) expr -l objc -- blah
note: Expression evaluation in pure Objective-C not supported. Ran expression as 'Objective C++'.

(lldb) expr -l c -- blah
note: Expression evaluation in pure C not supported. Ran expression as 'ISO C++'.

(lldb) expr -l c++14 -- blah
note: Ran expression as 'C++14'

(lldb) expr -l c++20 -- blah
note: Ran expression as 'C++20'

(lldb) expr -l objective-c++ -- blah
note: Ran expression as 'Objective C++'

(lldb) expr -l D -- blah
note: Expression evaluation in D not supported. Falling back to default language. Ran expression as 'Objective C++'.
```

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
rdar://159669244
@luporl
Copy link
Contributor

luporl commented Oct 13, 2025

This PR also broke lldb-aarch64-windows buildbot: https://lab.llvm.org/buildbot/#/builders/141/builds/12176.
I'll try to provide the test command output.

@slydiman
Copy link
Contributor

@slydiman hmm still failing after my attempted fix. Any chance you could provide the output again (on the new version of the test)?

(lldb) command source -s 0 'lit-lldb-init-quiet'
Executing commands in 'D:\test\lit-lldb-init-quiet'.
(lldb) command source -C --silent-run true lit-lldb-init
(lldb) target create "main.out"
Current executable set to 'D:\test\main.out' (x86_64).
(lldb) settings set interpreter.stop-command-source-on-error false
(lldb) command source -s 0 'with-target.input'
Executing commands in 'D:\test\with-target.input'.
(lldb) expr blah
            ^
            error: use of undeclared identifier 'blah'
note: Falling back to default language. Ran expression as 'Objective C++'.
(lldb) b 4
error: No selected frame to use to find the default file.
error: no file supplied and no default file available
(lldb) run
Process 13824 launched: 'D:\test\main.out' (x86_64)
Process 13824 exited with status = 10 (0x0000000a)
(lldb) expr blah
error: unable to evaluate expression while the process is exited: the process must be stopped because the expression might require allocating memory.
(lldb) expr -l objc -- blah
error: unable to evaluate expression while the process is exited: the process must be stopped because the expression might require allocating memory.
(lldb) expr -l c -- blah
error: unable to evaluate expression while the process is exited: the process must be stopped because the expression might require allocating memory.
(lldb) expr -l c++14 -- blah
error: unable to evaluate expression while the process is exited: the process must be stopped because the expression might require allocating memory.
(lldb) expr -l c++20 -- blah
error: unable to evaluate expression while the process is exited: the process must be stopped because the expression might require allocating memory.
(lldb) expr -l objective-c++ -- blah
error: unable to evaluate expression while the process is exited: the process must be stopped because the expression might require allocating memory.
(lldb) expr -l D -- blah
error: unable to evaluate expression while the process is exited: the process must be stopped because the expression might require allocating memory.
(lldb) expr -l c++17 -- x = 5
error: unable to evaluate expression while the process is exited: the process must be stopped because the expression might require allocating memory.
(lldb) expr x = 5
error: unable to evaluate expression while the process is exited: the process must be stopped because the expression might require allocating memory.

I don't see any problem with __builtin_debugtrap(); in the previous version.
The test failed because expected note: Expression evaluation in D not supported. Falling back to default language. Ran expression as 'Objective C++'. but got note: Expression evaluation in pure C not supported. Ran expression as 'ISO C++'.

@Michael137
Copy link
Member Author

Michael137 commented Oct 13, 2025

The problem was that there was no debug-info for the stopped frame. Now the problem is with my breakpoint setting:

(lldb) b 4
error: No selected frame to use to find the default file.
error: no file supplied and no default file available

I didn't specify the file (which does work on Unix). Could you try patching that up? Might be quicker than me doing it blindly and relying on CI. Would be greatly appreciated!

@slydiman
Copy link
Contributor

Could you try patching that up? Might be quicker than me doing it blindly and relying on CI. Would be greatly appreciated!

I will try.

@slydiman
Copy link
Contributor

No luck yet.
I tried to compile main.cpp with -O0 to be sure the debug info is present.
It seems %lldb runs lldb --no-lldbinit, so the parameter -x is redundant.
Note the debug info is placed to main.pdb. I tried to run lldb w/o -S lit-lldb-init-quiet because lit-lldb-init-quiet contains settings set symbols.enable-external-lookup false.
Tried b main.cpp:4 and breakpoint set -f main.cpp -l 4 as the first command.

(lldb) b 4
error: No selected frame to use to find the default file.
error: no file supplied and no default file available

or

(lldb) b main.cpp:4
Breakpoint 1: no locations (pending).
WARNING:  Unable to resolve breakpoint to any actual locations.

and finally

(lldb) run
Process 8464 launched: 'D:\test\main.out' (x86_64)
Process 8464 exited with status = 10 (0x0000000a)

I have no idea for now how it worked.
I will try something else later today.

@Michael137
Copy link
Member Author

No luck yet. I tried to compile main.cpp with -O0 to be sure the debug info is present. It seems %lldb runs lldb --no-lldbinit, so the parameter -x is redundant. Note the debug info is placed to main.pdb. I tried to run lldb w/o -S lit-lldb-init-quiet because lit-lldb-init-quiet contains settings set symbols.enable-external-lookup false. Tried b main.cpp:4 and breakpoint set -f main.cpp -l 4 as the first command.

(lldb) b 4
error: No selected frame to use to find the default file.
error: no file supplied and no default file available

or

(lldb) b main.cpp:4
Breakpoint 1: no locations (pending).
WARNING:  Unable to resolve breakpoint to any actual locations.

and finally

(lldb) run
Process 8464 launched: 'D:\test\main.out' (x86_64)
Process 8464 exited with status = 10 (0x0000000a)

I have no idea for now how it worked. I will try something else later today.

Weird. Does specifying -gdwarf resolve the breakpoint correctly? @DavidSpickett @Nerixyz any idea what we typically do for Windows shell tests? Why wouldn't the breakpoint resolve?

@Nerixyz
Copy link
Contributor

Nerixyz commented Oct 13, 2025

The breakpoint does resolve for me. On Windows I get the following

Full output
> &'f:\dev\llvm-project\build\bin\lldb.exe' --no-lldbinit -S 'F:/Dev/llvm-project/build/tools/lldb\test\Shell\lit-lldb-init-quiet' 'F:\Dev\llvm-project\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp.out' -x -b -o 'settings set interpreter.stop-command-source-on-error false' -s 'F:\Dev\llvm-project\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp/with-target.input'
<sys>:0: DeprecationWarning: builtin type SwigPyPacked has no __module__ attribute
<sys>:0: DeprecationWarning: builtin type SwigPyObject has no __module__ attribute
(lldb) command source -s 0 'F:/Dev/llvm-project/build/tools/lldb\test\Shell\lit-lldb-init-quiet'
Executing commands in 'F:\Dev\llvm-project\build\tools\lldb\test\Shell\lit-lldb-init-quiet'.
(lldb) command source -C --silent-run true lit-lldb-init
(lldb) target create "F:\\Dev\\llvm-project\\build\\tools\\lldb\\test\\Shell\\Expr\\Output\\TestExprLanguageNote.test.tmp.out"
Current executable set to 'F:\Dev\llvm-project\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp.out' (x86_64).
(lldb) settings set interpreter.stop-command-source-on-error false
(lldb) command source -s 0 'F:\Dev\llvm-project\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp/with-target.input'
Executing commands in 'F:\Dev\llvm-project\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp\with-target.input'.
(lldb) expr blah
            ˄
            ╰─ error: use of undeclared identifier 'blah'
note: Falling back to default language. Ran expression as 'Objective C++'.
(lldb) b 4
Breakpoint 1: where = TestExprLanguageNote.test.tmp.out`main + 16 at main.cpp:4, address = 0x0000000140007260
(lldb) run
Process 24360 launched: 'F:\Dev\llvm-project\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp.out' (x86_64)
Process 24360 stopped
* thread #1, stop reason = breakpoint 1.1
    frame #0: 0x00007ff6214e7260 TestExprLanguageNote.test.tmp.out`main at main.cpp:4
   1
   2    int main() {
   3      int x = 10;
-> 4      return x;
   5    }
   6
(lldb) expr blah
            ˄
            ╰─ error: use of undeclared identifier 'blah'
note: Ran expression as 'ISO C++'.
(lldb) expr -l objc -- blah
                       ˄
                       ╰─ error: use of undeclared identifier 'blah'
note: Expression evaluation in pure Objective-C not supported. Ran expression as 'Objective C++'.
(lldb) expr -l c -- blah
                    ˄
                    ╰─ error: use of undeclared identifier 'blah'
note: Expression evaluation in pure C not supported. Ran expression as 'ISO C++'.
(lldb) expr -l c++14 -- blah
                        ˄
                        ╰─ error: use of undeclared identifier 'blah'
note: Ran expression as 'C++14'.
(lldb) expr -l c++20 -- blah
                        ˄
                        ╰─ error: use of undeclared identifier 'blah'
note: Ran expression as 'C++20'.
(lldb) expr -l objective-c++ -- blah
                                ˄
                                ╰─ error: use of undeclared identifier 'blah'
note: Ran expression as 'Objective C++'.
(lldb) expr -l D -- blah
                    ˄
                    ╰─ error: use of undeclared identifier 'blah'
note: Expression evaluation in D not supported. Falling back to default language. Ran expression as 'Objective C++'.
(lldb) expr -l c++17 -- x = 5
(int) $0 = 5
(lldb) expr x = 5
(int) $1 = 5

The expr blah after run runs as ISO C++ instead of C++ xy:

(lldb) run
[...]
(lldb) expr blah
            ˄
            ╰─ error: use of undeclared identifier 'blah'
note: Ran expression as 'ISO C++'.

The following patch fixed the test:

diff --git a/lldb/test/Shell/Expr/TestExprLanguageNote.test b/lldb/test/Shell/Expr/TestExprLanguageNote.test
index 7d8c7025d7f7..de1095e0cee6 100644
--- a/lldb/test/Shell/Expr/TestExprLanguageNote.test
+++ b/lldb/test/Shell/Expr/TestExprLanguageNote.test
@@ -29,7 +29,7 @@ run
 expr blah
 
 # CHECK-TARGET: (lldb) expr
-# CHECK-TARGET: note: Ran expression as 'C++{{.*}}'
+# CHECK-TARGET: note: Ran expression as '{{(ISO )?}}C++{{.*}}'
 
 expr -l objc -- blah
 

I get the same output regardless of the PDB reader (modulo some errors about incomplete types with DIA).

@luporl
Copy link
Contributor

luporl commented Oct 13, 2025

lldb-aarch64-windows test command output:

C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build>c:\users\tcwg\llvm-worker\lldb-aarch64-windows\build\bin\lldb.exe --no-lldbinit -S C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/tools/lldb\test\Shell\lit-lldb-init-quiet C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp.out -x -b -o "settings set interpreter.stop-command-source-on-error false" -s C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp/with-target.input
(lldb) command source -s 0 'C:/Users/tcwg/llvm-worker/lldb-aarch64-windows/build/tools/lldb\test\Shell\lit-lldb-init-quiet'
Executing commands in 'C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\lldb\test\Shell\lit-lldb-init-quiet'.
(lldb) command source -C --silent-run true lit-lldb-init
(lldb) target create "C:\\Users\\tcwg\\llvm-worker\\lldb-aarch64-windows\\build\\tools\\lldb\\test\\Shell\\Expr\\Output\\TestExprLanguageNote.test.tmp.out"
Current executable set to 'C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp.out' (aarch64).
(lldb) settings set interpreter.stop-command-source-on-error false
(lldb) command source -s 0 'C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp/with-target.input'
Executing commands in 'C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp\with-target.input'.
(lldb) expr blah
            ˄
            ╰─ error: use of undeclared identifier 'blah'
note: Falling back to default language. Ran expression as 'Objective C++'.
(lldb) b 4
Breakpoint 1: where = TestExprLanguageNote.test.tmp.out`main + 16 at main.cpp:4, address = 0x000000014001100c
(lldb) run
Process 9472 launched: 'C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp.out' (aarch64)
Process 9472 stopped
* thread #1, stop reason = breakpoint 1.1
    frame #0: 0x00007ff61150100c TestExprLanguageNote.test.tmp.out`main at main.cpp:4
   1
   2    int main() {
   3      int x = 10;
-> 4      return x;
   5    }
   6
(lldb) expr blah
error: TestExprLanguageNote.test.tmp.out :: Class '__crt_cached_ptd_host::cached<int>::guard' has a member '_copy' of type '__crt_cached_ptd_host::cached<int>' which does not have a complete definition.
error: TestExprLanguageNote.test.tmp.out :: Class 'tagARRAYDESC' has a member 'tdescElem' of type 'tagTYPEDESC' which does not have a complete definition.
error: TestExprLanguageNote.test.tmp.out :: Class 'tagPARAMDESCEX' has a member 'varDefaultValue' of type 'tagVARIANT' which does not have a complete definition.
error: TestExprLanguageNote.test.tmp.out :: Class 'std::strong_ordering' has a member 'less' of type 'std::strong_ordering' which does not have a complete definition.
error: TestExprLanguageNote.test.tmp.out :: Class 'std::partial_ordering' has a member 'less' of type 'std::partial_ordering' which does not have a complete definition.
error: TestExprLanguageNote.test.tmp.out :: Class 'std::weak_ordering' has a member 'less' of type 'std::weak_ordering' which does not have a complete definition.
(lldb)             ˄
            ╰─ error: use of undeclared identifier 'blah'
note: Ran expression as 'ISO C++'.
(lldb) expr -l objc -- blah
                       ˄
                       ╰─ error: use of undeclared identifier 'blah'
note: Expression evaluation in pure Objective-C not supported. Ran expression as 'Objective C++'.
(lldb) expr -l c -- blah
                    ˄
                    ╰─ error: use of undeclared identifier 'blah'
note: Expression evaluation in pure C not supported. Ran expression as 'ISO C++'.
(lldb) expr -l c++14 -- blah
                        ˄
                        ╰─ error: use of undeclared identifier 'blah'
note: Ran expression as 'C++14'.
(lldb) expr -l c++20 -- blah
                        ˄
                        ╰─ error: use of undeclared identifier 'blah'
note: Ran expression as 'C++20'.
(lldb) expr -l objective-c++ -- blah
                                ˄
                                ╰─ error: use of undeclared identifier 'blah'
note: Ran expression as 'Objective C++'.
(lldb) expr -l D -- blah
                    ˄
                    ╰─ error: use of undeclared identifier 'blah'
note: Expression evaluation in D not supported. Falling back to default language. Ran expression as 'Objective C++'.
(lldb) expr -l c++17 -- x = 5
(int) $0 = 5
(lldb) expr x = 5
(int) $1 = 5

C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build>

The breakpoint resolved correctly too.

@slydiman
Copy link
Contributor

slydiman commented Oct 13, 2025

The following patch fixed the test:

I can confirm that this patch fixed the issue.
I have executed ninja check-lldb-shell in the test environment and it passed.
Then I copied the command from logs
d:\test\build-x64\bin\lldb.exe --no-lldbinit -S D:/test/build-x64/tools/lldb\test\Shell\lit-lldb-init-quiet D:\test\build-x64\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp.out -x -b -o "settings set interpreter.stop-command-source-on-error false" -s D:\test\build-x64\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp/with-target.input and executed it separately:

(lldb) command source -s 0 'D:/test/build-x64/tools/lldb\test\Shell\lit-lldb-init-quiet'
Executing commands in 'D:\test\build-x64\tools\lldb\test\Shell\lit-lldb-init-quiet'.
(lldb) command source -C --silent-run true lit-lldb-init
(lldb) target create "D:\\test\\build-x64\\tools\\lldb\\test\\Shell\\Expr\\Output\\TestExprLanguageNote.test.tmp.out"
Current executable set to 'D:\test\build-x64\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp.out' (x86_64).
(lldb) settings set interpreter.stop-command-source-on-error false
(lldb) command source -s 0 'D:\test\build-x64\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp/with-target.input'
Executing commands in 'D:\test\build-x64\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp\with-target.input'.
(lldb) expr blah
            ^
            error: use of undeclared identifier 'blah'
note: Falling back to default language. Ran expression as 'Objective C++'.
(lldb) b 4
error: No selected frame to use to find the default file.
error: no file supplied and no default file available
(lldb) run
lldb-server exiting...
Process 32108 launched: 'D:\test\build-x64\tools\lldb\test\Shell\Expr\Output\TestExprLanguageNote.test.tmp.out' (x86_64)
Process 32108 exited with status = 10 (0x0000000a)
...

Weird.

Upd: It requires Microsoft Visual Studio environment (vcvars64.bat).
But __builtin_debugtrap(); in the previous version worked w/o VS environment.

@Michael137
Copy link
Member Author

The breakpoint does resolve for me. On Windows I get the following

Full output
The expr blah after run runs as ISO C++ instead of C++ xy:

(lldb) run
[...]
(lldb) expr blah
            ˄
            ╰─ error: use of undeclared identifier 'blah'
note: Ran expression as 'ISO C++'.

The following patch fixed the test:

diff --git a/lldb/test/Shell/Expr/TestExprLanguageNote.test b/lldb/test/Shell/Expr/TestExprLanguageNote.test
index 7d8c7025d7f7..de1095e0cee6 100644
--- a/lldb/test/Shell/Expr/TestExprLanguageNote.test
+++ b/lldb/test/Shell/Expr/TestExprLanguageNote.test
@@ -29,7 +29,7 @@ run
 expr blah
 
 # CHECK-TARGET: (lldb) expr
-# CHECK-TARGET: note: Ran expression as 'C++{{.*}}'
+# CHECK-TARGET: note: Ran expression as '{{(ISO )?}}C++{{.*}}'
 
 expr -l objc -- blah
 

I get the same output regardless of the PDB reader (modulo some errors about incomplete types with DIA).

Thanks! I'll check in the suggested patch. Fingers crossed

@DavidSpickett
Copy link
Collaborator

@DavidSpickett @Nerixyz any idea what we typically do for Windows shell tests? Why wouldn't the breakpoint resolve?

For things that truly need DWARF I've added REQUIRES: not windows or (lld and windows). Sounds like this can work with PDB though.

@Michael137
Copy link
Member Author

The breakpoint does resolve for me. On Windows I get the following
Full output
The expr blah after run runs as ISO C++ instead of C++ xy:

(lldb) run
[...]
(lldb) expr blah
            ˄
            ╰─ error: use of undeclared identifier 'blah'
note: Ran expression as 'ISO C++'.

The following patch fixed the test:

diff --git a/lldb/test/Shell/Expr/TestExprLanguageNote.test b/lldb/test/Shell/Expr/TestExprLanguageNote.test
index 7d8c7025d7f7..de1095e0cee6 100644
--- a/lldb/test/Shell/Expr/TestExprLanguageNote.test
+++ b/lldb/test/Shell/Expr/TestExprLanguageNote.test
@@ -29,7 +29,7 @@ run
 expr blah
 
 # CHECK-TARGET: (lldb) expr
-# CHECK-TARGET: note: Ran expression as 'C++{{.*}}'
+# CHECK-TARGET: note: Ran expression as '{{(ISO )?}}C++{{.*}}'
 
 expr -l objc -- blah
 

I get the same output regardless of the PDB reader (modulo some errors about incomplete types with DIA).

Thanks! I'll check in the suggested patch. Fingers crossed

Argh still fails with the modified output: 62ac791

Could you pull the change and see if it also fails on your machine? Maybe I copied it wrong? Or the LLD requirement that I removed broke it?

@Nerixyz
Copy link
Contributor

Nerixyz commented Oct 13, 2025

Argh still fails with the modified output: 62ac791

That's an older patch. Did you mean fc22b58? That one hasn't had any Windows builds yet. Looks like it fixed CI: https://lab.llvm.org/buildbot/#/builders/211/builds/2850 was the first successful build.

@Michael137
Copy link
Member Author

Great! thanks all

akadutta pushed a commit to akadutta/llvm-project that referenced this pull request Oct 14, 2025
…lvm#162048)

Currently `llvm::dwarf::LanguageDescription` returns a stringified
`DW_LNAME`. It would be useful to have an API that returns the language
name for a particular `DW_LNAME_`/version pair. LLDB's use case is that
it wants to emit diagnostics with human readable descriptions of the
language we got from debug-info (see
llvm#161688). We could maintain a
side-table in LLDB but thought this might be generally useful and should
live next to the existing `LanguageDescription` API.
akadutta pushed a commit to akadutta/llvm-project that referenced this pull request Oct 14, 2025
…ge used for expression evaluation (llvm#161688)

Depends on:
* llvm#162050

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
llvm#156648).

Here are some example outputs:
```
# Without target
(lldb) expr blah
note: Falling back to default language. Ran expression as 'Objective C++'.

# Stopped in target
(lldb) expr blah
note: Ran expression as 'C++14'.

(lldb) expr -l objc -- blah
note: Expression evaluation in pure Objective-C not supported. Ran expression as 'Objective C++'.

(lldb) expr -l c -- blah
note: Expression evaluation in pure C not supported. Ran expression as 'ISO C++'.

(lldb) expr -l c++14 -- blah
note: Ran expression as 'C++14'

(lldb) expr -l c++20 -- blah
note: Ran expression as 'C++20'

(lldb) expr -l objective-c++ -- blah
note: Ran expression as 'Objective C++'

(lldb) expr -l D -- blah
note: Expression evaluation in D not supported. Falling back to default language. Ran expression as 'Objective C++'.
```

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
rdar://159669244
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants