[Lldb-commits] [lldb] [LLDB] Update DIL to pass current 'frame var' tests. (PR #145055)

2025-06-29 Thread via lldb-commits

https://github.com/cmtice updated 
https://github.com/llvm/llvm-project/pull/145055

>From e9079e6357b933e84603997edb8d0cd27a515989 Mon Sep 17 00:00:00 2001
From: Caroline Tice 
Date: Fri, 20 Jun 2025 08:33:14 -0700
Subject: [PATCH 1/6] [LLDB] Update DIL to pass current 'frame var' tests.

As a preliminary to making DIL the default implementation for 'frame var',
ran check-lldb forcing 'frame var' to always use DIL, and discovered a few
failing tests. This fixes most of them. The only two remaining failing tests
(once the smart pointer PR is committed) are TestVarPath.py, which fails a
test case using a negative array subscript, as DIL does not yet parse negative
numbers; and TestDAP_evaluate.py, which now passes a test case that the test 
says should fail (still investigating this).

Changes in this PR:
 - Sets correct VariableSP, as well as returning ValueObjectSP (needed for
   several watchpoint tests).
 - Update error messages, when looking up members, to match what the rest of
   LLDB expects. Also update appropriate DIL tests to expect the updated error
   messages.
 - Update DIL parser to look for and accept "(anonymous namespace)::" at the
   front of a variable name.
---
 lldb/source/Target/StackFrame.cpp |  1 +
 lldb/source/ValueObject/DILEval.cpp   | 10 ++---
 lldb/source/ValueObject/DILParser.cpp | 39 ---
 .../MemberOf/TestFrameVarDILMemberOf.py   |  2 +-
 .../TestFrameVarDILMemberOfAnonymousMember.py | 10 ++---
 5 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/lldb/source/Target/StackFrame.cpp 
b/lldb/source/Target/StackFrame.cpp
index ab5cd0b27c789..f5a80efc821d5 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -562,6 +562,7 @@ ValueObjectSP 
StackFrame::DILGetValueForVariableExpressionPath(
 return ValueObjectConstResult::Create(nullptr, std::move(error));
   }
 
+  var_sp = (*valobj_or_error)->GetVariable();
   return *valobj_or_error;
 }
 
