Skip to content

Commit 0261a39

Browse files
authored
Merge pull request #8222 from Michael137/lldb/type-completion-rework/WIP/to-20230725
This patch is rewriting the way we move Clang types between different ASTS in Clang. The motivation is that the current approach for 'completing types' in LLDB just doesn't work. We have all kinds of situations where we either have Clang crash due to for example having a Record without DefinitionData but with FieldDecls in it. The reason for that is that at the moment we create record types ([CXX]RecordDecls and ObjCInterfaceDecls) and we always pretend that a type potentially has a definition that somehow could be lazily pulled in. However, Clang doesn't have any interface (at least none that is consistently called) that turns a RecordDecl without DefinitionData into a RecordDecl with DefinitionData. The only relevant API in the ExternalASTSource is CompleteType is suffering from the fact that it's essentially not used by generic Clang code. The part of the ExternalASTSource API that is consistently called to pull in a potential definition is CompleteRedeclChain (which is for example automatically called when calling getDefinition on a RecordDecl). The problem with CompleteRedeclChain however is that it's not supposed to add definition data to the Decl its called on, but instead it should provide a redeclaration that is defining the record. That's a very different system than what we currently have and we can't just swap it out under the hood. To make it short: We probably need to rewrite that part of LLDB. So the solution here is essentially rewriting all our completion code to do this: Instead of creating these weirdly defined records that have fields but maybe not definition and so on, we only create forward decls at the start. We then bump the GenerationCounter of the ExternalASTSource of the current AST to force rebuilding of the redeclaration chain. When Clang asks for the definition of the record, it will ask the ExternalASTSource to complete the redeclaration chain. At this point we build the definition and add it as a second decl. The ASTImporter can now also stop using the minimal mode for records as there is no reason anymore. It just imports first the forward declaration and then the definition when needed.
2 parents c84491a + 66e12b4 commit 0261a39

40 files changed

+1551
-325
lines changed

clang/include/clang/AST/ASTImporter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ class TypeSourceInfo;
211211

212212
/// Whether to perform a minimal import.
213213
bool Minimal;
214+
bool LLDBRedeclCompletion = false;
214215

215216
ODRHandlingType ODRHandling;
216217

@@ -296,8 +297,10 @@ class TypeSourceInfo;
296297
/// Whether the importer will perform a minimal import, creating
297298
/// to-be-completed forward declarations when possible.
298299
bool isMinimalImport() const { return Minimal; }
300+
bool hasLLDBRedeclCompletion() const { return LLDBRedeclCompletion; }
299301

300302
void setODRHandling(ODRHandlingType T) { ODRHandling = T; }
303+
void setLLDBRedeclCompletion(bool Val) { LLDBRedeclCompletion = Val; }
301304

302305
/// \brief Import the given object, returns the result.
303306
///

clang/include/clang/AST/DeclObjC.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,7 +1238,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
12381238
/// which will be NULL if this class has not yet been defined.
12391239
///
12401240
/// The bit indicates when we don't need to check for out-of-date
1241-
/// declarations. It will be set unless modules are enabled.
1241+
/// declarations. It will be set unless there is an ExternalASTSource that
1242+
/// could provide a definition.
12421243
llvm::PointerIntPair<DefinitionData *, 1, bool> Data;
12431244

12441245
ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
@@ -1527,7 +1528,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
15271528
// If the name of this class is out-of-date, bring it up-to-date, which
15281529
// might bring in a definition.
15291530
// Note: a null value indicates that we don't have a definition and that
1530-
// modules are enabled.
1531+
// there is a ExternalASTSource that could provide a definition.
15311532
if (!Data.getOpaqueValue())
15321533
getMostRecentDecl();
15331534

@@ -2095,7 +2096,8 @@ class ObjCProtocolDecl : public ObjCContainerDecl,
20952096
/// which will be NULL if this class has not yet been defined.
20962097
///
20972098
/// The bit indicates when we don't need to check for out-of-date
2098-
/// declarations. It will be set unless modules are enabled.
2099+
/// declarations. It will be set unless there is an ExternalASTSource that
2100+
/// could provide a definition.
20992101
llvm::PointerIntPair<DefinitionData *, 1, bool> Data;
21002102

