Skip to content

Commit d85069c

Browse files
authored
[LLDB] Re-land 'Update DIL handling of array subscripting' (#154269)
This attempts to fix the issues with the original PR (#151605), updating the DIL code for handling array subscripting to more closely match and handle all the casees from the original 'frame var' implementation. The first PR did not include special-case code for objc pointers, which apparently caused a test failure on the green-dragon buildbot. Hopefully this PR, which includes the objc pointer special code, fixes that issue.
1 parent ff4b292 commit d85069c

File tree

4 files changed

+178
-34
lines changed

4 files changed

+178
-34
lines changed

lldb/source/ValueObject/DILEval.cpp

Lines changed: 122 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -330,40 +330,135 @@ Interpreter::Visit(const ArraySubscriptNode *node) {
330330
return lhs_or_err;
331331
lldb::ValueObjectSP base = *lhs_or_err;
332332

333-
// Check to see if 'base' has a synthetic value; if so, try using that.
333+
StreamString var_expr_path_strm;
334334
uint64_t child_idx = node->GetIndex();
335-
if (lldb::ValueObjectSP synthetic = base->GetSyntheticValue()) {
336-
llvm::Expected<uint32_t> num_children =
337-
synthetic->GetNumChildren(child_idx + 1);
338-
if (!num_children)
339-
return llvm::make_error<DILDiagnosticError>(
340-
m_expr, toString(num_children.takeError()), node->GetLocation());
341-
if (child_idx >= *num_children) {
342-
std::string message = llvm::formatv(
343-
"array index {0} is not valid for \"({1}) {2}\"", child_idx,
335+
lldb::ValueObjectSP child_valobj_sp;
336+
337+
bool is_incomplete_array = false;
338+
CompilerType base_type = base->GetCompilerType().GetNonReferenceType();
339+
base->GetExpressionPath(var_expr_path_strm);
340+
341+
if (base_type.IsPointerType()) {
342+
bool is_objc_pointer = true;
343+
344+
if (base->GetCompilerType().GetMinimumLanguage() != lldb::eLanguageTypeObjC)
345+
is_objc_pointer = false;
346+
else if (!base->GetCompilerType().IsPointerType())
347+
is_objc_pointer = false;
348+
349+
if (!m_use_synthetic && is_objc_pointer) {
350+
std::string err_msg = llvm::formatv(
351+
"\"({0}) {1}\" is an Objective-C pointer, and cannot be subscripted",
344352
base->GetTypeName().AsCString("<invalid type>"),
345-
base->GetName().AsCString());
346-
return llvm::make_error<DILDiagnosticError>(m_expr, message,
353+
var_expr_path_strm.GetData());
354+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
347355
node->GetLocation());
348356
}
349-
if (lldb::ValueObjectSP child_valobj_sp =
350-
synthetic->GetChildAtIndex(child_idx))
357+
if (is_objc_pointer) {
358+
lldb::ValueObjectSP synthetic = base->GetSyntheticValue();
359+
if (!synthetic || synthetic == base) {
360+
std::string err_msg =
361+
llvm::formatv("\"({0}) {1}\" is not an array type",
362+
base->GetTypeName().AsCString("<invalid type>"),
363+
var_expr_path_strm.GetData());
364+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
365+
node->GetLocation());
366+
}
367+
if (static_cast<uint32_t>(child_idx) >=
368+
synthetic->GetNumChildrenIgnoringErrors()) {
369+
std::string err_msg = llvm::formatv(
370+
"array index {0} is not valid for \"({1}) {2}\"", child_idx,
371+
base->GetTypeName().AsCString("<invalid type>"),
372+
var_expr_path_strm.GetData());
373+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
374+
node->GetLocation());
375+
}
376+
child_valobj_sp = synthetic->GetChildAtIndex(child_idx);
377+
if (!child_valobj_sp) {
378+
std::string err_msg = llvm::formatv(
379+
"array index {0} is not valid for \"({1}) {2}\"", child_idx,
380+
base->GetTypeName().AsCString("<invalid type>"),
381+
var_expr_path_strm.GetData());
382+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
383+
node->GetLocation());
384+
}
385+
if (m_use_dynamic != lldb::eNoDynamicValues) {
386+
if (auto dynamic_sp = child_valobj_sp->GetDynamicValue(m_use_dynamic))
387+
child_valobj_sp = std::move(dynamic_sp);
388+
}
351389
return child_valobj_sp;
352-
}
390+
}
353391

354-
auto base_type = base->GetCompilerType().GetNonReferenceType();
355-
if (!base_type.IsPointerType() && !base_type.IsArrayType())
356-
return llvm::make_error<DILDiagnosticError>(
357-
m_expr, "subscripted value is not an array or pointer",
358-
node->GetLocation());
359-
if (base_type.IsPointerToVoid())
360-
return llvm::make_error<DILDiagnosticError>(
361-
m_expr, "subscript of pointer to incomplete type 'void'",
362-
node->GetLocation());
392+
child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true);
393+
if (!child_valobj_sp) {
394+
std::string err_msg = llvm::formatv(
395+
"failed to use pointer as array for index {0} for "
396+
"\"({1}) {2}\"",
397+
child_idx, base->GetTypeName().AsCString("<invalid type>"),
398+
var_expr_path_strm.GetData());
399+
if (base_type.IsPointerToVoid())
400+
err_msg = "subscript of pointer to incomplete type 'void'";
401+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
402+
node->GetLocation());
403+
}
404+
} else if (base_type.IsArrayType(nullptr, nullptr, &is_incomplete_array)) {
405+
child_valobj_sp = base->GetChildAtIndex(child_idx);
406+
if (!child_valobj_sp && (is_incomplete_array || m_use_synthetic))
407+
child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true);
408+
if (!child_valobj_sp) {
409+
std::string err_msg = llvm::formatv(
410+
"array index {0} is not valid for \"({1}) {2}\"", child_idx,
411+
base->GetTypeName().AsCString("<invalid type>"),
412+
var_expr_path_strm.GetData());
413+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
414+
node->GetLocation());
415+
}
416+
} else if (base_type.IsScalarType()) {
417+
child_valobj_sp =
418+
base->GetSyntheticBitFieldChild(child_idx, child_idx, true);
419+
if (!child_valobj_sp) {
420+
std::string err_msg = llvm::formatv(
421+
"bitfield range {0}-{1} is not valid for \"({2}) {3}\"", child_idx,
422+
child_idx, base->GetTypeName().AsCString("<invalid type>"),
423+
var_expr_path_strm.GetData());
424+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
425+
node->GetLocation(), 1);
426+
}
427+
} else {
428+
lldb::ValueObjectSP synthetic = base->GetSyntheticValue();
429+
if (!m_use_synthetic || !synthetic || synthetic == base) {
430+
std::string err_msg =
431+
llvm::formatv("\"{0}\" is not an array type",
432+
base->GetTypeName().AsCString("<invalid type>"));
433+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
434+
node->GetLocation(), 1);
435+
}
436+
if (static_cast<uint32_t>(child_idx) >=
437+
synthetic->GetNumChildrenIgnoringErrors(child_idx + 1)) {
438+
std::string err_msg = llvm::formatv(
439+
"array index {0} is not valid for \"({1}) {2}\"", child_idx,
440+
base->GetTypeName().AsCString("<invalid type>"),
441+
var_expr_path_strm.GetData());
442+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
443+
node->GetLocation(), 1);
444+
}
445+
child_valobj_sp = synthetic->GetChildAtIndex(child_idx);
446+
if (!child_valobj_sp) {
447+
std::string err_msg = llvm::formatv(
448+
"array index {0} is not valid for \"({1}) {2}\"", child_idx,
449+
base->GetTypeName().AsCString("<invalid type>"),
450+
var_expr_path_strm.GetData());
451+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
452+
node->GetLocation(), 1);
453+
}
454+
}
363455

