[ASTImporter] Do not import FunctionTemplateDecl in record twice.

Summary:
For functions there is a check to not duplicate the declaration if it is in a
record (class). For function templates there was no similar check, if a
template (in the same class) was imported multiple times the
FunctionTemplateDecl was created multiple times with the same templated
FunctionDecl. This can result in problems with the declaration chain.

Reviewers: martong, a.sidorin, shafik, a_sidorin

Reviewed By: a_sidorin

Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D65203

llvm-svn: 368163
This commit is contained in:
Balazs Keri 2019-08-07 12:40:17 +00:00
parent e5fa049efa
commit e9719f9e9e
2 changed files with 58 additions and 2 deletions

View File

@ -3118,9 +3118,19 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (FoundByLookup) {
if (isa<CXXMethodDecl>(FoundByLookup)) {
if (D->getLexicalDeclContext() == D->getDeclContext()) {
if (!D->doesThisDeclarationHaveABody())
if (!D->doesThisDeclarationHaveABody()) {
if (FunctionTemplateDecl *DescribedD =
D->getDescribedFunctionTemplate()) {
// Handle a "templated" function together with its described
// template. This avoids need for a similar check at import of the
// described template.
assert(FoundByLookup->getDescribedFunctionTemplate() &&
"Templated function mapped to non-templated?");
Importer.MapImported(DescribedD,
FoundByLookup->getDescribedFunctionTemplate());
}
return Importer.MapImported(D, FoundByLookup);
else {
} else {
// Let's continue and build up the redecl chain in this case.
// FIXME Merge the functions into one decl.
}

View File

@ -2389,6 +2389,49 @@ TEST_P(ImportFunctions,
functionDecl(hasName("f"), hasDescendant(declRefExpr()))))));
}
struct ImportFunctionTemplates : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportFunctionTemplates, ImportFunctionTemplateInRecordDeclTwice) {
auto Code =
R"(
class X {
template <class T>
void f(T t);
};
)";
Decl *FromTU1 = getTuDecl(Code, Lang_CXX, "input1.cc");
auto *FromD1 = FirstDeclMatcher<FunctionTemplateDecl>().match(
FromTU1, functionTemplateDecl(hasName("f")));
auto *ToD1 = Import(FromD1, Lang_CXX);
Decl *FromTU2 = getTuDecl(Code, Lang_CXX, "input2.cc");
auto *FromD2 = FirstDeclMatcher<FunctionTemplateDecl>().match(
FromTU2, functionTemplateDecl(hasName("f")));
auto *ToD2 = Import(FromD2, Lang_CXX);
EXPECT_EQ(ToD1, ToD2);
}
TEST_P(ImportFunctionTemplates,
ImportFunctionTemplateWithDefInRecordDeclTwice) {
auto Code =
R"(
class X {
template <class T>
void f(T t);
};
template <class T>
void X::f(T t) {};
)";
Decl *FromTU1 = getTuDecl(Code, Lang_CXX, "input1.cc");
auto *FromD1 = FirstDeclMatcher<FunctionTemplateDecl>().match(
FromTU1, functionTemplateDecl(hasName("f")));
auto *ToD1 = Import(FromD1, Lang_CXX);
Decl *FromTU2 = getTuDecl(Code, Lang_CXX, "input2.cc");
auto *FromD2 = FirstDeclMatcher<FunctionTemplateDecl>().match(
FromTU2, functionTemplateDecl(hasName("f")));
auto *ToD2 = Import(FromD2, Lang_CXX);
EXPECT_EQ(ToD1, ToD2);
}
struct ImportFriendFunctions : ImportFunctions {};
TEST_P(ImportFriendFunctions, ImportFriendFunctionRedeclChainProto) {
@ -5223,6 +5266,9 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFriendFunctionTemplates,
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportClasses,
DefaultTestValuesForRunOptions, );
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFunctionTemplates,
DefaultTestValuesForRunOptions, );
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFriendFunctions,
DefaultTestValuesForRunOptions, );