martong created this revision. martong added reviewers: xazax.hun, a.sidorin. Herald added subscribers: cfe-commits, dkrupp, rnkovacs.
`DeclContext` is essentially a list of `Decl`s and a lookup table (`LookupPtr`) but these are encapsulated. E.g. `LookupPtr` is private. `DeclContext::removeDecl` has the responsibility to remove the given decl from the list and from the table too. Template specializations cannot participate in normal (qualified) lookup. Consequently no template specialization can be in the lookup table, but they will be in the list. When the lookup table is built or when a new `Decl` is added, then it is checked whether it is a template specialization and if so it is skipped from the lookup table. Thus, whenever we want to remove a `Decl` from a `DeclContext` we must not reach the point to remove that from the lookup table (and that is what this patch do). With respect to ASTImporter: At some point probably we will be reordering `FriendDecl`s and possibly `CXXMethodDecl`s in a `RecordDecl` at `importDeclContext` to be able to structurally compare two `RecordDecl`s. When that happens we most probably want to remove all `Decls` from a `RecordDecl` and then we would add them in the proper order. Repository: rC Clang https://reviews.llvm.org/D46835 Files: lib/AST/DeclBase.cpp unittests/AST/ASTImporterTest.cpp unittests/AST/MatchVerifier.h
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; 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<Decl> Verifier; + auto Code = + R"s( + struct declToImport { + template <typename T0> + struct X {}; + template <typename T0> + struct X<T0*> {}; + X<int*> x0; + }; + )s"; + + testImport(Code, Lang_CXX, "", Lang_CXX, Verifier, recordDecl()); +} + +TEST(ImportExpr, ImportSpecializationsOfFriendClassTemplate) { + MatchVerifier<Decl> Verifier; + auto Code = + R"( + namespace declToImport { + + template <class T> + struct F{}; + + class X { + friend struct F<int>; + friend struct F<double>; + }; + + } // namespace + )"; + + testImport(Code, Lang_CXX11, "", Lang_CXX11, Verifier, namespaceDecl()); +} + +TEST(ImportExpr, ImportSpecializationsOfVariableTemplate) { + MatchVerifier<Decl> Verifier; + auto Code = + R"( + namespace declToImport { + + struct limits { + template<typename T> + static const T min; // declaration of a static data member template + }; + template<typename T> + const T limits::min = { }; // definition of a static data member template + + template const int limits::min<int>; // 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<CXXRecordDecl>().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<CXXRecordDecl>().match( + FromTU, cxxRecordDecl(hasName("A"))); + + ToR2 = Import(FromR, Lang_CXX); + } + + EXPECT_NE(ToR1, ToR2); +} + } // end namespace ast_matchers } // end namespace clang 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,14 +1374,18 @@ } } } - + // Mark that D is no longer in the decl chain. D->NextInContextAndBits.setPointer(nullptr); // Remove D from the lookup table if necessary. if (isa<NamedDecl>(D)) { auto *ND = cast<NamedDecl>(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;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits