Skip to content

Commit 7bb9009

Browse files
authored
Merge pull request swiftlang#7921 from Michael137/bgufix/astimporter-objc-crash-to-20230725
This reverts commit e953669. Prior to this patch, the import re-ordering only applied to `RecordDecl`. This patch changed the `decls()` we were iterating over from a `RecordDecl` to those of the `DeclContext`, which meant we were now also doing this re-ordering for members of `ObjCInterfaceDecl`s. This caused crashes when debugging Objective-C applications with LLDB. For Objective-C interfaces this re-ordering doesn't actually make sense because those don't have function bodies, so there's no risk of importing a method body that references a yet-to-be-imported ivar, which is what [D154764](http://108.170.204.19/D154764) attempted to fix. Revert for now until we find a way to support `ObjCInterfaceDecl`s properly. rdar://119343184 rdar://119636274 rdar://119832131
2 parents 7d33929 + cf6e2d9 commit 7bb9009

File tree

2 files changed

+53
-97
lines changed

2 files changed

+53
-97
lines changed

clang/lib/AST/ASTImporter.cpp

Lines changed: 53 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,6 @@ namespace clang {
433433
Decl *From, DeclContext *&ToDC, DeclContext *&ToLexicalDC);
434434
Error ImportImplicitMethods(const CXXRecordDecl *From, CXXRecordDecl *To);
435435

436-
Error ImportFieldDeclDefinition(const FieldDecl *From, const FieldDecl *To);
437436
Expected<CXXCastPath> ImportCastPath(CastExpr *E);
438437
Expected<APValue> ImportAPValue(const APValue &FromValue);
439438

@@ -1851,33 +1850,52 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
18511850
// different values in two distinct translation units.
18521851
ChildErrorHandlingStrategy HandleChildErrors(FromDC);
18531852

1854-
auto MightNeedReordering = [](const Decl *D) {
1855-
return isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) || isa<FriendDecl>(D);
1856-
};
1857-
1858-
// Import everything that might need reordering first.
18591853
Error ChildErrors = Error::success();
18601854
for (auto *From : FromDC->decls()) {
1861-
if (!MightNeedReordering(From))
1862-
continue;
1863-
18641855
ExpectedDecl ImportedOrErr = import(From);
18651856

18661857
// If we are in the process of ImportDefinition(...) for a RecordDecl we
18671858
// want to make sure that we are also completing each FieldDecl. There
18681859
// are currently cases where this does not happen and this is correctness
18691860
// fix since operations such as code generation will expect this to be so.
1870-
if (!ImportedOrErr) {
1861+
if (ImportedOrErr) {
1862+
FieldDecl *FieldFrom = dyn_cast_or_null<FieldDecl>(From);
1863+
Decl *ImportedDecl = *ImportedOrErr;
1864+
FieldDecl *FieldTo = dyn_cast_or_null<FieldDecl>(ImportedDecl);
1865+
if (FieldFrom && FieldTo) {
1866+
RecordDecl *FromRecordDecl = nullptr;
1867+
RecordDecl *ToRecordDecl = nullptr;
1868+
// If we have a field that is an ArrayType we need to check if the array
1869+
// element is a RecordDecl and if so we need to import the definition.
1870+
if (FieldFrom->getType()->isArrayType()) {
1871+
// getBaseElementTypeUnsafe(...) handles multi-dimensonal arrays for us.
1872+
FromRecordDecl = FieldFrom->getType()->getBaseElementTypeUnsafe()->getAsRecordDecl();
1873+
ToRecordDecl = FieldTo->getType()->getBaseElementTypeUnsafe()->getAsRecordDecl();
1874+
}
1875+
1876+
if (!FromRecordDecl || !ToRecordDecl) {
1877+
const RecordType *RecordFrom =
1878+
FieldFrom->getType()->getAs<RecordType>();
1879+
const RecordType *RecordTo = FieldTo->getType()->getAs<RecordType>();
1880+
1881+
if (RecordFrom && RecordTo) {
1882+
FromRecordDecl = RecordFrom->getDecl();
1883+
ToRecordDecl = RecordTo->getDecl();
1884+
}
1885+
}
1886+
1887+
if (FromRecordDecl && ToRecordDecl) {
1888+
if (FromRecordDecl->isCompleteDefinition() &&
1889+
!ToRecordDecl->isCompleteDefinition()) {
1890+
Error Err = ImportDefinition(FromRecordDecl, ToRecordDecl);
1891+
HandleChildErrors.handleChildImportResult(ChildErrors,
1892+
std::move(Err));
1893+
}
1894+
}
1895+
}
1896+
} else {
18711897
HandleChildErrors.handleChildImportResult(ChildErrors,
18721898
ImportedOrErr.takeError());
1873-
continue;
1874-
}
1875-
FieldDecl *FieldFrom = dyn_cast_or_null<FieldDecl>(From);
1876-
Decl *ImportedDecl = *ImportedOrErr;
1877-
FieldDecl *FieldTo = dyn_cast_or_null<FieldDecl>(ImportedDecl);
1878-
if (FieldFrom && FieldTo) {
1879-
Error Err = ImportFieldDeclDefinition(FieldFrom, FieldTo);
1880-
HandleChildErrors.handleChildImportResult(ChildErrors, std::move(Err));
18811899
}
18821900
}
18831901

@@ -1892,7 +1910,7 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
18921910
// During the import of `a` we import first the dependencies in sequence,
18931911
// thus the order would be `c`, `b`, `a`. We will get the normal order by
18941912
// first removing the already imported members and then adding them in the
1895-
// order as they appear in the "from" context.
1913+
// order as they apper in the "from" context.
18961914
//
18971915
// Keeping field order is vital because it determines structure layout.
18981916
//
@@ -1904,6 +1922,9 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
19041922
// interface in LLDB is implemented by the means of the ASTImporter. However,
19051923
// calling an import at this point would result in an uncontrolled import, we
19061924
// must avoid that.
1925+
const auto *FromRD = dyn_cast<RecordDecl>(FromDC);
1926+
if (!FromRD)
1927+
return ChildErrors;
19071928

19081929
auto ToDCOrErr = Importer.ImportContext(FromDC);
19091930
if (!ToDCOrErr) {
@@ -1914,70 +1935,26 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
19141935
DeclContext *ToDC = *ToDCOrErr;
19151936
// Remove all declarations, which may be in wrong order in the
19161937
// lexical DeclContext and then add them in the proper order.
1917-
for (auto *D : FromDC->decls()) {
1918-
if (!MightNeedReordering(D))
1919-
continue;
1920-
1921-
assert(D && "DC contains a null decl");
1922-
if (Decl *ToD = Importer.GetAlreadyImportedOrNull(D)) {
1938+
for (auto *D : FromRD->decls()) {
1939+
if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) || isa<FriendDecl>(D)) {
1940+
assert(D && "DC contains a null decl");
1941+
Decl *ToD = Importer.GetAlreadyImportedOrNull(D);
19231942
// Remove only the decls which we successfully imported.
1924-
assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD));
1925-
// Remove the decl from its wrong place in the linked list.
1926-
ToDC->removeDecl(ToD);
1927-
// Add the decl to the end of the linked list.
1928-
// This time it will be at the proper place because the enclosing for
1929-
// loop iterates in the original (good) order of the decls.
1930-
ToDC->addDeclInternal(ToD);
1943+
if (ToD) {
1944+
assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD));
1945+
// Remove the decl from its wrong place in the linked list.
1946+
ToDC->removeDecl(ToD);
1947+
// Add the decl to the end of the linked list.
1948+
// This time it will be at the proper place because the enclosing for
1949+
// loop iterates in the original (good) order of the decls.
1950+
ToDC->addDeclInternal(ToD);
1951+
}
19311952
}
19321953
}
19331954

