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 @@ -548,6 +548,7 @@ ExpectedDecl VisitUsingDecl(UsingDecl *D); ExpectedDecl VisitUsingShadowDecl(UsingShadowDecl *D); ExpectedDecl VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + ExpectedDecl VisitUsingPackDecl(UsingPackDecl *D); ExpectedDecl ImportUsingShadowDecls(BaseUsingDecl *D, BaseUsingDecl *ToSI); ExpectedDecl VisitUsingEnumDecl(UsingEnumDecl *D); ExpectedDecl VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); @@ -4832,6 +4833,35 @@ return ToUsingDir; } +ExpectedDecl ASTNodeImporter::VisitUsingPackDecl(UsingPackDecl *D) { + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD = nullptr; + if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return std::move(Err); + if (ToD) + return ToD; + + auto ToInstantiatedFromUsingOrErr = + Importer.Import(D->getInstantiatedFromUsingDecl()); + if (!ToInstantiatedFromUsingOrErr) + return ToInstantiatedFromUsingOrErr.takeError(); + SmallVector Expansions(D->expansions().size()); + if (Error Err = ImportArrayChecked(D->expansions(), Expansions.begin())) + return std::move(Err); + + UsingPackDecl *ToUsingPack; + if (GetImportedOrCreateDecl(ToUsingPack, D, Importer.getToContext(), DC, + cast(*ToInstantiatedFromUsingOrErr), + Expansions)) + return ToUsingPack; + + addDeclToContexts(D, ToUsingPack); + + return ToUsingPack; +} + ExpectedDecl ASTNodeImporter::VisitUnresolvedUsingValueDecl( UnresolvedUsingValueDecl *D) { DeclContext *DC, *LexicalDC; 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 @@ -910,6 +910,20 @@ functionDecl(hasDescendant(usingEnumDecl(hasName("bar"))))); } +const internal::VariadicDynCastAllOfMatcher usingPackDecl; + +TEST_P(ImportDecl, ImportUsingPackDecl) { + MatchVerifier Verifier; + testImport( + "struct A { int operator()() { return 1; } };" + "struct B { int operator()() { return 2; } };" + "template struct C : T... { using T::operator()...; };" + "C declToImport;", + Lang_CXX20, "", Lang_CXX20, Verifier, + varDecl(hasType(templateSpecializationType(hasDeclaration( + classTemplateSpecializationDecl(hasDescendant(usingPackDecl()))))))); +} + /// \brief Matches shadow declarations introduced into a scope by a /// (resolved) using declaration. /// @@ -1022,6 +1036,31 @@ has(fieldDecl(hasType(dependentSizedArrayType()))))))); } +TEST_P(ASTImporterOptionSpecificTestBase, ImportUsingPackDecl) { + Decl *FromTU = getTuDecl( + "struct A { int operator()() { return 1; } };" + "struct B { int operator()() { return 2; } };" + "template struct C : T... { using T::operator()...; };" + "C Var;", + Lang_CXX20); + + auto From = FirstDeclMatcher().match(FromTU, usingPackDecl()); + ASSERT_TRUE(From); + auto To = cast(Import(From, Lang_CXX20)); + ASSERT_TRUE(To); + + ArrayRef FromExpansions = From->expansions(); + ArrayRef ToExpansions = To->expansions(); + ASSERT_EQ(FromExpansions.size(), ToExpansions.size()); + for (unsigned int I = 0; I < FromExpansions.size(); ++I) { + auto ImportedExpansion = Import(FromExpansions[I], Lang_CXX20); + EXPECT_EQ(ImportedExpansion, ToExpansions[I]); + } + + auto ImportedDC = cast(Import(From->getDeclContext(), Lang_CXX20)); + EXPECT_EQ(ImportedDC, cast(To->getDeclContext())); +} + TEST_P(ASTImporterOptionSpecificTestBase, TemplateTypeParmDeclNoDefaultArg) { Decl *FromTU = getTuDecl("template struct X {};", Lang_CXX03); auto From = FirstDeclMatcher().match(