diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-10-15 12:53:22 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-10-15 12:53:22 +0000 |
commit | bf7643e7966cd9acd797a84870018034112e49d3 (patch) | |
tree | e0d67a4229083d8f0ee3404d728c5cac4735087b | |
parent | 3425b97cc630717098f719d2d861b7e2be960bd0 (diff) |
More explicit template instantiation. Now we're checking for more
cases where an explicit instantiation requires a definition; the
remainder of these checks will come with the implementation of
paragraph 4 of [temp.explicit].
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84181 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 20 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.explicit/p3.cpp | 55 |
3 files changed, 71 insertions, 6 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b1222a3f84..c9803da719 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1112,6 +1112,8 @@ 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">; // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index ab0bbe081d..04580b70b8 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3651,12 +3651,20 @@ Sema::ActOnExplicitInstantiation(Scope *S, CheckExplicitInstantiationScope(*this, Record, NameLoc, true); if (!Record->getDefinition(Context)) { - // If the class has a definition, instantiate it (and all of its - // members, recursively). - Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); - if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern, - getTemplateInstantiationArgs(Record), - TSK)) + // C++ [temp.explicit]p3: + // A definition of a member class of a class template shall be in scope + // at the point of an explicit instantiation of the member class. + CXXRecordDecl *Def + = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); + if (!Def) { + Diag(TemplateLoc, diag::err_explicit_instantiation_undefined_member_class) + << Record->getDeclName() << Record->getDeclContext(); + Diag(Pattern->getLocation(), diag::note_forward_declaration) + << Pattern; + return true; + } else if (InstantiateClass(TemplateLoc, Record, Def, + getTemplateInstantiationArgs(Record), + TSK)) return true; } else // Instantiate all of the members of the class. InstantiateClassMembers(TemplateLoc, Record, diff --git a/test/CXX/temp/temp.spec/temp.explicit/p3.cpp b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp new file mode 100644 index 0000000000..2bd781bbed --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p3.cpp @@ -0,0 +1,55 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// A declaration of a function template shall be in scope at the point of the +// explicit instantiation of the function template. +template<typename T> void f0(T) { } +template void f0(int); // okay + +// A definition of the class or class template containing a member function +// template shall be in scope at the point of the explicit instantiation of +// the member function template. +struct X0; // expected-note 2{{forward declaration}} +template<typename> struct X1; // expected-note 2{{declared here}} \ + // expected-note 3{{forward declaration}} + +// FIXME: Repeated diagnostics here! +template void X0::f0<int>(int); // expected-error 2{{incomplete type}} \ + // expected-error{{invalid token after}} +template void X1<int>::f0<int>(int); // expected-error{{implicit instantiation of undefined template}} \ + // expected-error{{incomplete type}} \\ + // expected-error{{invalid token}} + +// A definition of a class template or class member template shall be in scope +// at the point of the explicit instantiation of the class template or class +// member template. +template struct X1<float>; // expected-error{{explicit instantiation of undefined template}} + +template<typename T> +struct X2 { // expected-note 4{{refers here}} + template<typename U> + struct Inner; // expected-note{{declared here}} + + struct InnerClass; // expected-note{{forward declaration}} +}; + +template struct X2<int>::Inner<float>; // expected-error{{explicit instantiation of undefined template}} + +// A definition of a class template shall be in scope at the point of an +// explicit instantiation of a member function or a static data member of the +// class template. +template void X1<int>::f1(int); // expected-error{{incomplete type}} \ + // expected-error{{does not refer}} + +template int X1<int>::member; // expected-error{{incomplete type}} \ + // expected-error{{does not refer}} + +// A definition of a member class of a class template shall be in scope at the +// point of an explicit instantiation of the member class. +template struct X2<float>::InnerClass; // expected-error{{undefined member}} + +// If the declaration of the explicit instantiation names an implicitly-declared +// special member function (Clause 12), the program is ill-formed. +template X2<int>::X2(); // expected-error{{not an instantiation}} +template X2<int>::X2(const X2&); // expected-error{{not an instantiation}} +template X2<int>::~X2(); // expected-error{{not an instantiation}} +template X2<int> &X2<int>::operator=(const X2<int>&); // expected-error{{not an instantiation}} |