diff options
author | John McCall <rjmccall@apple.com> | 2011-04-27 06:46:31 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-04-27 06:46:31 +0000 |
commit | 5476666d173861917bab2d35c5402ab4f9bf1672 (patch) | |
tree | 926344c53237dbb21486e828ec22d772a274f159 | |
parent | da6c89de486300c894a4178848ba02058377f0e9 (diff) | |
download | bcm5719-llvm-5476666d173861917bab2d35c5402ab4f9bf1672.tar.gz bcm5719-llvm-5476666d173861917bab2d35c5402ab4f9bf1672.zip |
Diagnose attempts to implicitly instantiate a template before it is
fully defined. Somehow this escaped notice for a very long time.
llvm-svn: 130298
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 13 | ||||
-rw-r--r-- | clang/test/CXX/class/class.mem/p2.cpp | 31 | ||||
-rw-r--r-- | clang/test/SemaCXX/PR9460.cpp | 6 | ||||
-rw-r--r-- | clang/test/SemaCXX/PR9461.cpp | 4 |
5 files changed, 50 insertions, 7 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f35d5c4b9bf..9a29ba2be09 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1863,6 +1863,9 @@ def err_template_recursion_depth_exceeded : Error< def note_template_recursion_depth : Note< "use -ftemplate-depth-N to increase recursive template instantiation depth">; +def err_template_instantiate_within_definition : Error< + "%select{implicit|explicit}0 instantiation of template %1 within its" + " own definition">; def err_template_instantiate_undefined : Error< "%select{implicit|explicit}0 instantiation of undefined template %1">; def err_implicit_instantiate_member_undefined : Error< diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index c951b2573a3..749c4a18a4e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1650,9 +1650,18 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *PatternDef = cast_or_null<CXXRecordDecl>(Pattern->getDefinition()); - if (!PatternDef) { - if (!Complain) { + if (!PatternDef || PatternDef->isBeingDefined()) { + if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) { // Say nothing + } else if (PatternDef) { + assert(PatternDef->isBeingDefined()); + Diag(PointOfInstantiation, + diag::err_template_instantiate_within_definition) + << (TSK != TSK_ImplicitInstantiation) + << Context.getTypeDeclType(Instantiation); + // Not much point in noting the template declaration here, since + // we're lexically inside it. + Instantiation->setInvalidDecl(); } else if (Pattern == Instantiation->getInstantiatedFromMemberClass()) { Diag(PointOfInstantiation, diag::err_implicit_instantiate_member_undefined) diff --git a/clang/test/CXX/class/class.mem/p2.cpp b/clang/test/CXX/class/class.mem/p2.cpp new file mode 100644 index 00000000000..09040d859c8 --- /dev/null +++ b/clang/test/CXX/class/class.mem/p2.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// C++11 [class.mem]p2: +// A class is considered a completely-defined object type (or +// complete type) at the closing } of the class-specifier. Within +// the class member-specification, the class is regarded as complete +// within function bodies, default arguments, +// exception-specifications, and brace-or-equal-initializers for +// non-static data members (including such things in nested classes). +// Otherwise it is regarded as incomplete within its own class +// member-specification. + +namespace test0 { + struct A { // expected-note {{definition of 'test0::A' is not complete until the closing '}'}} + A x; // expected-error {{field has incomplete type 'test0::A'}} + }; +} + +namespace test1 { + template <class T> struct A { + A<int> x; // expected-error {{implicit instantiation of template 'test1::A<int>' within its own definition}} + }; +} + +namespace test2 { + template <class T> struct A; + template <> struct A<int> {}; + template <class T> struct A { + A<int> x; + }; +} diff --git a/clang/test/SemaCXX/PR9460.cpp b/clang/test/SemaCXX/PR9460.cpp index be8dc6eb304..2cc435e495d 100644 --- a/clang/test/SemaCXX/PR9460.cpp +++ b/clang/test/SemaCXX/PR9460.cpp @@ -8,11 +8,11 @@ struct basic_string{ basic_string(aT*); }; -struct runtime_error{ -runtime_error( +struct runtime_error{ // expected-note {{candidate constructor}} + runtime_error( // expected-note {{candidate constructor}} basic_string<char> struct{ // expected-error {{cannot combine with previous 'type-name' declaration specifier}} a(){ // expected-error {{requires a type specifier}} -runtime_error(0); + runtime_error(0); // expected-error {{no matching conversion}} } } ); diff --git a/clang/test/SemaCXX/PR9461.cpp b/clang/test/SemaCXX/PR9461.cpp index e24bd4d35a8..ce17931324e 100644 --- a/clang/test/SemaCXX/PR9461.cpp +++ b/clang/test/SemaCXX/PR9461.cpp @@ -26,7 +26,7 @@ basic_string<_CharT,_Traits,_Alloc>::basic_string(const _CharT*,const _Alloc&) :us(_S_construct) {string a;} -struct runtime_error{runtime_error(string);}; +struct runtime_error{runtime_error(string);}; // expected-note 2 {{candidate constructor}} struct system_error:runtime_error{ // expected-note {{to match}} expected-note {{specified here}} -system_error():time_error("" // expected-error 4 {{expected}} expected-error {{initializer}} expected-note {{to match}} +system_error():time_error("" // expected-error 4 {{expected}} expected-error {{initializer}} expected-note {{to match}} expected-error {{no matching constructor}} |