Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -1350,6 +1350,8 @@ (D->NextInContextAndBits.getPointer() || D == LastDecl)); } +static bool shouldBeHidden(NamedDecl *D); + void DeclContext::removeDecl(Decl *D) { assert(D->getLexicalDeclContext() == this && "decl being removed from non-lexical context"); @@ -1372,7 +1374,7 @@ } } } - + // Mark that D is no longer in the decl chain. D->NextInContextAndBits.setPointer(nullptr); @@ -1380,6 +1382,10 @@ if (isa(D)) { auto *ND = cast(D); + // Do not try to remove the declaration if that is invisible to qualified + // lookup. E.g. template sepcializations are skipped. + if (shouldBeHidden(ND)) return; + // Remove only decls that have a name if (!ND->getDeclName()) return; Index: unittests/AST/ASTImporterTest.cpp =================================================================== --- unittests/AST/ASTImporterTest.cpp +++ unittests/AST/ASTImporterTest.cpp @@ -52,6 +52,9 @@ case Lang_CXX11: BasicArgs = {"-std=c++11", "-frtti"}; break; + case Lang_CXX14: + BasicArgs = {"-std=c++14", "-frtti"}; + break; case Lang_OpenCL: case Lang_OBJCXX: llvm_unreachable("Not implemented yet!"); @@ -1764,5 +1767,86 @@ compoundStmt(has(callExpr(has(unresolvedMemberExpr()))))))))); } +TEST(ImportExpr, ImportClassTemplatePartialSpecialization) { + MatchVerifier Verifier; + auto Code = + R"s( + struct declToImport { + template + struct X {}; + template + struct X {}; + X x0; + }; + )s"; + + testImport(Code, Lang_CXX, "", Lang_CXX, Verifier, recordDecl()); +} + +TEST(ImportExpr, ImportSpecializationsOfFriendClassTemplate) { + MatchVerifier Verifier; + auto Code = + R"( + namespace declToImport { + + template + struct F{}; + + class X { + friend struct F; + friend struct F; + }; + + } // namespace + )"; + + testImport(Code, Lang_CXX11, "", Lang_CXX11, Verifier, namespaceDecl()); +} + +TEST(ImportExpr, ImportSpecializationsOfVariableTemplate) { + MatchVerifier Verifier; + auto Code = + R"( + namespace declToImport { + + struct limits { + template + static const T min; // declaration of a static data member template + }; + template + const T limits::min = { }; // definition of a static data member template + + template const int limits::min; // explicit instantiation + + } // namespace + )"; + + testImport(Code, Lang_CXX14, "", Lang_CXX14, Verifier, namespaceDecl()); +} + +TEST_P(ASTImporterTestBase, DISABLED_ImportOfRecordWithDifferentFriends) { + Decl *ToR1; + { + Decl *FromTU = getTuDecl("struct A { friend class F0; friend class F1; };", + Lang_CXX, "input0.cc"); + auto *FromR = FirstDeclMatcher().match( + FromTU, cxxRecordDecl(hasName("A"))); + + ToR1 = Import(FromR, Lang_CXX); + } + + Decl *ToR2; + { + Decl *FromTU = + getTuDecl("struct A { friend class F0; };", Lang_CXX, "input1.cc"); + auto *FromR = FirstDeclMatcher().match( + FromTU, cxxRecordDecl(hasName("A"))); + + ToR2 = Import(FromR, Lang_CXX); + } + + EXPECT_NE(ToR1, ToR2); +} + } // end namespace ast_matchers } // end namespace clang Index: unittests/AST/MatchVerifier.h =================================================================== --- unittests/AST/MatchVerifier.h +++ unittests/AST/MatchVerifier.h @@ -28,11 +28,12 @@ namespace clang { namespace ast_matchers { -enum Language { +enum Language { Lang_C, Lang_C89, Lang_CXX, Lang_CXX11, + Lang_CXX14, Lang_OpenCL, Lang_OBJCXX }; @@ -113,6 +114,10 @@ Args.push_back("-std=c++11"); FileName = "input.cc"; break; + case Lang_CXX14: + Args.push_back("-std=c++14"); + FileName = "input.cc"; + break; case Lang_OpenCL: FileName = "input.cl"; break;