Skip to content

Commit 0d51e89

Browse files
committed
[LLDB] Update DIL handling of array subscripting.
This updates the DIL code for handling array subscripting to more closely match and handle all the cases from the original 'frame var' implementation. Also updates the DIL array subscripting test. This particularly fixes some issues with handling synthetic children, objc pointers, and accessing specific bits within scalar data types.
1 parent 17ccb84 commit 0d51e89

File tree

2 files changed

+135
-36
lines changed

2 files changed

+135
-36
lines changed

lldb/source/ValueObject/DILEval.cpp

Lines changed: 126 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -323,47 +323,144 @@ Interpreter::Visit(const MemberOfNode *node) {
323323
m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
324324
}
325325

326+
326327
llvm::Expected<lldb::ValueObjectSP>
327328
Interpreter::Visit(const ArraySubscriptNode *node) {
328329
auto lhs_or_err = Evaluate(node->GetBase());
329330
if (!lhs_or_err)
330331
return lhs_or_err;
331332
lldb::ValueObjectSP base = *lhs_or_err;
332333

333-
// Check to see if 'base' has a synthetic value; if so, try using that.
334+
StreamString var_expr_path_strm;
334335
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,
344-
base->GetTypeName().AsCString("<invalid type>"),
345-
base->GetName().AsCString());
346-
return llvm::make_error<DILDiagnosticError>(m_expr, message,
336+
lldb::ValueObjectSP child_valobj_sp;
337+
bool is_incomplete_array = false;
338+
CompilerType base_type = base->GetCompilerType().GetNonReferenceType();
339+
base->GetExpressionPath(var_expr_path_strm);
340+
if (base_type.IsPointerType()) {
341+
bool is_objc_pointer = true;
342+
if (base->GetCompilerType().GetMinimumLanguage() != lldb::eLanguageTypeObjC)
343+
is_objc_pointer = false;
344+
else if (!base_type.IsPointerType())
345+
is_objc_pointer = false;
346+
347+
if (is_objc_pointer && !m_use_synthetic) {
348+
std::string errMsg =
349+
llvm::formatv("\"(({0}) {1}\" is an Objective-C pointer, and cannot "
350+
"be subscripted",
351+
base->GetTypeName().AsCString("<invalid type>"),
352+
base->GetName());
353+
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
354+
node->GetLocation());
355+
} else if (is_objc_pointer) {
356+
lldb::ValueObjectSP synthetic = base->GetSyntheticValue();
357+
if (!synthetic || synthetic == base) {
358+
std::string errMsg =
359+
llvm::formatv("\"({0}) {1}\" is not an array type",
360+
base->GetTypeName().AsCString("<invalid type>"),
361+
base->GetName());
362+
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
363+
node->GetLocation());
364+
} else if (static_cast<uint32_t>(child_idx) >=
365+
synthetic->GetNumChildrenIgnoringErrors()) {
366+
std::string errMsg =
367+
llvm::formatv("array index {0} is not valid for \"({1}) {2}\"",
368+
child_idx,
369+
base->GetTypeName().AsCString("<invalid type>"),
370+
var_expr_path_strm.GetData());
371+
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
372+
node->GetLocation());
373+
} else {
374+
child_valobj_sp = synthetic->GetChildAtIndex(child_idx);
375+
if (!child_valobj_sp) {
376+
std::string errMsg =
377+
llvm::formatv("array index {0} is not valid for \"({1}) {2}\"",
378+
child_idx,
379+
base->GetTypeName().AsCString("<invalid type>"),
380+
var_expr_path_strm.GetData());
381+
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
382+
node->GetLocation());
383+
}
384+
}
385+
} else { // it's not an objc pointer
386+
child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true);
387+
if (!child_valobj_sp) {
388+
std::string errMsg =
389+
llvm::formatv("failed to use pointer as array for index {0} for "
390+
"\"({1}) {2}\"", child_idx,
391+
base->GetTypeName().AsCString("<invalid type>"),
392+
var_expr_path_strm.GetData());
393+
if (base_type.IsPointerToVoid())
394+
errMsg = "subscript of pointer to incomplete type 'void'";
395+
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
396+
node->GetLocation());
397+
}
398+
}
399+
} else if (base_type.IsArrayType(
400+
nullptr, nullptr, &is_incomplete_array)) {
401+
child_valobj_sp = base->GetChildAtIndex(child_idx);
402+
if (!child_valobj_sp && (is_incomplete_array || m_use_synthetic))
403+
child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true);
404+
if (!child_valobj_sp) {
405+
std::string errMsg =
406+
llvm::formatv("array index {0} is not valid for \"({1}) {2}\"",
407+
child_idx,
408+
base->GetTypeName().AsCString("<invalid type>"),
409+
var_expr_path_strm.GetData());
410+
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
347411
node->GetLocation());
348412
}
349-
if (lldb::ValueObjectSP child_valobj_sp =
350-
synthetic->GetChildAtIndex(child_idx))
351-
return child_valobj_sp;
413+
} else if (base_type.IsScalarType()) {
414+
child_valobj_sp =
415+
base->GetSyntheticBitFieldChild(child_idx, child_idx, true);
416+
if (!child_valobj_sp) {
417+
std::string errMsg =
418+
llvm::formatv("bitfield range {0}-{1} is not valid for \"({2}) {3}\"",
419+
child_idx, child_idx,
420+
base->GetTypeName().AsCString("<invalid type>"),
421+
var_expr_path_strm.GetData());
422+
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
423+
node->GetLocation(), 1);
424+
}
425+
} else {
426+
lldb::ValueObjectSP synthetic = base->GetSyntheticValue();
427+
if (!m_use_synthetic || !synthetic || synthetic == base) {
428+
std::string errMsg =
429+
llvm::formatv("\"{0}\" is not an array type",
430+
base->GetTypeName().AsCString("<invalid type>"));
431+
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
432+
node->GetLocation(), 1);
433+
} else if (static_cast<uint32_t>(child_idx) >=
434+
synthetic->GetNumChildrenIgnoringErrors()) {
435+
std::string errMsg =
436+
llvm::formatv("array index {0} is not valid for \"({1}) {2}\"",
437+
child_idx,
438+
base->GetTypeName().AsCString("<invalid type>"),
439+
var_expr_path_strm.GetData());
440+
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
441+
node->GetLocation(), 1);
442+
} else {
443+
child_valobj_sp = synthetic->GetChildAtIndex(child_idx);
444+
if (!child_valobj_sp) {
445+
std::string errMsg =
446+
llvm::formatv("array index {0} is not valid for \"({1}) {2}\"",
447+
child_idx,
448+
base->GetTypeName().AsCString("<invalid type>"),
449+
var_expr_path_strm.GetData());
450+
return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
451+
node->GetLocation(), 1);
452+
}
453+
}
352454
}
353455

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());
363-
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+
lldb::ValueObjectSP dynamic_value_sp(
459+
child_valobj_sp->GetDynamicValue(m_use_dynamic));
460+
if (dynamic_value_sp)
461+
child_valobj_sp = dynamic_value_sp;
462+
}
463+
return child_valobj_sp;
367464
}
368465

369466
int64_t signed_child_idx = node->GetIndex();

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,19 @@ 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+
73+
# Test accessing bits in scalar types.
74+
self.expect_var_path("idx_1[0]", value="1")
75+
self.expect_var_path("idx_1[1]", value="0")
76+
77+
# Bit acess not valid for a reference.
7878
self.expect(
7979
"frame var 'idx_1_ref[0]'",
8080
error=True,
81-
substrs=["subscripted value is not an array or pointer"],
81+
substrs=["bitfield range 0-0 is not valid"],
8282
)
83+
84+
# Base should be a "pointer to T" and index should be of an integral type.
8385
self.expect(
8486
"frame var 'int_arr[int_ptr]'",
8587
error=True,

0 commit comments

Comments
 (0)