364-
if (base_type.IsArrayType()) {
365-
if (lldb::ValueObjectSP child_valobj_sp = base->GetChildAtIndex(child_idx))
366-
return child_valobj_sp;
456+
if (child_valobj_sp) {
457+
if (m_use_dynamic != lldb::eNoDynamicValues) {
458+
if (auto dynamic_sp = child_valobj_sp->GetDynamicValue(m_use_dynamic))
459+
child_valobj_sp = std::move(dynamic_sp);
460+
}
461+
return child_valobj_sp;
367462
}
368463

369464
int64_t signed_child_idx = node->GetIndex();

lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,18 @@ def test_subscript(self):
6969
substrs=["expected 'r_square', got: <'.'"],
7070
)
7171

72-
# Base should be a "pointer to T" and index should be of an integral type.
73-
self.expect(
74-
"frame var 'idx_1[0]'",
75-
error=True,
76-
substrs=["subscripted value is not an array or pointer"],
77-
)
72+
# Test accessing bits in scalar types.
73+
self.expect_var_path("idx_1[0]", value="1")
74+
self.expect_var_path("idx_1[1]", value="0")
75+
76+
# Bit adcess not valid for a reference.
7877
self.expect(
7978
"frame var 'idx_1_ref[0]'",
8079
error=True,
81-
substrs=["subscripted value is not an array or pointer"],
80+
substrs=["bitfield range 0-0 is not valid"],
8281
)
82+
83+
# Base should be a "pointer to T" and index should be of an integral type.
8384
self.expect(
8485
"frame var 'int_arr[int_ptr]'",
8586
error=True,
@@ -105,6 +106,8 @@ def test_subscript_synthetic(self):
105106
)
106107

