From e2d3a3de71b2fa35614cb732a6da95a41fa38ad9 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 15 Oct 2009 14:05:49 +0000 Subject: [PATCH] Diagnose explicit instantiations of function templates and member functions/static data members of class template specializations that do not have definitions. This is the latter part of [temp.explicit]p4; the former part still needs more testing. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84182 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 9 +++-- lib/Sema/Sema.h | 6 ++- lib/Sema/SemaTemplate.cpp | 9 +++-- lib/Sema/SemaTemplateInstantiateDecl.cpp | 39 +++++++++++++++++-- .../temp/temp.spec/temp.explicit/p1-0x.cpp | 2 +- test/CXX/temp/temp.spec/temp.explicit/p2.cpp | 2 +- test/CXX/temp/temp.spec/temp.explicit/p4.cpp | 16 ++++++++ 7 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 test/CXX/temp/temp.spec/temp.explicit/p4.cpp diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index c9803da719..5ea8a6a288 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1112,9 +1112,12 @@ def err_explicit_instantiation_without_qualified_id_quals : Error< "qualifier in explicit instantiation of '%0%1' requires a template-id">; def err_explicit_instantiation_unqualified_wrong_namespace : Error< "explicit instantiation of %q0 must occur in %1">; -def err_explicit_instantiation_undefined_member_class : Error< - "explicit instantiation of undefined member class %0 of class template %1">; - +def err_explicit_instantiation_undefined_member : Error< + "explicit instantiation of undefined %select{member class|member function|" + "static data member}0 %1 of class template %2">; +def err_explicit_instantiation_undefined_func_template : Error< + "explicit instantiation of undefined function template %0">; + // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; def err_typename_nested_not_type : Error< diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 80f3663021..9b46f77c13 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3197,11 +3197,13 @@ public: void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, - bool Recursive = false); + bool Recursive = false, + bool DefinitionRequired = false); void InstantiateStaticDataMemberDefinition( SourceLocation PointOfInstantiation, VarDecl *Var, - bool Recursive = false); + bool Recursive = false, + bool DefinitionRequired = false); void InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 04580b70b8..aa0c034a55 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3657,8 +3657,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, CXXRecordDecl *Def = cast_or_null(Pattern->getDefinition(Context)); if (!Def) { - Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member_class) - << Record->getDeclName() << Record->getDeclContext(); + Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member) + << 0 << Record->getDeclName() << Record->getDeclContext(); Diag(Pattern->getLocation(), diag::note_forward_declaration) << Pattern; return true; @@ -3787,7 +3787,8 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // FIXME: Check for prior specializations and such. Prev->setTemplateSpecializationKind(TSK); if (TSK == TSK_ExplicitInstantiationDefinition) - InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false); + InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false, + /*DefinitionRequired=*/true); // FIXME: Create an ExplicitInstantiation node? return DeclPtrTy(); @@ -3887,7 +3888,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // definition. if (TSK == TSK_ExplicitInstantiationDefinition) InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, - false); + false, /*DefinitionRequired=*/true); Specialization->setTemplateSpecializationKind(TSK); break; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 060cc55983..ca05d59aba 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1044,9 +1044,14 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, /// /// \param Recursive if true, recursively instantiates any functions that /// are required by this instantiation. +/// +/// \param DefinitionRequired if true, then we are performing an explicit +/// instantiation where the body of the function is required. Complain if +/// there is no such body. void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, - bool Recursive) { + bool Recursive, + bool DefinitionRequired) { if (Function->isInvalidDecl()) return; @@ -1075,8 +1080,24 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (PatternDecl) Pattern = PatternDecl->getBody(PatternDecl); - if (!Pattern) + if (!Pattern) { + if (DefinitionRequired) { + if (Function->getPrimaryTemplate()) + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_func_template) + << Function->getPrimaryTemplate(); + else + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_member) + << 1 << Function->getDeclName() << Function->getDeclContext(); + + if (PatternDecl) + Diag(PatternDecl->getLocation(), + diag::note_explicit_instantiation_here); + } + return; + } // C++0x [temp.explicit]p9: // Except for inline functions, other explicit instantiation declarations @@ -1161,10 +1182,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, /// /// \param Recursive if true, recursively instantiates any functions that /// are required by this instantiation. +/// +/// \param DefinitionRequired if true, then we are performing an explicit +/// instantiation where an out-of-line definition of the member variable +/// is required. Complain if there is no such definition. void Sema::InstantiateStaticDataMemberDefinition( SourceLocation PointOfInstantiation, VarDecl *Var, - bool Recursive) { + bool Recursive, + bool DefinitionRequired) { if (Var->isInvalidDecl()) return; @@ -1187,6 +1213,13 @@ void Sema::InstantiateStaticDataMemberDefinition( // so we won't perform any instantiation. Rather, we rely on the user to // instantiate this definition (or provide a specialization for it) in // another translation unit. + if (DefinitionRequired) { + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_member) + << 2 << Var->getDeclName() << Var->getDeclContext(); + Diag(Def->getLocation(), diag::note_explicit_instantiation_here); + } + return; } diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp index becdd6b606..d7731f1763 100644 --- a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp +++ b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp @@ -2,7 +2,7 @@ template struct X { - void f(); + void f() {} }; template inline void X::f(); // expected-error{{'inline'}} diff --git a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp index aee0e5d19d..f3d2c955cb 100644 --- a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp +++ b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp @@ -35,7 +35,7 @@ namespace N { }; template - void f1(T); // expected-note{{explicit instantiation refers here}} + void f1(T) {}; // expected-note{{explicit instantiation refers here}} } using namespace N; diff --git a/test/CXX/temp/temp.spec/temp.explicit/p4.cpp b/test/CXX/temp/temp.spec/temp.explicit/p4.cpp new file mode 100644 index 0000000000..c45df562e4 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p4.cpp @@ -0,0 +1,16 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template void f0(T); // expected-note{{here}} +template void f0(int); // expected-error{{explicit instantiation of undefined function template}} + +template +struct X0 { + void f1(); // expected-note{{here}} + + static T value; // expected-note{{here}} +}; + +template void X0::f1(); // expected-error{{explicit instantiation of undefined member function}} + +template int X0::value; // expected-error{{explicit instantiation of undefined static data member}} + -- 2.40.0