Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -3651,6 +3651,11 @@ "of %select{explicit instantiation|explicit specialization|" "partial specialization|redeclaration}0 of %1 does not match" " expected type %3">; +def err_mismatched_exception_spec_explicit_instantiation : Error< + "exception specification in explicit instantiation does not match deduced one">; +def ext_mismatched_exception_spec_explicit_instantiation : ExtWarn< + "exception specification in explicit instantiation does not match deduced one">, + InGroup; // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7628,6 +7628,33 @@ // Ignore access control bits, we don't need them for redeclaration checking. FunctionDecl *Specialization = cast(*Result); + // C++11 [except.spec]p4 + // In an explicit instantiation an exception-specification may be specified, + // but is not required. + // If an exception-specification is specified in an explicit instantiation + // directive, it shall be compatible with the exception-specifications of + // other declarations of that function. + if (D.isFunctionDeclarator() && + D.getFunctionTypeInfo().getExceptionSpecType() != EST_None) { + auto TSI = GetTypeForDeclarator(D, S); + unsigned DiagID = + diag::err_mismatched_exception_spec_explicit_instantiation; + if (getLangOpts().MicrosoftExt) + DiagID = diag::ext_mismatched_exception_spec_explicit_instantiation; + bool Result = + TSI && !TSI->getType().isNull() && + CheckEquivalentExceptionSpec( + PDiag(DiagID) << Specialization->getType(), + PDiag(diag::note_explicit_instantiation_here), + Specialization->getType()->getAs(), + Specialization->getLocation(), + TSI->getType()->getAs(), D.getLocStart()); + // In Microsoft mode, mismatching exception specifications just cause a + // warning. + if (!getLangOpts().MicrosoftExt && Result) + return true; + } + if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) { Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_member_function_not_instantiated) Index: test/SemaTemplate/explicit-instantiation-cxx11.cpp =================================================================== --- test/SemaTemplate/explicit-instantiation-cxx11.cpp +++ test/SemaTemplate/explicit-instantiation-cxx11.cpp @@ -0,0 +1,161 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fcxx-exceptions -std=c++11 %s + +template void *; // expected-error{{expected unqualified-id}} + +template typedef void f0; // expected-error{{explicit instantiation of typedef}} + +int v0; // expected-note{{refers here}} +template int v0; // expected-error{{does not refer}} + +template +struct X0 { + static T value; + + T f0(T x) { + return x + 1; // expected-error{{invalid operands}} + } + T* f0(T*, T*) { return T(); } // expected-error{{cannot initialize return object of type 'int *' with an rvalue of type 'int'}} + + template T f0(T, U) { return T(); } // expected-note-re {{candidate template ignored: could not match 'int (int, U){{( __attribute__\(\(thiscall\)\))?}}' against 'int (int){{( __attribute__\(\(thiscall\)\))?}} const'}} \ + // expected-note {{candidate template ignored: could not match 'int' against 'int *'}} +}; + +template +T X0::value; // expected-error{{no matching constructor}} + +template int X0::value; + +struct NotDefaultConstructible { // expected-note {{candidate constructor (the implicit move constructor)}} expected-note {{candidate constructor (the implicit copy constructor)}} + NotDefaultConstructible(int); // expected-note{{candidate constructor}} +}; + +template NotDefaultConstructible X0::value; // expected-note{{instantiation}} + +template int X0::f0(int); +template int* X0::f0(int*, int*); // expected-note{{in instantiation of member function 'X0::f0' requested here}} +template int X0::f0(int, float); + +template int X0::f0(int) const; // expected-error{{does not refer}} +template int* X0::f0(int*, float*); // expected-error{{does not refer}} + +struct X1 { }; +typedef int X1::*MemPtr; + +template MemPtr X0::f0(MemPtr); // expected-note{{requested here}} + +struct X2 { + int f0(int); // expected-note{{refers here}} + + template T f1(T) { return T(); } + template T* f1(T*) { return 0; } + + template void f2(T, U*) { } // expected-note{{candidate}} + template void f2(T*, U) { } // expected-note{{candidate}} +}; + +template int X2::f0(int); // expected-error{{not an instantiation}} + +template int *X2::f1(int *); // okay + +template void X2::f2(int *, int *); // expected-error{{ambiguous}} + +template +void print_type() {} // expected-note {{candidate template ignored: could not match 'void ()' against 'void (float *)'}} + +template void print_type(); +template void print_type(); + +template +void print_type(T *) {} // expected-note {{candidate template ignored: could not match 'void (int *)' against 'void (float *)'}} + +template void print_type(int*); +template void print_type(float*); // expected-error{{does not refer}} + +void print_type(double*); +template void print_type(double*); + +// PR5069 +template void foo0 (int (&)[I + 1]) { } +template void foo0<2> (int (&)[3]); + +namespace explicit_instantiation_after_implicit_instantiation { + template struct X0 { static int x; }; + template int X0::x; + void test1() { (void)&X0<1>::x; } + template struct X0<1>; +} + +template struct X3 { }; +inline template struct X3; // expected-warning{{ignoring 'inline' keyword on explicit template instantiation}} +static template struct X3; // expected-warning{{ignoring 'static' keyword on explicit template instantiation}} + +namespace PR7622 { + template + struct basic_streambuf; + + template + struct basic_streambuf{friend bob<>()}; // expected-error{{unknown type name 'bob'}} \ + // expected-error{{expected member name or ';' after declaration specifiers}} + template struct basic_streambuf; +} + +// Test that we do not crash. +class TC1 { + class TC2 { + template // FIXME: error here. + void foo() { } + }; +}; + +namespace PR8020 { + template struct X { X() {} }; + template<> struct X { X(); }; + template X::X() {} // expected-error{{function cannot be defined in an explicit instantiation}} +} + +namespace PR10086 { + template void foobar(int i) {} // expected-error{{function cannot be defined in an explicit instantiation}} + int func() { + foobar(5); + } +} + +namespace undefined_static_data_member { + template struct A { + static int a; // expected-note {{here}} + template static int b; // expected-note {{here}} expected-warning {{extension}} + }; + struct B { + template static int c; // expected-note {{here}} expected-warning {{extension}} + }; + + template int A::a; // expected-error {{explicit instantiation of undefined static data member 'a' of class template 'undefined_static_data_member::A'}} + template int A::b; // expected-error {{explicit instantiation of undefined variable template 'undefined_static_data_member::A::b'}} + template int B::c; // expected-error {{explicit instantiation of undefined variable template 'undefined_static_data_member::B::c'}} + + + template struct C { + static int a; + template static int b; // expected-warning {{extension}} + }; + struct D { + template static int c; // expected-warning {{extension}} + }; + template int C::a; + template template int C::b; // expected-warning {{extension}} + template int D::c; // expected-warning {{extension}} + + template int C::a; + template int C::b; + template int D::c; +} + +// expected-note@+1 3 {{explicit instantiation refers here}} +template void Foo(T i) throw(T) { throw i; } +// expected-error@+1 {{exception specification in explicit instantiation does not match deduced one}} +template void Foo(int a) throw(char); +template void Foo(float a); +// expected-error@+1 {{exception specification in explicit instantiation does not match deduced one}} +template void Foo(double a) noexcept; +// expected-error@+1 {{exception specification in explicit instantiation does not match deduced one}} +template void Foo(long a) throw(long, char); Index: test/SemaTemplate/explicit-instantiation.cpp =================================================================== --- test/SemaTemplate/explicit-instantiation.cpp +++ test/SemaTemplate/explicit-instantiation.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fcxx-exceptions %s template void *; // expected-error{{expected unqualified-id}} @@ -149,3 +149,12 @@ template int C::b; template int D::c; } + +// expected-note@+1 2 {{explicit instantiation refers here}} +template void Foo(T i) throw(T) { throw i; } +// expected-error@+1 {{exception specification in explicit instantiation does not match deduced one}} +template void Foo(int a) throw(char); +// expected-error@+1 {{exception specification in explicit instantiation does not match deduced one}} +template void Foo(double a) throw(); +template void Foo(float a); +