21012103
ObjCProtocolDecl(ASTContext &C, DeclContext *DC, IdentifierInfo *Id,
@@ -2232,7 +2234,7 @@ class ObjCProtocolDecl : public ObjCContainerDecl,
22322234
// If the name of this protocol is out-of-date, bring it up-to-date, which
22332235
// might bring in a definition.
22342236
// Note: a null value indicates that we don't have a definition and that
2235-
// modules are enabled.
2237+
// there is a ExternalASTSource that could provide a definition.
22362238
if (!Data.getOpaqueValue())
22372239
getMostRecentDecl();
22382240

clang/lib/AST/ASTImporter.cpp

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,7 +1031,8 @@ Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) {
10311031

10321032
template <typename T>
10331033
bool ASTNodeImporter::hasSameVisibilityContextAndLinkage(T *Found, T *From) {
1034-
if (Found->getLinkageInternal() != From->getLinkageInternal())
1034+
if (!Importer.hasLLDBRedeclCompletion() &&
1035+
Found->getLinkageInternal() != From->getLinkageInternal())
10351036
return false;
10361037

10371038
if (From->hasExternalFormalLinkage())
@@ -1482,7 +1483,9 @@ ExpectedType ASTNodeImporter::VisitInjectedClassNameType(
14821483
}
14831484

14841485
ExpectedType ASTNodeImporter::VisitRecordType(const RecordType *T) {
1486+
// getCanonicalDecl in order to not trigger redeclaration completion
14851487
Expected<RecordDecl *> ToDeclOrErr = import(T->getDecl());
1488+
14861489
if (!ToDeclOrErr)
14871490
return ToDeclOrErr.takeError();
14881491

@@ -1771,8 +1774,9 @@ Error ASTNodeImporter::ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD) {
17711774

17721775
if (RecordDecl *FromRecord = dyn_cast<RecordDecl>(FromD)) {
17731776
if (RecordDecl *ToRecord = cast<RecordDecl>(ToD)) {
1774-
if (FromRecord->getDefinition() && FromRecord->isCompleteDefinition() &&
1775-
!ToRecord->getDefinition()) {
1777+
if (FromRecord->getDefinition() && !ToRecord->getDefinition() &&
1778+
(Importer.hasLLDBRedeclCompletion() ||
1779+
FromRecord->isCompleteDefinition())) {
17761780
if (Error Err = ImportDefinition(FromRecord, ToRecord))
17771781
return Err;
17781782
}
@@ -1873,12 +1877,15 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
18731877
ImportedOrErr.takeError());
18741878
continue;
18751879
}
1876-
FieldDecl *FieldFrom = dyn_cast_or_null<FieldDecl>(From);
1877-
Decl *ImportedDecl = *ImportedOrErr;
1878-
FieldDecl *FieldTo = dyn_cast_or_null<FieldDecl>(ImportedDecl);
1879-
if (FieldFrom && FieldTo) {
1880-
Error Err = ImportFieldDeclDefinition(FieldFrom, FieldTo);
1881-
HandleChildErrors.handleChildImportResult(ChildErrors, std::move(Err));
1880+
1881+
if (Importer.hasLLDBRedeclCompletion()) {
1882+
FieldDecl *FieldFrom = dyn_cast_or_null<FieldDecl>(From);
1883+
Decl *ImportedDecl = *ImportedOrErr;
1884+
FieldDecl *FieldTo = dyn_cast_or_null<FieldDecl>(ImportedDecl);
1885+
if (FieldFrom && FieldTo) {
1886+
Error Err = ImportFieldDeclDefinition(FieldFrom, FieldTo);
1887+
HandleChildErrors.handleChildImportResult(ChildErrors, std::move(Err));
1888+
}
18821889
}
18831890
}
18841891

@@ -2039,7 +2046,11 @@ Error ASTNodeImporter::ImportDefinition(
20392046
To->completeDefinition();
20402047
};
20412048

2042-
if (To->getDefinition() || To->isBeingDefined()) {
2049+
bool hasDef = (Importer.hasLLDBRedeclCompletion() &&
2050+
To->isThisDeclarationADefinition()) ||
2051+
To->getDefinition();
2052+
2053+
if (hasDef || To->isBeingDefined()) {
20432054
if (Kind == IDK_Everything ||
20442055
// In case of lambdas, the class already has a definition ptr set, but
20452056
// the contained decls are not imported yet. Also, isBeingDefined was
@@ -2558,6 +2569,9 @@ ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
25582569
!hasSameVisibilityContextAndLinkage(FoundR, FromR))
25592570
continue;
25602571
}
2572+
2573+
if (Importer.hasLLDBRedeclCompletion() && Importer.isMinimalImport())
2574+
return Importer.MapImported(D, FoundTypedef);
25612575
// If the "From" context has a complete underlying type but we
25622576
// already have a complete underlying type then return with that.
25632577
if (!FromUT->isIncompleteType() && !FoundUT->isIncompleteType())
@@ -2822,9 +2836,11 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
28222836
return POIOrErr.takeError();
28232837
}
28242838

2839+
auto Kind = Importer.hasLLDBRedeclCompletion() ? IDK_Everything : IDK_Default;
2840+
28252841
// Import the definition
28262842
if (D->isCompleteDefinition())
2827-
if (Error Err = ImportDefinition(D, D2))
2843+
if (Error Err = ImportDefinition(D, D2, Kind))
28282844
return std::move(Err);
28292845

28302846
return D2;
@@ -2902,7 +2918,8 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
29022918

29032919
if (IsStructuralMatch(D, FoundRecord)) {
29042920
RecordDecl *FoundDef = FoundRecord->getDefinition();
2905-
if (D->isThisDeclarationADefinition() && FoundDef) {
2921+
if (!Importer.hasLLDBRedeclCompletion() &&
2922+
D->isThisDeclarationADefinition() && FoundDef) {
29062923
// FIXME: Structural equivalence check should check for same
29072924
// user-defined methods.
29082925
Importer.MapImported(D, FoundDef);
@@ -3078,8 +3095,9 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
30783095
if (D->isAnonymousStructOrUnion())
30793096
D2->setAnonymousStructOrUnion(true);
30803097

3098+
auto Kind = Importer.hasLLDBRedeclCompletion() ? IDK_Everything : IDK_Default;
30813099
if (D->isCompleteDefinition())
3082-
if (Error Err = ImportDefinition(D, D2, IDK_Default))
3100+
if (Error Err = ImportDefinition(D, D2, Kind))
30833101
return std::move(Err);
30843102

30853103
return D2;
@@ -5203,7 +5221,8 @@ Error ASTNodeImporter::ImportDefinition(
52035221
diag::note_odr_objc_missing_superclass);
52045222
}
52055223

5206-
if (shouldForceImportDeclContext(Kind))
5224+
if (Importer.hasLLDBRedeclCompletion() ||
5225+
shouldForceImportDeclContext(Kind))
52075226
if (Error Err = ImportDeclContext(From))
52085227
return Err;
52095228
return Error::success();
@@ -6084,8 +6103,9 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
60846103
}
60856104
}
60866105

6106+
auto Kind = Importer.hasLLDBRedeclCompletion() ? IDK_Everything : IDK_Default;
60876107
if (D->isCompleteDefinition())
6088-
if (Error Err = ImportDefinition(D, D2))
6108+
if (Error Err = ImportDefinition(D, D2, Kind))
60896109
return std::move(Err);
60906110

60916111
return D2;

clang/lib/AST/DeclObjC.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,7 +1546,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
15461546
auto *Result = new (C, DC)
15471547
ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl,
15481548
isInternal);
1549-
Result->Data.setInt(!C.getLangOpts().Modules);
1549+
Result->Data.setInt(!C.getExternalSource());
15501550
C.getObjCInterfaceType(Result, PrevDecl);
15511551
return Result;
15521552
}
@@ -1556,7 +1556,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
15561556
auto *Result = new (C, ID)
15571557
ObjCInterfaceDecl(C, nullptr, SourceLocation(), nullptr, nullptr,
15581558
SourceLocation(), nullptr, false);
1559-
Result->Data.setInt(!C.getLangOpts().Modules);
1559+
Result->Data.setInt(!C.getExternalSource());
15601560
return Result;
15611561
}
15621562

@@ -1947,7 +1947,7 @@ ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC,
19471947
ObjCProtocolDecl *PrevDecl) {
19481948
auto *Result =
19491949
new (C, DC) ObjCProtocolDecl(C, DC, Id, nameLoc, atStartLoc, PrevDecl);
1950-
Result->Data.setInt(!C.getLangOpts().Modules);
1950+
Result->Data.setInt(!C.getExternalSource());
19511951
return Result;
19521952
}
19531953

