if (Error Err = importInto(TemplatedFD, D->getTemplatedDecl()))
return std::move(Err);
- // Template parameters of the ClassTemplateDecl and FunctionTemplateDecl are
- // shared, if the FunctionTemplateDecl is a deduction guide for the class.
- // At import the ClassTemplateDecl object is always created first (FIXME: is
- // this really true?) because the dependency, then the FunctionTemplateDecl.
- // The DeclContext of the template parameters is changed when the
- // FunctionTemplateDecl is created, but was set already when the class
- // template was created. So here it is not the TU (default value) any more.
- // FIXME: The DeclContext of the parameters is now set finally to the
- // CXXDeductionGuideDecl object that was imported later. This may not be the
- // same that is in the original AST, specially if there are multiple deduction
- // guides.
- DeclContext *OldParamDC = nullptr;
- if (Params->size() > 0)
- OldParamDC = Params->getParam(0)->getDeclContext();
+ // At creation of the template the template parameters are "adopted"
+ // (DeclContext is changed). After this possible change the lookup table
+ // must be updated.
+ // At deduction guides the DeclContext of the template parameters may be
+ // different from what we would expect, it may be the class template, or a
+ // probably different CXXDeductionGuideDecl. This may come from the fact that
+ // the template parameter objects may be shared between deduction guides or
+ // the class template, and at creation of multiple FunctionTemplateDecl
+ // objects (for deduction guides) the same parameters are re-used. The
+ // "adoption" happens multiple times with different parent, even recursively
+ // for TemplateTemplateParmDecl. The same happens at import when the
+ // FunctionTemplateDecl objects are created, but in different order.
+ // In this way the DeclContext of these template parameters is not necessarily
+ // the same as in the "from" context.
+ SmallVector<DeclContext *, 2> OldParamDC;
+ OldParamDC.reserve(Params->size());
+ llvm::transform(*Params, std::back_inserter(OldParamDC),
+ [](NamedDecl *ND) { return ND->getDeclContext(); });
FunctionTemplateDecl *ToFunc;
if (GetImportedOrCreateDecl(ToFunc, D, Importer.getToContext(), DC, Loc, Name,
ToFunc->setAccess(D->getAccess());
ToFunc->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToFunc);
- updateLookupTableForTemplateParameters(*Params, OldParamDC);
+
+ ASTImporterLookupTable *LT = Importer.SharedState->getLookupTable();
+ if (LT && !OldParamDC.empty()) {
+ for (unsigned int I = 0; I < OldParamDC.size(); ++I)
+ LT->updateForced(Params->getParam(I), OldParamDC[I]);
+ }
if (FoundByLookup) {
auto *Recent =
EXPECT_EQ(*ShadowI, ToUsingShadowF2);
}
+AST_MATCHER_P(FunctionTemplateDecl, templateParameterCountIs, unsigned, Cnt) {
+ return Node.getTemplateParameters()->size() == Cnt;
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase, ImportDeductionGuide) {
+ TranslationUnitDecl *FromTU = getTuDecl(
+ R"(
+ template<class> class A { };
+ template<class T> class B {
+ template<class T1, typename = A<T>> B(T1);
+ };
+ template<class T>
+ B(T, T) -> B<int>;
+ )",
+ Lang_CXX17);
+
+ // Get the implicit deduction guide for (non-default) constructor of 'B'.
+ auto *FromDGCtor = FirstDeclMatcher<FunctionTemplateDecl>().match(
+ FromTU, functionTemplateDecl(templateParameterCountIs(3)));
+ // Implicit deduction guide for copy constructor of 'B'.
+ auto *FromDGCopyCtor = FirstDeclMatcher<FunctionTemplateDecl>().match(
+ FromTU, functionTemplateDecl(templateParameterCountIs(1), isImplicit()));
+ // User defined deduction guide.
+ auto *FromDGOther = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
+ FromTU, cxxDeductionGuideDecl(unless(isImplicit())));
+
+ TemplateParameterList *FromDGCtorTP = FromDGCtor->getTemplateParameters();
+ // Don't know why exactly but this is the DeclContext here.
+ EXPECT_EQ(FromDGCtorTP->getParam(0)->getDeclContext(),
+ FromDGCopyCtor->getTemplatedDecl());
+ EXPECT_EQ(FromDGCtorTP->getParam(1)->getDeclContext(),
+ FromDGCtor->getTemplatedDecl());
+ EXPECT_EQ(FromDGCtorTP->getParam(2)->getDeclContext(),
+ FromDGCtor->getTemplatedDecl());
+ EXPECT_EQ(
+ FromDGCopyCtor->getTemplateParameters()->getParam(0)->getDeclContext(),
+ FromDGCopyCtor->getTemplatedDecl());
+ EXPECT_EQ(FromDGOther->getDescribedTemplate()
+ ->getTemplateParameters()
+ ->getParam(0)
+ ->getDeclContext(),
+ FromDGOther);
+
+ auto *ToDGCtor = Import(FromDGCtor, Lang_CXX17);
+ auto *ToDGCopyCtor = Import(FromDGCopyCtor, Lang_CXX17);
+ auto *ToDGOther = Import(FromDGOther, Lang_CXX17);
+ ASSERT_TRUE(ToDGCtor);
+ ASSERT_TRUE(ToDGCopyCtor);
+ ASSERT_TRUE(ToDGOther);
+
+ TemplateParameterList *ToDGCtorTP = ToDGCtor->getTemplateParameters();
+ EXPECT_EQ(ToDGCtorTP->getParam(0)->getDeclContext(),
+ ToDGCopyCtor->getTemplatedDecl());
+ EXPECT_EQ(ToDGCtorTP->getParam(1)->getDeclContext(),
+ ToDGCtor->getTemplatedDecl());
+ EXPECT_EQ(ToDGCtorTP->getParam(2)->getDeclContext(),
+ ToDGCtor->getTemplatedDecl());
+ EXPECT_EQ(
+ ToDGCopyCtor->getTemplateParameters()->getParam(0)->getDeclContext(),
+ ToDGCopyCtor->getTemplatedDecl());
+ EXPECT_EQ(ToDGOther->getDescribedTemplate()
+ ->getTemplateParameters()
+ ->getParam(0)
+ ->getDeclContext(),
+ ToDGOther);
+}
+
+TEST_P(ASTImporterOptionSpecificTestBase, ImportDeductionGuideDifferentOrder) {
+ // This test demonstrates that the DeclContext of the imported object is
+ // dependent on the order of import. The test is an exact copy of the previous
+ // one except at the indicated locations.
+ TranslationUnitDecl *FromTU = getTuDecl(
+ R"(
+ template<class> class A { };
+ template<class T> class B {
+ template<class T1, typename = A<T>> B(T1);
+ };
+ template<class T>
+ B(T, T) -> B<int>;
+ )",
+ Lang_CXX17);
+
+ // Get the implicit deduction guide for (non-default) constructor of 'B'.
+ auto *FromDGCtor = FirstDeclMatcher<FunctionTemplateDecl>().match(
+ FromTU, functionTemplateDecl(templateParameterCountIs(3)));
+ // Implicit deduction guide for copy constructor of 'B'.
+ auto *FromDGCopyCtor = FirstDeclMatcher<FunctionTemplateDecl>().match(
+ FromTU, functionTemplateDecl(templateParameterCountIs(1), isImplicit()));
+ // User defined deduction guide.
+ auto *FromDGOther = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
+ FromTU, cxxDeductionGuideDecl(unless(isImplicit())));
+
+ TemplateParameterList *FromDGCtorTP = FromDGCtor->getTemplateParameters();
+ // Don't know why exactly but this is the DeclContext here.
+ EXPECT_EQ(FromDGCtorTP->getParam(0)->getDeclContext(),
+ FromDGCopyCtor->getTemplatedDecl());
+ EXPECT_EQ(FromDGCtorTP->getParam(1)->getDeclContext(),
+ FromDGCtor->getTemplatedDecl());
+ EXPECT_EQ(FromDGCtorTP->getParam(2)->getDeclContext(),
+ FromDGCtor->getTemplatedDecl());
+ EXPECT_EQ(
+ FromDGCopyCtor->getTemplateParameters()->getParam(0)->getDeclContext(),
+ FromDGCopyCtor->getTemplatedDecl());
+ EXPECT_EQ(FromDGOther->getDescribedTemplate()
+ ->getTemplateParameters()
+ ->getParam(0)
+ ->getDeclContext(),
+ FromDGOther);
+
+ // Here the import of 'ToDGCopyCtor' and 'ToDGCtor' is reversed relative to
+ // the previous test.
+ auto *ToDGCopyCtor = Import(FromDGCopyCtor, Lang_CXX17);
+ auto *ToDGCtor = Import(FromDGCtor, Lang_CXX17);
+ auto *ToDGOther = Import(FromDGOther, Lang_CXX17);
+ ASSERT_TRUE(ToDGCtor);
+ ASSERT_TRUE(ToDGCopyCtor);
+ ASSERT_TRUE(ToDGOther);
+
+ TemplateParameterList *ToDGCtorTP = ToDGCtor->getTemplateParameters();
+ // Next line: DeclContext is different relative to the previous test.
+ EXPECT_EQ(ToDGCtorTP->getParam(0)->getDeclContext(),
+ ToDGCtor->getTemplatedDecl());
+ EXPECT_EQ(ToDGCtorTP->getParam(1)->getDeclContext(),
+ ToDGCtor->getTemplatedDecl());
+ EXPECT_EQ(ToDGCtorTP->getParam(2)->getDeclContext(),
+ ToDGCtor->getTemplatedDecl());
+ // Next line: DeclContext is different relative to the previous test.
+ EXPECT_EQ(
+ ToDGCopyCtor->getTemplateParameters()->getParam(0)->getDeclContext(),
+ ToDGCtor->getTemplatedDecl());
+ EXPECT_EQ(ToDGOther->getDescribedTemplate()
+ ->getTemplateParameters()
+ ->getParam(0)
+ ->getDeclContext(),
+ ToDGOther);
+}
+
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest,
DefaultTestValuesForRunOptions);