diff options
Diffstat (limited to 'clang/lib/AST/ASTImporter.cpp')
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 98 |
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 = |