diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -8776,8 +8776,24 @@ // Set the error for all nodes which have been created before we // recognized the error. - for (const auto &Path : SavedImportPaths[FromD]) + for (const auto &Path : SavedImportPaths[FromD]) { + Decl *PrevFromDi = FromD; for (Decl *FromDi : Path) { + // Begin and end of the path equals 'FromD', skip it. + if (FromDi == FromD) + continue; + // We should not set import error on a node that "consumes" the error + // during import of its children (failing import of the child does not + // cause failure of the parent). See ImportDeclContext and uses of + // 'consumeError'. + // The import path contains child nodes first. + // (Parent-child relationship is used here in sense of import + // dependency.) + if (!isa(FromDi)) + if (auto *FromDiDC = dyn_cast(FromDi)) + if (FromDiDC->containsDecl(PrevFromDi)) + break; // Skip every following node in the path. + PrevFromDi = FromDi; setImportDeclError(FromDi, ErrOut); //FIXME Should we remove these Decls from ImportedDecls? // Set the error for the mapped to Decl, which is in the "to" context. @@ -8787,6 +8803,7 @@ // FIXME Should we remove these Decls from the LookupTable, // and from ImportedFromDecls? } + } SavedImportPaths.erase(FromD); // Do not return ToDOrErr, error was taken out of it. diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -5806,6 +5806,53 @@ EXPECT_FALSE(ImportedF); } +TEST_P(ErrorHandlingTest, DoNotInheritErrorFromNonDependentChild) { + // Declarations should not inherit an import error from a child object + // if the declaration has no direct dependence to such a child. + // For example a namespace should not get import error if one of the + // declarations inside it fails to import. + // There was a special case in error handling (when "import path circles" are + // encountered) when this property was not held. This case is provoked by the + // following code. + constexpr auto ToTUCode = R"( + namespace ns { + struct Err { + char A; + }; + } + )"; + constexpr auto FromTUCode = R"( + namespace ns { + struct A { + using U = struct Err; + }; + } + namespace ns { + struct Err {}; // ODR violation + void f(A) {} + } + )"; + + Decl *ToTU = getToTuDecl(ToTUCode, Lang_CXX11); + static_cast(ToTU); + Decl *FromTU = getTuDecl(FromTUCode, Lang_CXX11); + auto *FromA = FirstDeclMatcher().match( + FromTU, cxxRecordDecl(hasName("A"), hasDefinition())); + ASSERT_TRUE(FromA); + auto *ImportedA = Import(FromA, Lang_CXX11); + // 'A' can not be imported: ODR error at 'Err' + EXPECT_FALSE(ImportedA); + // When import of 'A' failed there was a "saved import path circle" that + // contained namespace 'ns' (A - U - Err - ns - f - A). This should not mean + // that every object in this path fails to import. + + Decl *FromNS = FirstDeclMatcher().match( + FromTU, namespaceDecl(hasName("ns"))); + EXPECT_TRUE(FromNS); + auto *ImportedNS = Import(FromNS, Lang_CXX11); + EXPECT_TRUE(ImportedNS); +} + TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionBody) { Decl *FromTU = getTuDecl( R"(