1934-
// Import everything else.
1935-
for (auto *From : FromDC->decls()) {
1936-
if (MightNeedReordering(From))
1937-
continue;
1938-
1939-
ExpectedDecl ImportedOrErr = import(From);
1940-
if (!ImportedOrErr)
1941-
HandleChildErrors.handleChildImportResult(ChildErrors,
1942-
ImportedOrErr.takeError());
1943-
}
1944-
19451955
return ChildErrors;
19461956
}
19471957

1948-
Error ASTNodeImporter::ImportFieldDeclDefinition(const FieldDecl *From,
1949-
const FieldDecl *To) {
1950-
RecordDecl *FromRecordDecl = nullptr;
1951-
RecordDecl *ToRecordDecl = nullptr;
1952-
// If we have a field that is an ArrayType we need to check if the array
1953-
// element is a RecordDecl and if so we need to import the definition.
1954-
QualType FromType = From->getType();
1955-
QualType ToType = To->getType();
1956-
if (FromType->isArrayType()) {
1957-
// getBaseElementTypeUnsafe(...) handles multi-dimensonal arrays for us.
1958-
FromRecordDecl = FromType->getBaseElementTypeUnsafe()->getAsRecordDecl();
1959-
ToRecordDecl = ToType->getBaseElementTypeUnsafe()->getAsRecordDecl();
1960-
}
1961-
1962-
if (!FromRecordDecl || !ToRecordDecl) {
1963-
const RecordType *RecordFrom = FromType->getAs<RecordType>();
1964-
const RecordType *RecordTo = ToType->getAs<RecordType>();
1965-
1966-
if (RecordFrom && RecordTo) {
1967-
FromRecordDecl = RecordFrom->getDecl();
1968-
ToRecordDecl = RecordTo->getDecl();
1969-
}
1970-
}
1971-
1972-
if (FromRecordDecl && ToRecordDecl) {
1973-
if (FromRecordDecl->isCompleteDefinition() &&
1974-
!ToRecordDecl->isCompleteDefinition())
1975-
return ImportDefinition(FromRecordDecl, ToRecordDecl);
1976-
}
1977-
1978-
return Error::success();
1979-
}
1980-
19811958
Error ASTNodeImporter::ImportDeclContext(
19821959
Decl *FromD, DeclContext *&ToDC, DeclContext *&ToLexicalDC) {
19831960
auto ToDCOrErr = Importer.ImportContext(FromD->getDeclContext());

clang/unittests/AST/ASTImporterTest.cpp

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8048,27 +8048,6 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportDeductionGuideDifferentOrder) {
80488048
ToDGOther);
80498049
}
80508050

8051-
TEST_P(ASTImporterOptionSpecificTestBase,
8052-
ImportFieldsFirstForCorrectRecordLayoutTest) {
8053-
// UnaryOperator(&) triggers RecordLayout computation, which relies on
8054-
// correctly imported fields.
8055-
auto Code =
8056-
R"(
8057-
class A {
8058-
int m() {
8059-
return &((A *)0)->f1 - &((A *)0)->f2;
8060-
}
8061-
int f1;
8062-
int f2;
8063-
};
8064-
)";
8065-
Decl *FromTU = getTuDecl(Code, Lang_CXX11);
8066-
8067-
auto *FromF = FirstDeclMatcher<CXXMethodDecl>().match(
8068-
FromTU, cxxMethodDecl(hasName("A::m")));
8069-
Import(FromF, Lang_CXX11);
8070-
}
8071-
80728051
TEST_P(ASTImporterOptionSpecificTestBase,
80738052
ImportRecordWithLayoutRequestingExpr) {
80748053
TranslationUnitDecl *FromTU = getTuDecl(

0 commit comments

Comments
 (0)