[Lldb-commits] [lldb] [LLDB] Update DIL to pass current 'frame var' tests. (PR #145055)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Jun 20 09:18:08 PDT 2025
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 <cmtice at google.com>
Date: Fri, 20 Jun 2025 08:33:14 -0700
Subject: [PATCH 1/4] [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("<invalid type>"), base->GetName());
return llvm::make_error<DILDiagnosticError>(
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("<invalid type>"), base->GetName());
return llvm::make_error<DILDiagnosticError>(
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 starting with a left parenthesis.
+ Expect(Token::identifier);
+ identifier2 = CurToken().GetSpelling();
+ m_dil_lexer.Advance();
+ }
+ identifier = identifier + "::" + identifier2;
+ return std::make_unique<IdentifierNode>(loc, identifier);
+ } else {
+ m_dil_lexer.Advance();
+ auto expr = ParseExpression();
+ Expect(Token::r_paren);
+ m_dil_lexer.Advance();
+ return expr;
+ }
}
BailOut(llvm::formatv("Unexpected token: {0}", CurToken()),
diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
index bb16c1f82489d..c204b75941a2f 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
@@ -32,7 +32,7 @@ def test_frame_var(self):
self.expect_var_path("sp->r", type="int &")
self.expect("frame variable 'sp->foo'", error=True,
- substrs=["no member named 'foo' in 'Sx *'"])
+ substrs=["\"foo\" is not a member of \"(Sx *) sp\""])
self.expect("frame variable 'sp.x'", error=True,
substrs=["member reference type 'Sx *' is a "
diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py
index 1bde4706da90f..eb6261aefb5c8 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py
@@ -28,7 +28,7 @@ def test_frame_var(self):
self.expect_var_path("a.y", value="2")
self.expect("frame variable 'b.x'", error=True,
- substrs=["no member named 'x' in 'B'"])
+ substrs=["\"x\" is not a member of \"(B) b\""])
#self.expect_var_path("b.y", value="0")
self.expect_var_path("b.z", value="3")
self.expect_var_path("b.w", value="4")
@@ -44,18 +44,18 @@ def test_frame_var(self):
self.expect_var_path("d.w", value="10")
self.expect("frame variable 'e.x'", error=True,
- substrs=["no member named 'x' in 'E'"])
+ substrs=["\"x\" is not a member of \"(E) e\""])
self.expect("frame variable 'f.x'", error=True,
- substrs=["no member named 'x' in 'F'"])
+ substrs=["\"x\" is not a member of \"(F) f\""])
self.expect_var_path("f.named_field.x", value="12")
self.expect_var_path("unnamed_derived.y", value="2")
self.expect_var_path("unnamed_derived.z", value="13")
self.expect("frame variable 'derb.x'", error=True,
- substrs=["no member named 'x' in 'DerivedB'"])
+ substrs=["\"x\" is not a member of \"(DerivedB) derb\""])
self.expect("frame variable 'derb.y'", error=True,
- substrs=["no member named 'y' in 'DerivedB'"])
+ substrs=["\"y\" is not a member of \"(DerivedB) derb\""])
self.expect_var_path("derb.w", value="14")
self.expect_var_path("derb.k", value="15")
self.expect_var_path("derb.a.x", value="1")
>From e7ae837e44baa64fd5fe73d34ee2b0d968ab3e08 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Fri, 20 Jun 2025 08:49:31 -0700
Subject: [PATCH 2/4] Fix clang-format issues.
---
.../MemberOf/TestFrameVarDILMemberOf.py | 18 ++++++----
.../TestFrameVarDILMemberOfAnonymousMember.py | 35 +++++++++++++------
2 files changed, 37 insertions(+), 16 deletions(-)
diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
index c204b75941a2f..2fb6a49058cf7 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
@@ -31,12 +31,18 @@ def test_frame_var(self):
self.expect_var_path("sp->x", value="1")
self.expect_var_path("sp->r", type="int &")
- self.expect("frame variable 'sp->foo'", error=True,
- substrs=["\"foo\" is not a member of \"(Sx *) sp\""])
-
- self.expect("frame variable 'sp.x'", error=True,
- substrs=["member reference type 'Sx *' is a "
- "pointer; did you mean to use '->'"])
+ self.expect(
+ "frame variable 'sp->foo'",
+ error=True,
+ substrs=["\"foo\" is not a member of \"(Sx *) sp\""],
+ )
+
+ self.expect(
+ "frame variable 'sp.x'",
+ error=True,
+ substrs=["member reference type 'Sx *' is a "
+ "pointer; did you mean to use '->'"],
+ )
# Test for record typedefs.
self.expect_var_path("sa.x", value="3")
diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py
index eb6261aefb5c8..3124133833946 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py
@@ -27,8 +27,11 @@ def test_frame_var(self):
self.expect_var_path("a.x", value="1")
self.expect_var_path("a.y", value="2")
- self.expect("frame variable 'b.x'", error=True,
- substrs=["\"x\" is not a member of \"(B) b\""])
+ self.expect(
+ "frame variable 'b.x'",
+ error=True,
+ substrs=["\"x\" is not a member of \"(B) b\""],
+ )
#self.expect_var_path("b.y", value="0")
self.expect_var_path("b.z", value="3")
self.expect_var_path("b.w", value="4")
@@ -43,19 +46,31 @@ def test_frame_var(self):
self.expect_var_path("d.z", value="9")
self.expect_var_path("d.w", value="10")
- self.expect("frame variable 'e.x'", error=True,
- substrs=["\"x\" is not a member of \"(E) e\""])
- self.expect("frame variable 'f.x'", error=True,
- substrs=["\"x\" is not a member of \"(F) f\""])
+ self.expect(
+ "frame variable 'e.x'",
+ error=True,
+ substrs=["\"x\" is not a member of \"(E) e\""],
+ )
+ self.expect(
+ "frame variable 'f.x'",
+ error=True,
+ substrs=["\"x\" is not a member of \"(F) f\""],
+ )
self.expect_var_path("f.named_field.x", value="12")
self.expect_var_path("unnamed_derived.y", value="2")
self.expect_var_path("unnamed_derived.z", value="13")
- self.expect("frame variable 'derb.x'", error=True,
- substrs=["\"x\" is not a member of \"(DerivedB) derb\""])
- self.expect("frame variable 'derb.y'", error=True,
- substrs=["\"y\" is not a member of \"(DerivedB) derb\""])
+ self.expect(
+ "frame variable 'derb.x'",
+ error=True,
+ substrs=["\"x\" is not a member of \"(DerivedB) derb\""],
+ )
+ self.expect(
+ "frame variable 'derb.y'",
+ error=True,
+ substrs=["\"y\" is not a member of \"(DerivedB) derb\""],
+ )
self.expect_var_path("derb.w", value="14")
self.expect_var_path("derb.k", value="15")
self.expect_var_path("derb.a.x", value="1")
>From f7fbde01b9d21e70597a079813115ebe713f55ab Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Fri, 20 Jun 2025 09:07:33 -0700
Subject: [PATCH 3/4] Fix more clang-format issues.
---
.../var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py | 7 ++++---
.../TestFrameVarDILMemberOfAnonymousMember.py | 10 +++++-----
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
index 2fb6a49058cf7..cf0c63bcda549 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
@@ -34,14 +34,15 @@ def test_frame_var(self):
self.expect(
"frame variable 'sp->foo'",
error=True,
- substrs=["\"foo\" is not a member of \"(Sx *) sp\""],
+ substrs=['"foo" is not a member of "(Sx *) sp"'],
)
self.expect(
"frame variable 'sp.x'",
error=True,
- substrs=["member reference type 'Sx *' is a "
- "pointer; did you mean to use '->'"],
+ substrs=[
+ "member reference type 'Sx *' is a pointer; did you mean to use '->'"]
+ ,
)
# Test for record typedefs.
diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py
index 3124133833946..856b3a069eec8 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOfAnonymousMember/TestFrameVarDILMemberOfAnonymousMember.py
@@ -30,7 +30,7 @@ def test_frame_var(self):
self.expect(
"frame variable 'b.x'",
error=True,
- substrs=["\"x\" is not a member of \"(B) b\""],
+ substrs=['"x" is not a member of "(B) b"'],
)
#self.expect_var_path("b.y", value="0")
self.expect_var_path("b.z", value="3")
@@ -49,12 +49,12 @@ def test_frame_var(self):
self.expect(
"frame variable 'e.x'",
error=True,
- substrs=["\"x\" is not a member of \"(E) e\""],
+ substrs=['"x" is not a member of "(E) e"'],
)
self.expect(
"frame variable 'f.x'",
error=True,
- substrs=["\"x\" is not a member of \"(F) f\""],
+ substrs=['"x" is not a member of "(F) f"'],
)
self.expect_var_path("f.named_field.x", value="12")
@@ -64,12 +64,12 @@ def test_frame_var(self):
self.expect(
"frame variable 'derb.x'",
error=True,
- substrs=["\"x\" is not a member of \"(DerivedB) derb\""],
+ substrs=['"x" is not a member of "(DerivedB) derb"'],
)
self.expect(
"frame variable 'derb.y'",
error=True,
- substrs=["\"y\" is not a member of \"(DerivedB) derb\""],
+ substrs=['"y" is not a member of "(DerivedB) derb"'],
)
self.expect_var_path("derb.w", value="14")
self.expect_var_path("derb.k", value="15")
>From c7c16bd625de454c0dddf393e6c3d87acf103af2 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Fri, 20 Jun 2025 09:17:37 -0700
Subject: [PATCH 4/4] Fix clang-format issue.
---
.../frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
index cf0c63bcda549..ca6754a556d89 100644
--- a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
+++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
@@ -41,8 +41,8 @@ def test_frame_var(self):
"frame variable 'sp.x'",
error=True,
substrs=[
- "member reference type 'Sx *' is a pointer; did you mean to use '->'"]
- ,
+ "member reference type 'Sx *' is a pointer; did you mean to use '->'"
+ ],
)
# Test for record typedefs.
More information about the lldb-commits
mailing list