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 @@ -2897,6 +2897,17 @@ getCanonicalForwardRedeclChain(D2CXX); for (auto *R : Redecls) { auto *RI = cast(R); + // Skip this declaration if it is currently under import and + // incomplete. Because it is under import we will reach this place in + // its own import call. At import of a "templated" CXXRecordDecl the + // described template is imported first and that import call sets the + // described template. But before this is done other imports happen so + // this case may occur. + if (!RI->getDescribedTemplate()) + continue; + // Skip the declaration if injected type is already set. + if (isa(RI->getTypeForDecl())) + continue; RI->setTypeForDecl(nullptr); // Below we create a new injected type and assign that to the // canonical decl, subsequent declarations in the chain will reuse 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 @@ -6141,6 +6141,41 @@ EXPECT_EQ(ToAttr->getAnnotation(), "A"); } +TEST_P(ASTImporterOptionSpecificTestBase, + ImportOfTemplatedDeclWhenPreviousDeclHasNoDescribedTemplateSet) { + Decl *FromTU = getTuDecl( + R"( + + namespace std { + template + class basic_stringbuf; + } + namespace std { + class char_traits; + template + class basic_stringbuf; + } + namespace std { + template + class basic_stringbuf {}; + } + + )", + Lang_CXX11); + + auto *From1 = FirstDeclMatcher().match( + FromTU, + classTemplateDecl(hasName("basic_stringbuf"), unless(isImplicit()))); + auto *To1 = cast_or_null(Import(From1, Lang_CXX11)); + EXPECT_TRUE(To1); + + auto *From2 = LastDeclMatcher().match( + FromTU, + classTemplateDecl(hasName("basic_stringbuf"), unless(isImplicit()))); + auto *To2 = cast_or_null(Import(From2, Lang_CXX11)); + EXPECT_TRUE(To2); +} + INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest, DefaultTestValuesForRunOptions, );