diff --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index c8cb54aa18a93..2c4d355a2c6b8 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -356,8 +356,8 @@ Interpreter::Visit(const MemberOfNode *node) {
 
 if (!m_use_synthetic || !field_obj) {
   std::string errMsg = llvm::formatv(
-  "no member named '{0}' in {1}", node->GetFieldName(),
-  base->GetCompilerType().GetFullyUnqualifiedType().TypeDescription());
+  "\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
+  base->GetTypeName().AsCString(""), base->GetName());
   return llvm::make_error(
   m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
 }
@@ -376,9 +376,9 @@ Interpreter::Visit(const MemberOfNode *node) {
   CompilerType base_type = base->GetCompilerType();
   if (node->GetIsArrow() && base->IsPointerType())
 base_type = base_type.GetPointeeType();
-  std::string errMsg =
-  llvm::formatv("no member named '{0}' in {1}", node->GetFieldName(),
-base_type.GetFullyUnqualifiedType().TypeDescription());
+  std::string errMsg = llvm::formatv(
+  "\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
+  base->GetTypeName().AsCString(""), base->GetName());
   return llvm::make_error(
   m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
 }
diff --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index 9667885734f21..37d5bd30fa61f 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -178,11 +178,40 @@ ASTNodeUP DILParser::ParsePrimaryExpression() {
   }
 
   if (CurToken().Is(Token::l_paren)) {
-m_dil_lexer.Advance();
-auto expr = ParseExpression();
-Expect(Token::r_paren);
-m_dil_lexer.Advance();
-return expr;
+// Check in case this is an anonynmous namespace
+if (m_dil_lexer.LookAhead(1).Is(Token::identifier) &&
+(m_dil_lexer.LookAhead(1).GetSpelling() == "anonymous") &&
+m_dil_lexer.LookAhead(2).Is(Token::identifier) &&
+(m_dil_lexer.LookAhead(2).GetSpelling() == "namespace") &&
+m_dil_lexer.LookAhead(3).Is(Token::r_paren) &&
+m_dil_lexer.LookAhead(4).Is(Token::coloncolon)) {
+  m_dil_lexer.Advance(4);
+
+  std::string identifier = "(anonymous namespace)";
+  Expect(Token::coloncolon);
+  // Save the source location for the diagnostics message.
+  uint32_t loc = CurToken().GetLocation();
+  m_dil_lexer.Advance();
+  assert(
+  (CurToken().Is(Token::identifier) || CurToken().Is(Token::l_paren)) 
&&
+  "Expected an identifier or anonymous namespeace, but not found.");
+  std::string identifier2 = ParseNestedNameSpecifier();
+  if (identifier2.empty()) {
+// There was only an identifer, no more levels of nesting. Or there
+// was an invalid expression sta

[Lldb-commits] [lldb] [LLDB] Update DIL to pass current 'frame var' tests. (PR #145055)

2025-06-29 Thread via lldb-commits

cmtice wrote:

I think I have addressed all your concerns. Please take another look; thanks!

https://github.com/llvm/llvm-project/pull/145055
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [lldb-dap] Prevent using an implicit `step-in`. (PR #143644)

2025-06-29 Thread Ebuka Ezike via lldb-commits

https://github.com/da-viper updated 
https://github.com/llvm/llvm-project/pull/143644

>From 24e8bbe12758773ef9ca55c3c4022a610db434e9 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike 
Date: Wed, 11 Jun 2025 02:14:12 +0100
Subject: [PATCH] [lldb-dap] Prevent using an implicit `step-in`.

When there is a function that is inlined at the current program counter. If you 
get the current `line_entry` using the program counter's address it will point 
to the location of the inline function that may be in another file. (this is in 
implicit step-in and should not happen what step over is called).

Use the current frame to get the correct `line_entry`
---
 .../test/tools/lldb-dap/lldbdap_testcase.py   |  7 +++-
 .../API/tools/lldb-dap/step/TestDAP_step.py   | 37 +++
 lldb/test/API/tools/lldb-dap/step/main.cpp| 14 ++-
 lldb/test/API/tools/lldb-dap/step/other.h |  7 
 lldb/tools/lldb-dap/DAP.cpp   | 11 ++
 lldb/tools/lldb-dap/DAP.h | 11 ++
 lldb/tools/lldb-dap/JSONUtils.cpp |  7 +---
 7 files changed, 87 insertions(+), 7 deletions(-)
 create mode 100644 lldb/test/API/tools/lldb-dap/step/other.h

diff --git 
a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py 
b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
index 3b54d598c3509..6299caf7631af 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
@@ -344,7 +344,12 @@ def stepOver(
 granularity="statement",
 timeout=DEFAULT_TIMEOUT,
 ):
-self.dap_server.request_next(threadId=threadId, 
granularity=granularity)
+response = self.dap_server.request_next(
+threadId=threadId, granularity=granularity
+)
+self.assertTrue(
+response["success"], f"next request failed: response {response}"
+)
 if waitForStop:
 return self.dap_server.wait_for_stopped(timeout)
 return None
diff --git a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py 
b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py
index 42a39e3c8c080..5339e0bab1d5e 100644
--- a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py
+++ b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py
@@ -83,3 +83,40 @@ def test_step(self):
 
 # only step one thread that is at the breakpoint and stop
 break
+
+def test_step_over(self):
+"""
+Test stepping over when the program counter is in another file.
+"""
+program = self.getBuildArtifact("a.out")
+self.build_and_launch(program)
+source = "main.cpp"
+breakpoint1_line = line_number(source, "// breakpoint 2")
+step_over_pos = line_number(source, "// position_after_step_over")
+lines = [breakpoint1_line]
+breakpoint_ids = self.set_source_breakpoints(source, lines)
+self.assertEqual(
+len(breakpoint_ids), len(lines), "expect correct number of 
breakpoints."
+)
+self.continue_to_breakpoints(breakpoint_ids)
+
+thread_id = self.dap_server.get_thread_id()
+self.stepOver(thread_id)
+levels = 1
+frames = self.get_stackFrames(thread_id, 0, levels)
+self.assertEqual(len(frames), levels, "expect current number of frame 
levels.")
+top_frame = frames[0]
+self.assertEqual(
+top_frame["source"]["name"], source, "expect we are in the same 
file."
+)
+self.assertTrue(
+top_frame["source"]["path"].endswith(source),
+f"expect path ending with '{source}'.",
+)
+self.assertEqual(
+top_frame["line"],
+step_over_pos,
+f"expect step_over on line {step_over_pos}",
+)
+
+self.continue_to_exit()
diff --git a/lldb/test/API/tools/lldb-dap/step/main.cpp 
b/lldb/test/API/tools/lldb-dap/step/main.cpp
index 8905beb5e7eff..7320e83154f5b 100644
--- a/lldb/test/API/tools/lldb-dap/step/main.cpp
+++ b/lldb/test/API/tools/lldb-dap/step/main.cpp
@@ -1,3 +1,5 @@
+#include "other.h"
+
 int function(int x) {
   if ((x % 2) == 0)
 return function(x - 1) + x; // breakpoint 1
@@ -5,4 +7,14 @@ int function(int x) {
 return x;
 }
 
-int main(int argc, char const *argv[]) { return function(2); }
+int function2() {
+  int volatile value = 3; // breakpoint 2
+  inlined_fn();   // position_after_step_over
+
+  return value;
+}
+
+int main(int argc, char const *argv[]) {
+  int func_result = function2();
+  return function(2) - func_result; // returns 0
+}
diff --git a/lldb/test/API/tools/lldb-dap/step/other.h 
b/lldb/test/API/tools/lldb-dap/step/other.h
new file mode 100644
index 0..c71cc373fbdff
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/step/other.h
@@ -0,0 +1,7 @@
+#ifndef OTHER_H
+#define OTHER_H
+
+__attribute__((noinline)) void not_inl

[Lldb-commits] [lldb] [lldb-dap] Prevent using an implicit `step-in`. (PR #143644)

2025-06-29 Thread Ebuka Ezike via lldb-commits

https://github.com/da-viper updated 
https://github.com/llvm/llvm-project/pull/143644

>From 6ff8149d35aa931c7f08373d92cf556ad0d9abc3 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike 
Date: Wed, 11 Jun 2025 02:14:12 +0100
Subject: [PATCH] [lldb-dap] Prevent using an implicit `step-in`.

When there is a function that is inlined at the current program counter. If you 
get the current `line_entry` using the program counter's address it will point 
to the location of the inline function that may be in another file. (this is in 
implicit step-in and should not happen what step over is called).

Use the current frame to get the correct `line_entry`
---
 .../test/tools/lldb-dap/lldbdap_testcase.py   |  7 +++-
 .../API/tools/lldb-dap/step/TestDAP_step.py   | 37 +++
 lldb/test/API/tools/lldb-dap/step/main.cpp| 14 ++-
 lldb/test/API/tools/lldb-dap/step/other.h |  7 
 lldb/tools/lldb-dap/DAP.cpp   | 11 ++
 lldb/tools/lldb-dap/DAP.h | 11 ++
 lldb/tools/lldb-dap/JSONUtils.cpp |  7 +---
 7 files changed, 87 insertions(+), 7 deletions(-)
 create mode 100644 lldb/test/API/tools/lldb-dap/step/other.h

diff --git 
a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py 
b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
index 3b54d598c3509..6299caf7631af 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
@@ -344,7 +344,12 @@ def stepOver(
 granularity="statement",
 timeout=DEFAULT_TIMEOUT,
 ):
-self.dap_server.request_next(threadId=threadId, 
granularity=granularity)
+response = self.dap_server.request_next(
+threadId=threadId, granularity=granularity
+)
+self.assertTrue(
+response["success"], f"next request failed: response {response}"
+)
 if waitForStop:
 return self.dap_server.wait_for_stopped(timeout)
 return None
diff --git a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py 
b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py
index 42a39e3c8c080..5339e0bab1d5e 100644
--- a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py
+++ b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py
@@ -83,3 +83,40 @@ def test_step(self):
 
 # only step one thread that is at the breakpoint and stop
 break
+
+def test_step_over(self):
+"""
+Test stepping over when the program counter is in another file.
+"""
+program = self.getBuildArtifact("a.out")
+self.build_and_launch(program)
+source = "main.cpp"
+breakpoint1_line = line_number(source, "// breakpoint 2")
+step_over_pos = line_number(source, "// position_after_step_over")
+lines = [breakpoint1_line]
+breakpoint_ids = self.set_source_breakpoints(source, lines)
+self.assertEqual(
+len(breakpoint_ids), len(lines), "expect correct number of 
breakpoints."
+)
+self.continue_to_breakpoints(breakpoint_ids)
+
+thread_id = self.dap_server.get_thread_id()
+self.stepOver(thread_id)
+levels = 1
+frames = self.get_stackFrames(thread_id, 0, levels)
+self.assertEqual(len(frames), levels, "expect current number of frame 
levels.")
+top_frame = frames[0]
+self.assertEqual(
+top_frame["source"]["name"], source, "expect we are in the same 
file."
+)
+self.assertTrue(
+top_frame["source"]["path"].endswith(source),
+f"expect path ending with '{source}'.",
+)
+self.assertEqual(
+top_frame["line"],
+step_over_pos,
+f"expect step_over on line {step_over_pos}",
+)
+
+self.continue_to_exit()
diff --git a/lldb/test/API/tools/lldb-dap/step/main.cpp 
b/lldb/test/API/tools/lldb-dap/step/main.cpp
index 8905beb5e7eff..9454fa7a7855a 100644
--- a/lldb/test/API/tools/lldb-dap/step/main.cpp
+++ b/lldb/test/API/tools/lldb-dap/step/main.cpp
@@ -1,3 +1,5 @@
+#include "other.h"
+
 int function(int x) {
   if ((x % 2) == 0)
 return function(x - 1) + x; // breakpoint 1
@@ -5,4 +7,14 @@ int function(int x) {
 return x;
 }
 
-int main(int argc, char const *argv[]) { return function(2); }
+int function2() {
+  int volatile value = 3; // breakpoint 2
+  fn2();  // position_after_step_over
+
+  return value;
+}
+
+int main(int argc, char const *argv[]) {
+  int func_result = function2();
+  return function(2) - func_result; // returns 0
+}
diff --git a/lldb/test/API/tools/lldb-dap/step/other.h 
b/lldb/test/API/tools/lldb-dap/step/other.h
new file mode 100644
index 0..aad022bbc2615
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/step/other.h
@@ -0,0 +1,7 @@
+#ifndef OTHER_H
+#define OTHER_H
+
+__attribute__((noinline)) void fn1() {

[Lldb-commits] [lldb] [lldb-dap] Prevent using an implicit `step-in`. (PR #143644)

2025-06-29 Thread Ebuka Ezike via lldb-commits

da-viper wrote:

> Would it work if we replace the call to `fn1` with some other statement -- 
> one that doesn't involve function calls. E.g. maybe assignment to a volatile 
> variable. 

Yeah it is reproducible with a volatile variable before the function call.



https://github.com/llvm/llvm-project/pull/143644
___
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits


[Lldb-commits] [lldb] [LLDB] Update DIL to pass current 'frame var' tests. (PR #145055)

2025-06-29 Thread via lldb-commits

https://github.com/cmtice updated 
https://github.com/llvm/llvm-project/pull/145055

>From e9079e6357b933e84603997edb8d0cd27a515989 Mon Sep 17 00:00:00 2001
From: Caroline Tice 
Date: Fri, 20 Jun 2025 08:33:14 -0700
Subject: [PATCH 1/5] [LLDB] Update DIL to pass current 'frame var' tests.

As a preliminary to making DIL the default implementation for 'frame var',
ran check-lldb forcing 'frame var' to always use DIL, and discovered a few
failing tests. This fixes most of them. The only two remaining failing tests
(once the smart pointer PR is committed) are TestVarPath.py, which fails a
test case using a negative array subscript, as DIL does not yet parse negative
numbers; and TestDAP_evaluate.py, which now passes a test case that the test 
says should fail (still investigating this).

Changes in this PR:
 - Sets correct VariableSP, as well as returning ValueObjectSP (needed for
   several watchpoint tests).
 - Update error messages, when looking up members, to match what the rest of
   LLDB expects. Also update appropriate DIL tests to expect the updated error
   messages.
 - Update DIL parser to look for and accept "(anonymous namespace)::" at the
   front of a variable name.
---
 lldb/source/Target/StackFrame.cpp |  1 +
 lldb/source/ValueObject/DILEval.cpp   | 10 ++---
 lldb/source/ValueObject/DILParser.cpp | 39 ---
 .../MemberOf/TestFrameVarDILMemberOf.py   |  2 +-
 .../TestFrameVarDILMemberOfAnonymousMember.py | 10 ++---
 5 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/lldb/source/Target/StackFrame.cpp 
b/lldb/source/Target/StackFrame.cpp
index ab5cd0b27c789..f5a80efc821d5 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -562,6 +562,7 @@ ValueObjectSP 
StackFrame::DILGetValueForVariableExpressionPath(
 return ValueObjectConstResult::Create(nullptr, std::move(error));
   }
 
+  var_sp = (*valobj_or_error)->GetVariable();
   return *valobj_or_error;
 }
 
diff --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index c8cb54aa18a93..2c4d355a2c6b8 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -356,8 +356,8 @@ Interpreter::Visit(const MemberOfNode *node) {
 
 if (!m_use_synthetic || !field_obj) {
   std::string errMsg = llvm::formatv(
-  "no member named '{0}' in {1}", node->GetFieldName(),
-  base->GetCompilerType().GetFullyUnqualifiedType().TypeDescription());
+  "\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
+  base->GetTypeName().AsCString(""), base->GetName());
   return llvm::make_error(
   m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
 }
@@ -376,9 +376,9 @@ Interpreter::Visit(const MemberOfNode *node) {
   CompilerType base_type = base->GetCompilerType();
   if (node->GetIsArrow() && base->IsPointerType())
 base_type = base_type.GetPointeeType();
-  std::string errMsg =
-  llvm::formatv("no member named '{0}' in {1}", node->GetFieldName(),
-base_type.GetFullyUnqualifiedType().TypeDescription());
+  std::string errMsg = llvm::formatv(
+  "\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
+  base->GetTypeName().AsCString(""), base->GetName());
   return llvm::make_error(
   m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
 }
diff --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index 9667885734f21..37d5bd30fa61f 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -178,11 +178,40 @@ ASTNodeUP DILParser::ParsePrimaryExpression() {
   }
 
   if (CurToken().Is(Token::l_paren)) {
-m_dil_lexer.Advance();
-auto expr = ParseExpression();
-Expect(Token::r_paren);
-m_dil_lexer.Advance();
-return expr;
+// Check in case this is an anonynmous namespace
+if (m_dil_lexer.LookAhead(1).Is(Token::identifier) &&
+(m_dil_lexer.LookAhead(1).GetSpelling() == "anonymous") &&
+m_dil_lexer.LookAhead(2).Is(Token::identifier) &&
+(m_dil_lexer.LookAhead(2).GetSpelling() == "namespace") &&
+m_dil_lexer.LookAhead(3).Is(Token::r_paren) &&
+m_dil_lexer.LookAhead(4).Is(Token::coloncolon)) {
+  m_dil_lexer.Advance(4);
+
+  std::string identifier = "(anonymous namespace)";
+  Expect(Token::coloncolon);
+  // Save the source location for the diagnostics message.
+  uint32_t loc = CurToken().GetLocation();
+  m_dil_lexer.Advance();
+  assert(
+  (CurToken().Is(Token::identifier) || CurToken().Is(Token::l_paren)) 
&&
+  "Expected an identifier or anonymous namespeace, but not found.");
+  std::string identifier2 = ParseNestedNameSpecifier();
+  if (identifier2.empty()) {
+// There was only an identifer, no more levels of nesting. Or there
+// was an invalid expression sta

[Lldb-commits] [lldb] [LLDB] Update DIL to pass current 'frame var' tests. (PR #145055)

2025-06-29 Thread via lldb-commits

https://github.com/cmtice updated 
https://github.com/llvm/llvm-project/pull/145055

>From e9079e6357b933e84603997edb8d0cd27a515989 Mon Sep 17 00:00:00 2001
From: Caroline Tice 
Date: Fri, 20 Jun 2025 08:33:14 -0700
Subject: [PATCH 1/5] [LLDB] Update DIL to pass current 'frame var' tests.

As a preliminary to making DIL the default implementation for 'frame var',
ran check-lldb forcing 'frame var' to always use DIL, and discovered a few
failing tests. This fixes most of them. The only two remaining failing tests
(once the smart pointer PR is committed) are TestVarPath.py, which fails a
test case using a negative array subscript, as DIL does not yet parse negative
numbers; and TestDAP_evaluate.py, which now passes a test case that the test 
says should fail (still investigating this).

Changes in this PR:
 - Sets correct VariableSP, as well as returning ValueObjectSP (needed for
   several watchpoint tests).
 - Update error messages, when looking up members, to match what the rest of
   LLDB expects. Also update appropriate DIL tests to expect the updated error
   messages.
 - Update DIL parser to look for and accept "(anonymous namespace)::" at the
   front of a variable name.
---
 lldb/source/Target/StackFrame.cpp |  1 +
 lldb/source/ValueObject/DILEval.cpp   | 10 ++---
 lldb/source/ValueObject/DILParser.cpp | 39 ---
 .../MemberOf/TestFrameVarDILMemberOf.py   |  2 +-
 .../TestFrameVarDILMemberOfAnonymousMember.py | 10 ++---
 5 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/lldb/source/Target/StackFrame.cpp 
b/lldb/source/Target/StackFrame.cpp
index ab5cd0b27c789..f5a80efc821d5 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -562,6 +562,7 @@ ValueObjectSP 
StackFrame::DILGetValueForVariableExpressionPath(
 return ValueObjectConstResult::Create(nullptr, std::move(error));
   }
 
+  var_sp = (*valobj_or_error)->GetVariable();
   return *valobj_or_error;
 }
 
diff --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index c8cb54aa18a93..2c4d355a2c6b8 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -356,8 +356,8 @@ Interpreter::Visit(const MemberOfNode *node) {
 
 if (!m_use_synthetic || !field_obj) {
   std::string errMsg = llvm::formatv(
-  "no member named '{0}' in {1}", node->GetFieldName(),
-  base->GetCompilerType().GetFullyUnqualifiedType().TypeDescription());
+  "\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
+  base->GetTypeName().AsCString(""), base->GetName());
   return llvm::make_error(
   m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
 }
@@ -376,9 +376,9 @@ Interpreter::Visit(const MemberOfNode *node) {
   CompilerType base_type = base->GetCompilerType();
   if (node->GetIsArrow() && base->IsPointerType())
 base_type = base_type.GetPointeeType();
-  std::string errMsg =
-  llvm::formatv("no member named '{0}' in {1}", node->GetFieldName(),
-base_type.GetFullyUnqualifiedType().TypeDescription());
+  std::string errMsg = llvm::formatv(
+  "\"{0}\" is not a member of \"({1}) {2}\"", node->GetFieldName(),
+  base->GetTypeName().AsCString(""), base->GetName());
   return llvm::make_error(
   m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
 }
diff --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index 9667885734f21..37d5bd30fa61f 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -178,11 +178,40 @@ ASTNodeUP DILParser::ParsePrimaryExpression() {
   }
 
   if (CurToken().Is(Token::l_paren)) {
-m_dil_lexer.Advance();
-auto expr = ParseExpression();
-Expect(Token::r_paren);
-m_dil_lexer.Advance();
-return expr;
+// Check in case this is an anonynmous namespace
+if (m_dil_lexer.LookAhead(1).Is(Token::identifier) &&
+(m_dil_lexer.LookAhead(1).GetSpelling() == "anonymous") &&
+m_dil_lexer.LookAhead(2).Is(Token::identifier) &&
+(m_dil_lexer.LookAhead(2).GetSpelling() == "namespace") &&
+m_dil_lexer.LookAhead(3).Is(Token::r_paren) &&
+m_dil_lexer.LookAhead(4).Is(Token::coloncolon)) {
+  m_dil_lexer.Advance(4);
+
+  std::string identifier = "(anonymous namespace)";
+  Expect(Token::coloncolon);
+  // Save the source location for the diagnostics message.
+  uint32_t loc = CurToken().GetLocation();
+  m_dil_lexer.Advance();
+  assert(
+  (CurToken().Is(Token::identifier) || CurToken().Is(Token::l_paren)) 
&&
+  "Expected an identifier or anonymous namespeace, but not found.");
+  std::string identifier2 = ParseNestedNameSpecifier();
+  if (identifier2.empty()) {
+// There was only an identifer, no more levels of nesting. Or there
+// was an invalid expression sta