diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -695,6 +695,12 @@ SourceManager& getSourceManager() { return SourceMgr; } const SourceManager& getSourceManager() const { return SourceMgr; } + // Cleans up some of the data structures. This allows us to do cleanup + // normally done in the constructor earlier. May render much of the + // ASTContext unusable so should be called when ASTContext will no longer be + // used. + void cleanup(); + llvm::BumpPtrAllocator &getAllocator() const { return BumpAlloc; } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -990,7 +990,7 @@ addTranslationUnitDecl(); } -ASTContext::~ASTContext() { +void ASTContext::cleanup() { // Release the DenseMaps associated with DeclContext objects. // FIXME: Is this the ideal solution? ReleaseDeclContextMaps(); @@ -998,6 +998,7 @@ // Call all of the deallocation functions on all of their targets. for (auto &Pair : Deallocations) (Pair.first)(Pair.second); + Deallocations.clear(); // ASTRecordLayout objects in ASTRecordLayouts must always be destroyed // because they can contain DenseMaps. @@ -1007,6 +1008,7 @@ // Increment in loop to prevent using deallocated memory. if (auto *R = const_cast((I++)->second)) R->Destroy(*this); + ObjCLayouts.clear(); for (llvm::DenseMap::iterator I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); I != E; ) { @@ -1014,16 +1016,21 @@ if (auto *R = const_cast((I++)->second)) R->Destroy(*this); } + ASTRecordLayouts.clear(); for (llvm::DenseMap::iterator A = DeclAttrs.begin(), AEnd = DeclAttrs.end(); A != AEnd; ++A) A->second->~AttrVec(); + DeclAttrs.clear(); for (const auto &Value : ModuleInitializers) Value.second->~PerModuleInitializers(); + ModuleInitializers.clear(); } +ASTContext::~ASTContext() { cleanup(); } + void ASTContext::setTraversalScope(const std::vector &TopLevelDecls) { TraversalScope = TopLevelDecls; getParentMapContext().clear(); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1962,6 +1962,7 @@ // pointer because the subclass doesn't add anything that needs to // be deleted. StoredDeclsMap::DestroyAll(LastSDM.getPointer(), LastSDM.getInt()); + LastSDM.setPointer(nullptr); } void StoredDeclsMap::DestroyAll(StoredDeclsMap *Map, bool Dependent) { diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -351,10 +351,11 @@ } } - // FIXME: Fix cleanup issues with clearing the AST when we properly free - // things. - if (CodeGenOpts.DisableFree && CodeGenOpts.ClearASTBeforeBackend) + if (CodeGenOpts.ClearASTBeforeBackend) { + // The ASTContext may be unusable after this. + C.cleanup(); C.getAllocator().Reset(); + } EmbedBitcode(getModule(), CodeGenOpts, llvm::MemoryBufferRef());