DeclUnloader: remove TagDecls after all other decls

The order in which declarations are removed makes a difference, e.g.
`MaybeRemoveDeclFromModule()` may require access to type information to
make up the mangled name.

Thus, we segregate declarations to be removed in `TagDecl`s (i.e., struct
/ union / class / enum) and other declarations.  Removal of `TagDecl`s
is deferred until all the other declarations have been processed.
Declarations in each group are iterated in reverse order.

Fixes #12457.
This commit is contained in:
Javier Lopez-Gomez 2023-05-18 14:35:51 +02:00 committed by jenkins
parent badb929352
commit 11a1a348f8

View File

@ -682,16 +682,29 @@ bool DeclUnloader::VisitRedeclarable(clang::Redeclarable<T>* R, DeclContext* DC)
bool DeclUnloader::VisitDeclContext(DeclContext* DC) {
bool Successful = true;
typedef llvm::SmallVector<Decl*, 64> Decls;
Decls declsToErase;
// Removing from single-linked list invalidates the iterators.
llvm::SmallVector<Decl*, 64> tagDecls, otherDecls;
// The order in which declarations are removed makes a difference, e.g.
// `MaybeRemoveDeclFromModule()` may require access to type information to
// make up the mangled name.
// Thus, we segregate declarations to be removed in `TagDecl`s (i.e., struct
// / union / class / enum) and other declarations. Removal of `TagDecl`s
// is deferred until all the other declarations have been processed.
// Declarations in each group are iterated in reverse order.
// Note that removing from single-linked list invalidates the iterators.
for (DeclContext::decl_iterator I = DC->noload_decls_begin();
I != DC->noload_decls_end(); ++I) {
declsToErase.push_back(*I);
if (isa<TagDecl>(*I))
tagDecls.push_back(*I);
else
otherDecls.push_back(*I);
}
for(Decls::reverse_iterator I = declsToErase.rbegin(),
E = declsToErase.rend(); I != E; ++I) {
for (auto I = otherDecls.rbegin(), E = otherDecls.rend(); I != E; ++I) {
Successful = Visit(*I) && Successful;
assert(Successful);
}
for (auto I = tagDecls.rbegin(), E = tagDecls.rend(); I != E; ++I) {
Successful = Visit(*I) && Successful;
assert(Successful);
}