107108
self.runCmd("settings set target.experimental.use-DIL true")
109+
self.runCmd("script from myArraySynthProvider import *")
110+
self.runCmd("type synth add -l myArraySynthProvider myArray")
108111

109112
# Test synthetic value subscription
110113
self.expect_var_path("vector[1]", value="2")
@@ -113,3 +116,7 @@ def test_subscript_synthetic(self):
113116
error=True,
114117
substrs=["array index 100 is not valid"],
115118
)
119+
self.expect(
120+
"frame var 'ma_ptr[0]'",
121+
substrs=["(myArray) ma_ptr[0] = ([0] = 7, [1] = 8, [2] = 9, [3] = 10)"],
122+
)

lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/main.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
#include <vector>
22

3+
class myArray {
4+
public:
5+
int m_array[4] = {7, 8, 9, 10};
6+
int m_arr_size = 4;
7+
};
8+
39
int main(int argc, char **argv) {
410
int int_arr[] = {1, 2, 3};
511
int *int_ptr = int_arr;
@@ -29,5 +35,8 @@ int main(int argc, char **argv) {
2935

3036
std::vector<int> vector = {1, 2, 3};
3137

38+
myArray ma;
39+
myArray *ma_ptr = &ma;
40+
3241
return 0; // Set a breakpoint here
3342
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import lldb
2+
3+
4+
class myArraySynthProvider:
5+
def __init__(self, valobj, dict):
6+
self.valobj = valobj
7+
8+
def num_children(self):
9+
size_valobj = self.valobj.GetChildMemberWithName("m_arr_size")
10+
if size_valobj:
11+
return size_valobj.GetValueAsUnsigned(0)
12+
return 0
13+
14+
def get_child_at_index(self, index):
15+
size_valobj = self.valobj.GetChildMemberWithName("m_arr_size")
16+
arr = self.valobj.GetChildMemberWithName("m_array")
17+
if not size_valobj or not arr:
18+
return None
19+
max_idx = size_valobj.GetValueAsUnsigned(0)
20+
if index >= max_idx:
21+
return None
22+
return arr.GetChildAtIndex(index)
23+
24+
def get_child_index(self, name):
25+
if name == "[0]":
26+
return 0
27+
if name == "[1]":
28+
return
29+
if name == "[2]":
30+
return 2
31+
if name == "[3]":
32+
return 3
33+
return -1

0 commit comments

Comments
 (0)