@@ -1956,7 +1956,7 @@ ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C,
19561956
ObjCProtocolDecl *Result =
19571957
new (C, ID) ObjCProtocolDecl(C, nullptr, nullptr, SourceLocation(),
19581958
SourceLocation(), nullptr);
1959-
Result->Data.setInt(!C.getLangOpts().Modules);
1959+
Result->Data.setInt(!C.getExternalSource());
19601960
return Result;
19611961
}
19621962

lldb/include/lldb/Core/PluginManager.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ class PluginManager {
474474
// TypeSystem
475475
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
476476
TypeSystemCreateInstance create_callback,
477+
DebuggerInitializeCallback debugger_callback,
477478
LanguageSet supported_languages_for_types,
478479
LanguageSet supported_languages_for_expressions);
479480

@@ -528,6 +529,13 @@ class PluginManager {
528529
Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
529530
llvm::StringRef description, bool is_global_property);
530531

532+
static lldb::OptionValuePropertiesSP
533+
GetSettingForTypeSystemPlugin(Debugger &debugger, ConstString setting_name);
534+
535+
static bool CreateSettingForTypeSystemPlugin(
536+
Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
537+
ConstString description, bool is_global_property);
538+
531539
static bool CreateSettingForTracePlugin(
532540
Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
533541
llvm::StringRef description, bool is_global_property);

