Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -633,6 +633,11 @@ DynTypedNodeList getParents(const ast_type_traits::DynTypedNode &Node); + void invalidateParents() { + ReleaseParentMapEntries(); + PointerParents = nullptr; + } + const clang::PrintingPolicy &getPrintingPolicy() const { return PrintingPolicy; } Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -6686,6 +6686,8 @@ if (!ToD) return nullptr; + ToContext.invalidateParents(); + // Record the imported declaration. ImportedDecls[FromD] = ToD; ToD->IdentifierNamespace = FromD->IdentifierNamespace; @@ -6762,13 +6764,17 @@ llvm::DenseMap::iterator Pos = ImportedStmts.find(FromS); if (Pos != ImportedStmts.end()) return Pos->second; - + // Import the type ASTNodeImporter Importer(*this); Stmt *ToS = Importer.Visit(FromS); if (!ToS) return nullptr; + // FIXME: We could add a separate function that assumes parents have already + // been invalidated to avoid repeatedly calling this. + ToContext.invalidateParents(); + // Record the imported declaration. ImportedStmts[FromS] = ToS; return ToS; @@ -6779,37 +6785,39 @@ return nullptr; NestedNameSpecifier *prefix = Import(FromNNS->getPrefix()); + NestedNameSpecifier *ToNNS = nullptr; switch (FromNNS->getKind()) { case NestedNameSpecifier::Identifier: if (IdentifierInfo *II = Import(FromNNS->getAsIdentifier())) { - return NestedNameSpecifier::Create(ToContext, prefix, II); + ToNNS = NestedNameSpecifier::Create(ToContext, prefix, II); } - return nullptr; + break; case NestedNameSpecifier::Namespace: if (auto *NS = cast_or_null(Import(FromNNS->getAsNamespace()))) { - return NestedNameSpecifier::Create(ToContext, prefix, NS); + ToNNS = NestedNameSpecifier::Create(ToContext, prefix, NS); } - return nullptr; + break; case NestedNameSpecifier::NamespaceAlias: if (auto *NSAD = cast_or_null(Import(FromNNS->getAsNamespaceAlias()))) { - return NestedNameSpecifier::Create(ToContext, prefix, NSAD); + ToNNS = NestedNameSpecifier::Create(ToContext, prefix, NSAD); } - return nullptr; + break; case NestedNameSpecifier::Global: - return NestedNameSpecifier::GlobalSpecifier(ToContext); + ToNNS = NestedNameSpecifier::GlobalSpecifier(ToContext); + break; case NestedNameSpecifier::Super: if (auto *RD = cast_or_null(Import(FromNNS->getAsRecordDecl()))) { - return NestedNameSpecifier::SuperSpecifier(ToContext, RD); + ToNNS = NestedNameSpecifier::SuperSpecifier(ToContext, RD); } - return nullptr; + break; case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { @@ -6817,14 +6825,20 @@ if (!T.isNull()) { bool bTemplate = FromNNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate; - return NestedNameSpecifier::Create(ToContext, prefix, + ToNNS = NestedNameSpecifier::Create(ToContext, prefix, bTemplate, T.getTypePtr()); } + break; } - return nullptr; + + default: + llvm_unreachable("Invalid nested name specifier kind"); } - llvm_unreachable("Invalid nested name specifier kind"); + if (ToNNS) + ToContext.invalidateParents(); + + return ToNNS; } NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { Index: unittests/AST/ASTImporterTest.cpp =================================================================== --- unittests/AST/ASTImporterTest.cpp +++ unittests/AST/ASTImporterTest.cpp @@ -1431,6 +1431,36 @@ MatchVerifier{}.match(To->getTranslationUnitDecl(), Pattern)); } +TEST_P(ASTImporterTestBase, ValidParents) { + // Create parent cache in To context. + Decl *PreTU = getTuDecl("struct S {};", Lang_CXX, "pre.cc"); + RecordDecl *FromRD = FirstDeclMatcher().match(PreTU, recordDecl()); + auto ToRD = cast(Import(FromRD, Lang_CXX)); + auto &ToACtx = ToAST->getASTContext(); + ToACtx.getParents(*ToRD); + + Decl *FromTU = getTuDecl("void f() {}", Lang_CXX); + CompoundStmt *FromCS = FirstDeclMatcher().match(FromTU, + compoundStmt()); + FunctionDecl *FromFD = FirstDeclMatcher().match(FromTU, + functionDecl()); + + auto FromPs = FromFD->getASTContext().getParents(*FromCS); + ASSERT_TRUE(!FromPs.empty()); + auto FromP = FromPs[0].get(); + EXPECT_EQ(FromP, FromFD); + + auto ToFD = cast(Import(FromFD, Lang_CXX)); + + Decl *ToTU = ToACtx.getTranslationUnitDecl(); + auto ToCS = FirstDeclMatcher().match(ToTU, compoundStmt()); + + auto ToPs = ToACtx.getParents(*ToCS); + ASSERT_TRUE(!ToPs.empty()); + auto ToP = ToPs[0].get(); + EXPECT_EQ(ToP, ToFD); +} + INSTANTIATE_TEST_CASE_P( ParameterizedTests, ASTImporterTestBase, ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);