summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/ASTImporter.cpp
diff options
context:
space:
mode:
authorGabor Marton <gabor.marton@ericsson.com>2019-06-25 08:00:51 +0000
committerGabor Marton <gabor.marton@ericsson.com>2019-06-25 08:00:51 +0000
commit303c9861e90cb9a15b15d31fab06d0374d42c9af (patch)
tree4337137fabfb22424855eeaf15cba01f0295d811 /clang/lib/AST/ASTImporter.cpp
parent78edad1bf18e5f72dda26707c40e75cbb5db53da (diff)
downloadbcm5719-llvm-303c9861e90cb9a15b15d31fab06d0374d42c9af.tar.gz
bcm5719-llvm-303c9861e90cb9a15b15d31fab06d0374d42c9af.zip
[ASTImporter] Store import errors for Decls
Summary: We add a new member which is a mapping from the already-imported declarations in the "from" context to the error status of the import of that declaration. This map contains only the declarations that were not correctly imported. The same declaration may or may not be included in ImportedDecls. This map is updated continuously during imports and never cleared (like ImportedDecls). In Import(Decl*) we use this mapping, so if there was a previous failed import we return with the existing error. We add/remove from the Lookuptable in consistency with ImportedFromDecls. When we map a decl in the 'to' context to something in the 'from' context then and only then we add it to the lookup table. When we remove a mapping then and only then we remove it from the lookup table. This patch is the first in a series of patches whose aim is to further strengthen the error handling in ASTImporter. Reviewers: a_sidorin, a.sidorin, shafik Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D62373 llvm-svn: 364279
Diffstat (limited to 'clang/lib/AST/ASTImporter.cpp')
-rw-r--r--clang/lib/AST/ASTImporter.cpp98
1 files changed, 80 insertions, 18 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index d3c79eac903..edefa45fb56 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -253,11 +253,10 @@ namespace clang {
LLVM_NODISCARD bool
GetImportedOrCreateSpecialDecl(ToDeclT *&ToD, CreateFunT CreateFun,
FromDeclT *FromD, Args &&... args) {
- // FIXME: This code is needed later.
- //if (Importer.getImportDeclErrorIfAny(FromD)) {
- // ToD = nullptr;
- // return true; // Already imported but with error.
- //}
+ if (Importer.getImportDeclErrorIfAny(FromD)) {
+ ToD = nullptr;
+ return true; // Already imported but with error.
+ }
ToD = cast_or_null<ToDeclT>(Importer.GetAlreadyImportedOrNull(FromD));
if (ToD)
return true; // Already imported.
@@ -5113,7 +5112,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
}
} else { // ODR violation.
// FIXME HandleNameConflict
- return nullptr;
+ return make_error<ImportError>(ImportError::NameConflict);
}
}
@@ -5555,6 +5554,8 @@ ExpectedStmt ASTNodeImporter::VisitStmt(Stmt *S) {
ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) {
+ if (Importer.returnWithErrorInTest())
+ return make_error<ImportError>(ImportError::UnsupportedConstruct);
SmallVector<IdentifierInfo *, 4> Names;
for (unsigned I = 0, E = S->getNumOutputs(); I != E; I++) {
IdentifierInfo *ToII = Importer.Import(S->getOutputIdentifier(I));
@@ -7749,7 +7750,6 @@ Expected<Decl *> ASTImporter::ImportImpl(Decl *FromD) {
void ASTImporter::RegisterImportedDecl(Decl *FromD, Decl *ToD) {
MapImported(FromD, ToD);
- AddToLookupTable(ToD);
}
Expected<QualType> ASTImporter::Import(QualType FromT) {
@@ -7822,6 +7822,11 @@ Expected<Decl *> ASTImporter::Import(Decl *FromD) {
return nullptr;
+ // Check whether there was a previous failed import.
+ // If yes return the existing error.
+ if (auto Error = getImportDeclErrorIfAny(FromD))
+ return make_error<ImportError>(*Error);
+
// Check whether we've already imported this declaration.
Decl *ToD = GetAlreadyImportedOrNull(FromD);
if (ToD) {
@@ -7832,24 +7837,65 @@ Expected<Decl *> ASTImporter::Import(Decl *FromD) {
// Import the declaration.
ExpectedDecl ToDOrErr = ImportImpl(FromD);
- if (!ToDOrErr)
- return ToDOrErr;
+ if (!ToDOrErr) {
+ // Failed to import.
+
+ auto Pos = ImportedDecls.find(FromD);
+ if (Pos != ImportedDecls.end()) {
+ // Import failed after the object was created.
+ // Remove all references to it.
+ auto *ToD = Pos->second;
+ ImportedDecls.erase(Pos);
+
+ // ImportedDecls and ImportedFromDecls are not symmetric. It may happen
+ // (e.g. with namespaces) that several decls from the 'from' context are
+ // mapped to the same decl in the 'to' context. If we removed entries
+ // from the LookupTable here then we may end up removing them multiple
+ // times.
+
+ // The Lookuptable contains decls only which are in the 'to' context.
+ // Remove from the Lookuptable only if it is *imported* into the 'to'
+ // context (and do not remove it if it was added during the initial
+ // traverse of the 'to' context).
+ auto PosF = ImportedFromDecls.find(ToD);
+ if (PosF != ImportedFromDecls.end()) {
+ if (LookupTable)
+ if (auto *ToND = dyn_cast<NamedDecl>(ToD))
+ LookupTable->remove(ToND);
+ ImportedFromDecls.erase(PosF);
+ }
+
+ // 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.
+ // 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);
+ // Do not return ToDOrErr, error was taken out of it.
+ return make_error<ImportError>(ErrOut);
+ }
+
ToD = *ToDOrErr;
- // FIXME Use getImportDeclErrorIfAny() here (and return with the error) once
- // the error handling is finished in GetImportedOrCreateSpecialDecl().
+ // FIXME: Handle the "already imported with error" case. We can get here
+ // nullptr only if GetImportedOrCreateDecl returned nullptr (after a
+ // previously failed create was requested).
+ // Later GetImportedOrCreateDecl can be updated to return the error.
if (!ToD) {
- return nullptr;
+ auto Err = getImportDeclErrorIfAny(FromD);
+ assert(Err);
+ return make_error<ImportError>(*Err);
}
// Make sure that ImportImpl registered the imported decl.
assert(ImportedDecls.count(FromD) != 0 && "Missing call to MapImported?");
-
- // Once the decl is connected to the existing declarations, i.e. when the
- // redecl chain is properly set then we populate the lookup again.
- // This way the primary context will be able to find all decls.
- AddToLookupTable(ToD);
-
// Notify subclasses.
Imported(FromD, ToD);
@@ -8560,9 +8606,25 @@ Decl *ASTImporter::MapImported(Decl *From, Decl *To) {
// This mapping should be maintained only in this function. Therefore do not
// check for additional consistency.
ImportedFromDecls[To] = From;
+ AddToLookupTable(To);
return To;
}
+llvm::Optional<ImportError>
+ASTImporter::getImportDeclErrorIfAny(Decl *FromD) const {
+ auto Pos = ImportDeclErrors.find(FromD);
+ if (Pos != ImportDeclErrors.end())
+ return Pos->second;
+ else
+ return Optional<ImportError>();
+}
+
+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;
+}
+
bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To,
bool Complain) {
llvm::DenseMap<const Type *, const Type *>::iterator Pos =
OpenPOWER on IntegriCloud