lldb/source/Core/PluginManager.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,10 +1423,11 @@ PluginManager::GetInstrumentationRuntimeCreateCallbackAtIndex(uint32_t idx) {
14231423
struct TypeSystemInstance : public PluginInstance<TypeSystemCreateInstance> {
14241424
TypeSystemInstance(llvm::StringRef name, llvm::StringRef description,
14251425
CallbackType create_callback,
1426+
DebuggerInitializeCallback debugger_init_callback,
14261427
LanguageSet supported_languages_for_types,
14271428
LanguageSet supported_languages_for_expressions)
1428-
: PluginInstance<TypeSystemCreateInstance>(name, description,
1429-
create_callback),
1429+
: PluginInstance<TypeSystemCreateInstance>(
1430+
name, description, create_callback, debugger_init_callback),
14301431
supported_languages_for_types(supported_languages_for_types),
14311432
supported_languages_for_expressions(
14321433
supported_languages_for_expressions) {}
@@ -1445,11 +1446,12 @@ static TypeSystemInstances &GetTypeSystemInstances() {
14451446
bool PluginManager::RegisterPlugin(
14461447
llvm::StringRef name, llvm::StringRef description,
14471448
TypeSystemCreateInstance create_callback,
1449+
DebuggerInitializeCallback debugger_init_callback,
14481450
LanguageSet supported_languages_for_types,
14491451
LanguageSet supported_languages_for_expressions) {
14501452
return GetTypeSystemInstances().RegisterPlugin(
1451-
name, description, create_callback, supported_languages_for_types,
1452-
supported_languages_for_expressions);
1453+
name, description, create_callback, debugger_init_callback,
1454+
supported_languages_for_types, supported_languages_for_expressions);
14531455
}
14541456

14551457
bool PluginManager::UnregisterPlugin(TypeSystemCreateInstance create_callback) {
@@ -1536,6 +1538,7 @@ void PluginManager::DebuggerInitialize(Debugger &debugger) {
15361538
GetOperatingSystemInstances().PerformDebuggerCallback(debugger);
15371539
GetStructuredDataPluginInstances().PerformDebuggerCallback(debugger);
15381540
GetTracePluginInstances().PerformDebuggerCallback(debugger);
1541+
GetTypeSystemInstances().PerformDebuggerCallback(debugger);
15391542
}
15401543

15411544
// This is the preferred new way to register plugin specific settings. e.g.
@@ -1660,6 +1663,7 @@ static constexpr llvm::StringLiteral kProcessPluginName("process");
16601663
static constexpr llvm::StringLiteral kTracePluginName("trace");
16611664
static constexpr llvm::StringLiteral kObjectFilePluginName("object-file");
16621665
static constexpr llvm::StringLiteral kSymbolFilePluginName("symbol-file");
1666+
static constexpr llvm::StringLiteral kTypeSystemPluginName("typesystem");
16631667
static constexpr llvm::StringLiteral kJITLoaderPluginName("jit-loader");
16641668
static constexpr llvm::StringLiteral
16651669
kStructuredDataPluginName("structured-data");
@@ -1744,6 +1748,22 @@ bool PluginManager::CreateSettingForSymbolFilePlugin(
17441748
properties_sp, description, is_global_property);
17451749
}
17461750

1751+
lldb::OptionValuePropertiesSP
1752+
PluginManager::GetSettingForTypeSystemPlugin(Debugger &debugger,
1753+
ConstString setting_name) {
1754+
return GetSettingForPlugin(debugger, setting_name,
1755+
ConstString(kTypeSystemPluginName));
1756+
}
1757+
1758+
bool PluginManager::CreateSettingForTypeSystemPlugin(
1759+
Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
1760+
ConstString description, bool is_global_property) {
1761+
return CreateSettingForPlugin(
1762+
debugger, ConstString(kTypeSystemPluginName),
1763+
ConstString("Settings for type system plug-ins"), properties_sp,
1764+
description, is_global_property);
1765+
}
1766+
17471767
lldb::OptionValuePropertiesSP
17481768
PluginManager::GetSettingForJITLoaderPlugin(Debugger &debugger,
17491769
llvm::StringRef setting_name) {

lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H
1010
#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H
1111

12+
#include "Plugins/TypeSystem/Clang/ImporterBackedASTSource.h"
1213
#include "clang/Basic/Module.h"
1314
#include "clang/Sema/Lookup.h"
1415
#include "clang/Sema/MultiplexExternalSemaSource.h"
@@ -20,7 +21,7 @@ namespace lldb_private {
2021

2122
/// Wraps an ExternalASTSource into an ExternalSemaSource. Doesn't take
2223
/// ownership of the provided source.
23-
class ExternalASTSourceWrapper : public clang::ExternalSemaSource {
24+
class ExternalASTSourceWrapper : public ImporterBackedASTSource {
2425
ExternalASTSource *m_Source;
2526

2627
public:
@@ -240,7 +241,7 @@ class ASTConsumerForwarder : public clang::SemaConsumer {
240241
/// provide more accurate replies to the requests, but might not be able to
241242
/// answer all requests. The debug information will be used as a fallback then
242243
/// to provide information that is not in the C++ module.
243-
class SemaSourceWithPriorities : public clang::ExternalSemaSource {
244+
class SemaSourceWithPriorities : public ImporterBackedASTSource {
244245

245246
private:
246247
/// The sources ordered in decreasing priority.
@@ -273,9 +274,16 @@ class SemaSourceWithPriorities : public clang::ExternalSemaSource {
273274
return nullptr;
274275
}
275276

277+
/// Call ExternalASTSource::CompleteRedeclChain(D)
278+
/// on each AST source. Returns as soon as we got
279+
/// a definition for D.
276280
void CompleteRedeclChain(const clang::Decl *D) override {
277-
for (size_t i = 0; i < Sources.size(); ++i)
281+
for (size_t i = 0; i < Sources.size(); ++i) {
278282
Sources[i]->CompleteRedeclChain(D);
283+
if (auto *td = llvm::dyn_cast<clang::TagDecl>(D))
284+
if (td->getDefinition())
285+
return;
286+
}
279287
}
280288

281289
clang::Selector GetExternalSelector(uint32_t ID) override {

0 commit comments

Comments
 (0)