From 98f0723ca24c604d72a10047b10b60743ac71f27 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 24 Jun 2013 22:51:00 +0000 Subject: [PATCH] Check for matching template-parameter-lists when merging template declarations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184791 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Serialization/ASTReaderDecl.cpp | 55 +++++++++++++++++++++++++-- test/Modules/Inputs/cxx-templates-a.h | 4 ++ test/Modules/Inputs/cxx-templates-b.h | 4 ++ test/Modules/cxx-templates.cpp | 26 +++++++++++++ 4 files changed, 86 insertions(+), 3 deletions(-) diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 3d64fa51d9..a7305c887d 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -967,6 +967,9 @@ void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { PD->ParmVarDeclBits.HasInheritedDefaultArg = Record[Idx++]; if (Record[Idx++]) // hasUninstantiatedDefaultArg. PD->setUninstantiatedDefaultArg(Reader.ReadExpr(F)); + + // FIXME: If this is a redeclaration of a function from another module, handle + // inheritance of default arguments. } void ASTDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { @@ -1334,6 +1337,9 @@ void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) { TemplateParameterList* TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx); D->init(TemplatedDecl, TemplateParams); + + // FIXME: If this is a redeclaration of a template from another module, handle + // inheritance of default template arguments. } ASTDeclReader::RedeclarableResult @@ -1772,6 +1778,48 @@ uint64_t ASTReader::getGlobalBitOffset(ModuleFile &M, uint32_t LocalOffset) { return LocalOffset + M.GlobalBitOffset; } +static bool isSameTemplateParameterList(const TemplateParameterList *X, + const TemplateParameterList *Y); + +/// \brief Determine whether two template parameters are similar enough +/// that they may be used in declarations of the same template. +static bool isSameTemplateParameter(const NamedDecl *X, + const NamedDecl *Y) { + if (X->getKind() != Y->getKind()) + return false; + + if (const TemplateTypeParmDecl *TX = dyn_cast(X)) { + const TemplateTypeParmDecl *TY = cast(Y); + return TX->isParameterPack() == TY->isParameterPack(); + } + + if (const NonTypeTemplateParmDecl *TX = dyn_cast(X)) { + const NonTypeTemplateParmDecl *TY = cast(Y); + return TX->isParameterPack() == TY->isParameterPack() && + TX->getASTContext().hasSameType(TX->getType(), TY->getType()); + } + + const TemplateTemplateParmDecl *TX = cast(X); + const TemplateTemplateParmDecl *TY = cast(Y); + return TX->isParameterPack() == TY->isParameterPack() && + isSameTemplateParameterList(TX->getTemplateParameters(), + TY->getTemplateParameters()); +} + +/// \brief Determine whether two template parameter lists are similar enough +/// that they may be used in declarations of the same template. +static bool isSameTemplateParameterList(const TemplateParameterList *X, + const TemplateParameterList *Y) { + if (X->size() != Y->size()) + return false; + + for (unsigned I = 0, N = X->size(); I != N; ++I) + if (!isSameTemplateParameter(X->getParam(I), Y->getParam(I))) + return false; + + return true; +} + /// \brief Determine whether the two declarations refer to the same entity. static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { assert(X->getDeclName() == Y->getDeclName() && "Declaration name mismatch!"); @@ -1841,10 +1889,11 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { // Identical template names and kinds match if their template parameter lists // and patterns match. if (TemplateDecl *TemplateX = dyn_cast(X)) { - TemplateDecl *TemplateY = dyn_cast(Y); - // FIXME: Check template parameter lists. + TemplateDecl *TemplateY = cast(Y); return isSameEntity(TemplateX->getTemplatedDecl(), - TemplateY->getTemplatedDecl()); + TemplateY->getTemplatedDecl()) && + isSameTemplateParameterList(TemplateX->getTemplateParameters(), + TemplateY->getTemplateParameters()); } // FIXME: Many other cases to implement. diff --git a/test/Modules/Inputs/cxx-templates-a.h b/test/Modules/Inputs/cxx-templates-a.h index 52bc3a2e3a..76997c7bdb 100644 --- a/test/Modules/Inputs/cxx-templates-a.h +++ b/test/Modules/Inputs/cxx-templates-a.h @@ -4,3 +4,7 @@ namespace N { template T f() { return T(); } template T f(T); } + +template int template_param_kinds_1(); +template class> int template_param_kinds_2(); +template class> int template_param_kinds_3(); diff --git a/test/Modules/Inputs/cxx-templates-b.h b/test/Modules/Inputs/cxx-templates-b.h index 3cc940c2c4..c50d7059b4 100644 --- a/test/Modules/Inputs/cxx-templates-b.h +++ b/test/Modules/Inputs/cxx-templates-b.h @@ -4,3 +4,7 @@ namespace N { template T f(); template T f(T t) { return t; } } + +template int template_param_kinds_1(); +template class> int template_param_kinds_2(); +template class> int template_param_kinds_3(); diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp index 7926812738..7d500f4896 100644 --- a/test/Modules/cxx-templates.cpp +++ b/test/Modules/cxx-templates.cpp @@ -6,6 +6,12 @@ @import cxx_templates_a; @import cxx_templates_b; +template struct Tmpl_T_C {}; +template struct Tmpl_T_I_I {}; + +template struct Tmpl_T_T_A {}; +template struct Tmpl_T_T_B {}; + void g() { f(0); f(1.0); @@ -20,6 +26,26 @@ void g() { N::f(); // expected-error {{no matching function}} // expected-note@Inputs/cxx-templates-a.h:4 {{couldn't infer template argument}} // expected-note@Inputs/cxx-templates-a.h:5 {{requires 1 argument, but 0 were provided}} + + template_param_kinds_1<0>(); // ok, from cxx-templates-a.h + template_param_kinds_1(); // ok, from cxx-templates-b.h + + template_param_kinds_2(); // expected-error {{no matching function}} + // expected-note@Inputs/cxx-templates-a.h:9 {{invalid explicitly-specified argument}} + // expected-note@Inputs/cxx-templates-b.h:9 {{invalid explicitly-specified argument}} + + template_param_kinds_2(); // expected-error {{ambiguous}} + // expected-note@Inputs/cxx-templates-a.h:9 {{candidate}} + // expected-note@Inputs/cxx-templates-b.h:9 {{candidate}} + + // FIXME: This should be valid, but we incorrectly match the template template + // argument against both template template parameters. + template_param_kinds_3(); // expected-error {{ambiguous}} + // expected-note@Inputs/cxx-templates-a.h:10 {{candidate}} + // expected-note@Inputs/cxx-templates-b.h:10 {{candidate}} + template_param_kinds_3(); // expected-error {{ambiguous}} + // expected-note@Inputs/cxx-templates-a.h:10 {{candidate}} + // expected-note@Inputs/cxx-templates-b.h:10 {{candidate}} } // FIXME: There should only be two 'f's here. -- 2.40.0