[Lldb-commits] [lldb] [LLDB] Update DIL to pass current 'frame var' tests. (PR #145055)
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)
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)
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)
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)
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)
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)
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