balazske created this revision.
Herald added subscribers: martong, teemperor, gamesh411, Szelethus, dkrupp.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
balazske requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
The assertion can happen if ASTImporter imports a CXXRecordDecl in a template
and then imports another redeclaration of this declaration, while the first
import is in progress.
The process of first import did not set the "described template" yet
and the second import finds the first declaration at setting the injected types.
Setting the injected type requires in the assertion that the described template
is set.
The exact assertion was:
clang/lib/AST/ASTContext.cpp:4411:
clang::QualType
clang::ASTContext::getInjectedClassNameType(clang::CXXRecordDecl*,
clang::QualType) const:
Assertion `NeedsInjectedClassNameType(Decl)' failed.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D94067
Files:
clang/lib/AST/ASTImporter.cpp
clang/unittests/AST/ASTImporterTest.cpp
Index: clang/unittests/AST/ASTImporterTest.cpp
===================================================================
--- clang/unittests/AST/ASTImporterTest.cpp
+++ 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<typename T>
+ class basic_stringbuf;
+ }
+ namespace std {
+ class char_traits;
+ template<typename T = char_traits>
+ class basic_stringbuf;
+ }
+ namespace std {
+ template<typename T>
+ class basic_stringbuf {};
+ }
+
+ )",
+ Lang_CXX11);
+
+ auto *From1 = FirstDeclMatcher<ClassTemplateDecl>().match(
+ FromTU,
+ classTemplateDecl(hasName("basic_stringbuf"), unless(isImplicit())));
+ auto *To1 = cast_or_null<ClassTemplateDecl>(Import(From1, Lang_CXX11));
+ EXPECT_TRUE(To1);
+
+ auto *From2 = LastDeclMatcher<ClassTemplateDecl>().match(
+ FromTU,
+ classTemplateDecl(hasName("basic_stringbuf"), unless(isImplicit())));
+ auto *To2 = cast_or_null<ClassTemplateDecl>(Import(From2, Lang_CXX11));
+ EXPECT_TRUE(To2);
+}
+
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest,
DefaultTestValuesForRunOptions, );
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -2897,6 +2897,17 @@
getCanonicalForwardRedeclChain(D2CXX);
for (auto *R : Redecls) {
auto *RI = cast<CXXRecordDecl>(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<InjectedClassNameType>(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
Index: clang/unittests/AST/ASTImporterTest.cpp
===================================================================
--- clang/unittests/AST/ASTImporterTest.cpp
+++ 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<typename T>
+ class basic_stringbuf;
+ }
+ namespace std {
+ class char_traits;
+ template<typename T = char_traits>
+ class basic_stringbuf;
+ }
+ namespace std {
+ template<typename T>
+ class basic_stringbuf {};
+ }
+
+ )",
+ Lang_CXX11);
+
+ auto *From1 = FirstDeclMatcher<ClassTemplateDecl>().match(
+ FromTU,
+ classTemplateDecl(hasName("basic_stringbuf"), unless(isImplicit())));
+ auto *To1 = cast_or_null<ClassTemplateDecl>(Import(From1, Lang_CXX11));
+ EXPECT_TRUE(To1);
+
+ auto *From2 = LastDeclMatcher<ClassTemplateDecl>().match(
+ FromTU,
+ classTemplateDecl(hasName("basic_stringbuf"), unless(isImplicit())));
+ auto *To2 = cast_or_null<ClassTemplateDecl>(Import(From2, Lang_CXX11));
+ EXPECT_TRUE(To2);
+}
+
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest,
DefaultTestValuesForRunOptions, );
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -2897,6 +2897,17 @@
getCanonicalForwardRedeclChain(D2CXX);
for (auto *R : Redecls) {
auto *RI = cast<CXXRecordDecl>(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<InjectedClassNameType>(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
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits