[ASTImporter] Mark erroneous nodes in from ctx
Summary:
During import of a specific Decl D, it may happen that some AST nodes
had already been created before we recognize an error. In this case we
signal back the error to the caller, but the "to" context remains
polluted with those nodes which had been created. Ideally, those nodes
should not had been created, but that time we did not know about the
error, the error happened later. Since the AST is immutable (most of
the cases we can't remove existing nodes) we choose to mark these nodes
as erroneous.
Here are the steps of the algorithm:
1) We keep track of the nodes which we visit during the import of D: See
ImportPathTy.
2) If a Decl is already imported and it is already on the import path
(we have a cycle) then we copy/store the relevant part of the import
path. We store these cycles for each Decl.
3) When we recognize an error during the import of D then we set up this
error to all Decls in the stored cycles for D and we clear the stored
cycles.
Reviewers: a_sidorin, a.sidorin, shafik
Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D62375
llvm-svn: 364771
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 097046d..b2de045 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -7842,6 +7842,10 @@
if (!FromD)
return nullptr;
+ // Push FromD to the stack, and remove that when we return.
+ ImportPath.push(FromD);
+ auto ImportPathBuilder =
+ llvm::make_scope_exit([this]() { ImportPath.pop(); });
// Check whether there was a previous failed import.
// If yes return the existing error.
@@ -7853,6 +7857,10 @@
if (ToD) {
// If FromD has some updated flags after last import, apply it
updateFlags(FromD, ToD);
+ // If we encounter a cycle during an import then we save the relevant part
+ // of the import path associated to the Decl.
+ if (ImportPath.hasCycleAtBack())
+ SavedImportPaths[FromD].push_back(ImportPath.copyCycleAtBack());
return ToD;
}
@@ -7889,16 +7897,20 @@
// FIXME: AST may contain remaining references to the failed object.
}
- // Error encountered for the first time.
- assert(!getImportDeclErrorIfAny(FromD) &&
- "Import error already set for Decl.");
-
- // After takeError the error is not usable any more in ToDOrErr.
+ // After takeError the error is not usable anymore in ToDOrErr.
// Get a copy of the error object (any more simple solution for this?).
ImportError ErrOut;
handleAllErrors(ToDOrErr.takeError(),
[&ErrOut](const ImportError &E) { ErrOut = E; });
setImportDeclError(FromD, ErrOut);
+
+ // Set the error for all nodes which have been created before we
+ // recognized the error.
+ for (const auto &Path : SavedImportPaths[FromD])
+ for (Decl *Di : Path)
+ setImportDeclError(Di, ErrOut);
+ SavedImportPaths[FromD].clear();
+
// Do not return ToDOrErr, error was taken out of it.
return make_error<ImportError>(ErrOut);
}
@@ -7921,6 +7933,7 @@
Imported(FromD, ToD);
updateFlags(FromD, ToD);
+ SavedImportPaths[FromD].clear();
return ToDOrErr;
}
@@ -8641,9 +8654,10 @@
}
void ASTImporter::setImportDeclError(Decl *From, ImportError Error) {
- assert(ImportDeclErrors.find(From) == ImportDeclErrors.end() &&
- "Setting import error allowed only once for a Decl.");
- ImportDeclErrors[From] = Error;
+ auto InsertRes = ImportDeclErrors.insert({From, Error});
+ // Either we set the error for the first time, or we already had set one and
+ // now we want to set the same error.
+ assert(InsertRes.second || InsertRes.first->second.Error == Error.Error);
}
bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To,