diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index bc28bb567f693..c3179b80cfcc5 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -670,6 +670,10 @@ Bug Fixes to C++ Support default initializing a base class in a constant expression context. Fixes: (`#69890 `_) +- Fix crash when template class static member imported to other translation unit. + Fixes: + (`#68769 `_) + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an import failure of recursive friend class template. diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 650ff201e66b7..c4e931e220f69 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -4476,6 +4476,17 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) { auto ToVTOrErr = import(D->getDescribedVarTemplate()); if (!ToVTOrErr) return ToVTOrErr.takeError(); + } else if (MemberSpecializationInfo *MSI = D->getMemberSpecializationInfo()) { + TemplateSpecializationKind SK = MSI->getTemplateSpecializationKind(); + VarDecl *FromInst = D->getInstantiatedFromStaticDataMember(); + if (Expected ToInstOrErr = import(FromInst)) + ToVar->setInstantiationOfStaticDataMember(*ToInstOrErr, SK); + else + return ToInstOrErr.takeError(); + if (ExpectedSLoc POIOrErr = import(MSI->getPointOfInstantiation())) + ToVar->getMemberSpecializationInfo()->setPointOfInstantiation(*POIOrErr); + else + return POIOrErr.takeError(); } if (Error Err = ImportInitializer(D, ToVar)) diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 87e6cd1e160c4..0cbec5cf9ba06 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -1370,6 +1370,40 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplatedDecl) { ASSERT_EQ(ToTemplated1, ToTemplated); } +TEST_P(ASTImporterOptionSpecificTestBase, + ImportTemplateSpecializationStaticMember) { + auto FromCode = + R"( + template class Test{ + public: + static const unsigned int length; + }; + + template<> const unsigned int Test::length; + template<> const unsigned int Test::length = 0; + )"; + auto ToCode = + R"( + template class Test { + public: + static const unsigned int length; + }; + + template <> const unsigned int Test::length; + + void foo() { int i = 1 / Test::length; } + )"; + Decl *FromTU = getTuDecl(FromCode, Lang_CXX14); + auto FromDecl = FirstDeclMatcher().match( + FromTU, varDecl(hasName("length"), isDefinition())); + Decl *ToTu = getToTuDecl(ToCode, Lang_CXX14); + auto ToX = Import(FromDecl, Lang_CXX03); + auto ToDecl = FirstDeclMatcher().match( + ToTu, varDecl(hasName("length"), isDefinition())); + EXPECT_TRUE(ToX); + EXPECT_EQ(ToX, ToDecl); +} + TEST_P(ASTImporterOptionSpecificTestBase, ImportChooseExpr) { // This tests the import of isConditionTrue directly to make sure the importer // gets it right.