Skip to content

Commit 410454f

Browse files
authored
Merge pull request #10257 from swiftlang/lldb/compressed-pair-to-20240723
🍒[lldb] Add support for new libc++ __compressed_pair layout
2 parents a7714ed + 372d155 commit 410454f

File tree

19 files changed

+441
-295
lines changed

19 files changed

+441
-295
lines changed

clang/include/clang/AST/ASTImporter.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,6 @@ class TypeSourceInfo;
258258
FoundDeclsTy findDeclsInToCtx(DeclContext *DC, DeclarationName Name);
259259

260260
void AddToLookupTable(Decl *ToD);
261-
llvm::Error ImportAttrs(Decl *ToD, Decl *FromD);
262261

263262
protected:
264263
/// Can be overwritten by subclasses to implement their own import logic.

clang/include/clang/AST/DeclCXX.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,10 +1188,6 @@ class CXXRecordDecl : public RecordDecl {
11881188
///
11891189
/// \note This does NOT include a check for union-ness.
11901190
bool isEmpty() const { return data().Empty; }
1191-
/// Marks this record as empty. This is used by DWARFASTParserClang
1192-
/// when parsing records with empty fields having [[no_unique_address]]
1193-
/// attribute
1194-
void markEmpty() { data().Empty = true; }
11951191

11961192
void setInitMethod(bool Val) { data().HasInitMethod = Val; }
11971193
bool hasInitMethod() const { return data().HasInitMethod; }

clang/lib/AST/ASTImporter.cpp

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4201,12 +4201,6 @@ ExpectedDecl ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
42014201
D->getInClassInitStyle()))
42024202
return ToField;
42034203

4204-
// We need [[no_unqiue_address]] attributes to be added to FieldDecl, before
4205-
// we add fields in CXXRecordDecl::addedMember, otherwise record will be
4206-
// marked as having non-zero size.
4207-
Err = Importer.ImportAttrs(ToField, D);
4208-
if (Err)
4209-
return std::move(Err);
42104204
ToField->setAccess(D->getAccess());
42114205
ToField->setLexicalDeclContext(LexicalDC);
42124206
ToField->setImplicit(D->isImplicit());
@@ -9423,19 +9417,6 @@ TranslationUnitDecl *ASTImporter::GetFromTU(Decl *ToD) {
94239417
return FromDPos->second->getTranslationUnitDecl();
94249418
}
94259419

9426-
Error ASTImporter::ImportAttrs(Decl *ToD, Decl *FromD) {
9427-
if (!FromD->hasAttrs() || ToD->hasAttrs())
9428-
return Error::success();
9429-
for (const Attr *FromAttr : FromD->getAttrs()) {
9430-
auto ToAttrOrErr = Import(FromAttr);
9431-
if (ToAttrOrErr)
9432-
ToD->addAttr(*ToAttrOrErr);
9433-
else
9434-
return ToAttrOrErr.takeError();
9435-
}
9436-
return Error::success();
9437-
}
9438-
94399420
Expected<Decl *> ASTImporter::Import(Decl *FromD) {
94409421
if (!FromD)
94419422
return nullptr;
@@ -9569,8 +9550,15 @@ Expected<Decl *> ASTImporter::Import(Decl *FromD) {
95699550
}
95709551
// Make sure that ImportImpl registered the imported decl.
95719552
assert(ImportedDecls.count(FromD) != 0 && "Missing call to MapImported?");
9572-
if (auto Error = ImportAttrs(ToD, FromD))
9573-
return std::move(Error);
9553+
9554+
if (FromD->hasAttrs())
9555+
for (const Attr *FromAttr : FromD->getAttrs()) {
9556+
auto ToAttrOrErr = Import(FromAttr);
9557+
if (ToAttrOrErr)
9558+
ToD->addAttr(*ToAttrOrErr);
9559+
else
9560+
return ToAttrOrErr.takeError();
9561+
}
95749562

95759563
// Notify subclasses.
95769564
Imported(FromD, ToD);

clang/unittests/AST/ASTImporterTest.cpp

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9376,29 +9376,6 @@ TEST_P(ASTImporterOptionSpecificTestBase, VaListCpp) {
93769376
ToVaList->getUnderlyingType(), ToBuiltinVaList->getUnderlyingType()));
93779377
}
93789378

9379-
TEST_P(ASTImporterOptionSpecificTestBase,
9380-
ImportDefinitionOfEmptyClassWithNoUniqueAddressField) {
9381-
Decl *FromTU = getTuDecl(
9382-
R"(
9383-
struct B {};
9384-
struct A { B b; };
9385-
)",
9386-
Lang_CXX20);
9387-
9388-
CXXRecordDecl *FromD = FirstDeclMatcher<CXXRecordDecl>().match(
9389-
FromTU, cxxRecordDecl(hasName("A")));
9390-
9391-
for (auto *FD : FromD->fields())
9392-
FD->addAttr(clang::NoUniqueAddressAttr::Create(FromD->getASTContext(),
9393-
clang::SourceRange()));
9394-
FromD->markEmpty();
9395-
9396-
CXXRecordDecl *ToD = Import(FromD, Lang_CXX20);
9397-
EXPECT_TRUE(ToD->isEmpty());
9398-
for (auto *FD : ToD->fields())
9399-
EXPECT_EQ(true, FD->hasAttr<NoUniqueAddressAttr>());
9400-
}
9401-
94029379
TEST_P(ASTImporterOptionSpecificTestBase, ImportExistingTypedefToRecord) {
94039380
const char *Code =
94049381
R"(

lldb/examples/synthetic/libcxx.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,12 @@ def _get_value_of_compressed_pair(self, pair):
721721
def update(self):
722722
logger = lldb.formatters.Logger.Logger()
723723
try:
724+
has_compressed_pair_layout = True
725+
alloc_valobj = self.valobj.GetChildMemberWithName("__alloc_")
726+
size_valobj = self.valobj.GetChildMemberWithName("__size_")
727+
if alloc_valobj.IsValid() and size_valobj.IsValid():
728+
has_compressed_pair_layout = False
729+
724730
# A deque is effectively a two-dim array, with fixed width.
725731
# 'map' contains pointers to the rows of this array. The
726732
# full memory area allocated by the deque is delimited
@@ -734,9 +740,13 @@ def update(self):
734740
# variable tells which element in this NxM array is the 0th
735741
# one, and the 'size' element gives the number of elements
736742
# in the deque.
737-
count = self._get_value_of_compressed_pair(
738-
self.valobj.GetChildMemberWithName("__size_")
739-
)
743+
if has_compressed_pair_layout:
744+
count = self._get_value_of_compressed_pair(
745+
self.valobj.GetChildMemberWithName("__size_")
746+
)
747+
else:
748+
count = size_valobj.GetValueAsUnsigned(0)
749+
740750
# give up now if we cant access memory reliably
741751
if self.block_size < 0:
742752
logger.write("block_size < 0")
@@ -748,9 +758,15 @@ def update(self):
748758
self.map_begin = map_.GetChildMemberWithName("__begin_")
749759
map_begin = self.map_begin.GetValueAsUnsigned(0)
750760
map_end = map_.GetChildMemberWithName("__end_").GetValueAsUnsigned(0)
751-
map_endcap = self._get_value_of_compressed_pair(
752-
map_.GetChildMemberWithName("__end_cap_")
753-
)
761+
762+
if has_compressed_pair_layout:
763+
map_endcap = self._get_value_of_compressed_pair(
764+
map_.GetChildMemberWithName("__end_cap_")
765+
)
766+
else:
767+
map_endcap = map_.GetChildMemberWithName(
768+
"__end_cap_"
769+
).GetValueAsUnsigned(0)
754770

755771
# check consistency
756772
if not map_first <= map_begin <= map_end <= map_endcap:

lldb/include/lldb/Symbol/SymbolFile.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,15 @@ class SymbolFile : public PluginInterface {
217217
/// The characteristics of an array type.
218218
struct ArrayInfo {
219219
int64_t first_index = 0;
220-
llvm::SmallVector<uint64_t, 1> element_orders;
220+
221+
///< Each entry belongs to a distinct DW_TAG_subrange_type.
222+
///< For multi-dimensional DW_TAG_array_types we would have
223+
///< an entry for each dimension. An entry represents the
224+
///< optional element count of the subrange.
225+
///
226+
///< The order of entries follows the order of the DW_TAG_subrange_type
227+
///< children of this DW_TAG_array_type.
228+
llvm::SmallVector<std::optional<uint64_t>, 1> element_orders;
221229
uint32_t byte_stride = 0;
222230
uint32_t bit_stride = 0;
223231
};

lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,40 @@
2727
#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
2828
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
2929
#include "lldb/lldb-enumerations.h"
30+
#include "lldb/lldb-forward.h"
3031
#include <optional>
3132
#include <tuple>
3233

3334
using namespace lldb;
3435
using namespace lldb_private;
3536
using namespace lldb_private::formatters;
3637

38+
static void consumeInlineNamespace(llvm::StringRef &name) {
39+
// Delete past an inline namespace, if any: __[a-zA-Z0-9_]+::
40+
auto scratch = name;
41+
if (scratch.consume_front("__") && std::isalnum(scratch[0])) {
42+
scratch = scratch.drop_while([](char c) { return std::isalnum(c); });
43+
if (scratch.consume_front("::")) {
44+
// Successfully consumed a namespace.
45+
name = scratch;
46+
}
47+
}
48+
}
49+
50+
bool lldb_private::formatters::isOldCompressedPairLayout(
51+
ValueObject &pair_obj) {
52+
return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair");
53+
}
54+
55+
bool lldb_private::formatters::isStdTemplate(ConstString type_name,
56+
llvm::StringRef type) {
57+
llvm::StringRef name = type_name.GetStringRef();
58+
// The type name may be prefixed with `std::__<inline-namespace>::`.
59+
if (name.consume_front("std::"))
60+
consumeInlineNamespace(name);
61+
return name.consume_front(type) && name.starts_with("<");
62+
}
63+
3764
lldb::ValueObjectSP lldb_private::formatters::GetChildMemberWithName(
3865
ValueObject &obj, llvm::ArrayRef<ConstString> alternative_names) {
3966
for (ConstString name : alternative_names) {
@@ -53,7 +80,7 @@ lldb_private::formatters::GetFirstValueOfLibCXXCompressedPair(
5380
if (first_child)
5481
value = first_child->GetChildMemberWithName("__value_");
5582
if (!value) {
56-
// pre-r300140 member name
83+
// pre-c88580c member name
5784
value = pair.GetChildMemberWithName("__first_");
5885
}
5986
return value;
@@ -70,7 +97,7 @@ lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair(
7097
}
7198
}
7299
if (!value) {
73-
// pre-r300140 member name
100+
// pre-c88580c member name
74101
value = pair.GetChildMemberWithName("__second_");
75102
}
76103
return value;
@@ -176,7 +203,9 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
176203
if (!ptr_sp)
177204
return false;
178205

179-
ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
206+
if (isOldCompressedPairLayout(*ptr_sp))
207+
ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
208+
180209
if (!ptr_sp)
181210
return false;
182211

@@ -363,13 +392,22 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
363392

364393
// Retrieve the actual pointer and the deleter, and clone them to give them
365394
// user-friendly names.
366-
ValueObjectSP value_pointer_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
367-
if (value_pointer_sp)
368-
m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
395+
if (isOldCompressedPairLayout(*ptr_sp)) {
396+
if (ValueObjectSP value_pointer_sp =
397+
GetFirstValueOfLibCXXCompressedPair(*ptr_sp))
398+
m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
399+
400+
if (ValueObjectSP deleter_sp =
401+
GetSecondValueOfLibCXXCompressedPair(*ptr_sp))
402+
m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
403+
} else {
404+
m_value_ptr_sp = ptr_sp->Clone(ConstString("pointer"));
369405

370-
ValueObjectSP deleter_sp = GetSecondValueOfLibCXXCompressedPair(*ptr_sp);
371-
if (deleter_sp)
372-
m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
406+
if (ValueObjectSP deleter_sp =
407+
valobj_sp->GetChildMemberWithName("__deleter_"))
408+
if (deleter_sp->GetNumChildrenIgnoringErrors() > 0)
409+
m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
410+
}
373411

374412
return lldb::ChildCacheState::eRefetch;
375413
}
@@ -407,24 +445,27 @@ namespace {
407445
enum class StringLayout { CSD, DSC };
408446
}
409447

448+
static ValueObjectSP ExtractLibCxxStringData(ValueObject &valobj) {
449+
if (auto rep_sp = valobj.GetChildMemberWithName("__rep_"))
450+
return rep_sp;
451+
452+
ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
453+
if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
454+
return nullptr;
455+
456+
if (!isOldCompressedPairLayout(*valobj_r_sp))
457+
return nullptr;
458+
459+
return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
460+
}
461+
410462
/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
411463
/// extract its data payload. Return the size + payload pair.
412464
// TODO: Support big-endian architectures.
413465
static std::optional<std::pair<uint64_t, ValueObjectSP>>
414466
ExtractLibcxxStringInfo(ValueObject &valobj) {
415-
ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
416-
if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
417-
return {};
418-
419-
// __r_ is a compressed_pair of the actual data and the allocator. The data we
420-
// want is in the first base class.
421-
ValueObjectSP valobj_r_base_sp = valobj_r_sp->GetChildAtIndex(0);
422-
if (!valobj_r_base_sp)
423-
return {};
424-
425-
ValueObjectSP valobj_rep_sp =
426-
valobj_r_base_sp->GetChildMemberWithName("__value_");
427-
if (!valobj_rep_sp)
467+
ValueObjectSP valobj_rep_sp = ExtractLibCxxStringData(valobj);
468+
if (!valobj_rep_sp || !valobj_rep_sp->GetError().Success())
428469
return {};
429470

430471
ValueObjectSP l = valobj_rep_sp->GetChildMemberWithName("__l");

lldb/source/Plugins/Language/CPlusPlus/LibCxx.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ GetChildMemberWithName(ValueObject &obj,
2525

2626
lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair);
2727
lldb::ValueObjectSP GetSecondValueOfLibCXXCompressedPair(ValueObject &pair);
28-
28+
bool isOldCompressedPairLayout(ValueObject &pair_obj);
29+
bool isStdTemplate(ConstString type_name, llvm::StringRef type);
2930

3031
bool LibcxxStringSummaryProviderASCII(
3132
ValueObject &valobj, Stream &stream,

0 commit comments

Comments
 (0)