Hi rsmith,
According to C++ standard 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. This patch
adds checks for this.
http://reviews.llvm.org/D5822
Files:
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaTemplate.cpp
test/SemaTemplate/explicit-instantiation-cxx11.cpp
test/SemaTemplate/explicit-instantiation.cpp
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<typename T>
+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 <typename U> 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<typename T>
+T X0<T>::value; // expected-error{{no matching constructor}}
+
+template int X0<int>::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<NotDefaultConstructible>::value; // expected-note{{instantiation}}
+
+template int X0<int>::f0(int);
+template int* X0<int>::f0(int*, int*); // expected-note{{in instantiation of member function 'X0<int>::f0' requested here}}
+template int X0<int>::f0(int, float);
+
+template int X0<int>::f0(int) const; // expected-error{{does not refer}}
+template int* X0<int>::f0(int*, float*); // expected-error{{does not refer}}
+
+struct X1 { };
+typedef int X1::*MemPtr;
+
+template MemPtr X0<MemPtr>::f0(MemPtr); // expected-note{{requested here}}
+
+struct X2 {
+ int f0(int); // expected-note{{refers here}}
+
+ template<typename T> T f1(T) { return T(); }
+ template<typename T> T* f1(T*) { return 0; }
+
+ template<typename T, typename U> void f2(T, U*) { } // expected-note{{candidate}}
+ template<typename T, typename U> 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 <typename T>
+void print_type() {} // expected-note {{candidate template ignored: could not match 'void ()' against 'void (float *)'}}
+
+template void print_type<int>();
+template void print_type<float>();
+
+template <typename T>
+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<int>(float*); // expected-error{{does not refer}}
+
+void print_type(double*);
+template void print_type<double>(double*);
+
+// PR5069
+template<int I> void foo0 (int (&)[I + 1]) { }
+template void foo0<2> (int (&)[3]);
+
+namespace explicit_instantiation_after_implicit_instantiation {
+ template <int I> struct X0 { static int x; };
+ template <int I> int X0<I>::x;
+ void test1() { (void)&X0<1>::x; }
+ template struct X0<1>;
+}
+
+template<typename> struct X3 { };
+inline template struct X3<int>; // expected-warning{{ignoring 'inline' keyword on explicit template instantiation}}
+static template struct X3<float>; // expected-warning{{ignoring 'static' keyword on explicit template instantiation}}
+
+namespace PR7622 {
+ template<typename,typename=int>
+ struct basic_streambuf;
+
+ template<typename,typename>
+ struct basic_streambuf{friend bob<>()}; // expected-error{{unknown type name 'bob'}} \
+ // expected-error{{expected member name or ';' after declaration specifiers}}
+ template struct basic_streambuf<int>;
+}
+
+// Test that we do not crash.
+class TC1 {
+ class TC2 {
+ template // FIXME: error here.
+ void foo() { }
+ };
+};
+
+namespace PR8020 {
+ template <typename T> struct X { X() {} };
+ template<> struct X<int> { X(); };
+ template X<int>::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<typename T> struct A {
+ static int a; // expected-note {{here}}
+ template<typename U> static int b; // expected-note {{here}} expected-warning {{extension}}
+ };
+ struct B {
+ template<typename U> static int c; // expected-note {{here}} expected-warning {{extension}}
+ };
+
+ template int A<int>::a; // expected-error {{explicit instantiation of undefined static data member 'a' of class template 'undefined_static_data_member::A<int>'}}
+ template int A<int>::b<int>; // expected-error {{explicit instantiation of undefined variable template 'undefined_static_data_member::A<int>::b<int>'}}
+ template int B::c<int>; // expected-error {{explicit instantiation of undefined variable template 'undefined_static_data_member::B::c<int>'}}
+
+
+ template<typename T> struct C {
+ static int a;
+ template<typename U> static int b; // expected-warning {{extension}}
+ };
+ struct D {
+ template<typename U> static int c; // expected-warning {{extension}}
+ };
+ template<typename T> int C<T>::a;
+ template<typename T> template<typename U> int C<T>::b; // expected-warning {{extension}}
+ template<typename U> int D::c; // expected-warning {{extension}}
+
+ template int C<int>::a;
+ template int C<int>::b<int>;
+ template int D::c<int>;
+}
+
+// expected-note@+1 3 {{explicit instantiation refers here}}
+template <class T> 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<int>::b<int>;
template int D::c<int>;
}
+
+// expected-note@+1 2 {{explicit instantiation refers here}}
+template <class T> 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);
+
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<Microsoft>;
// 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<FunctionDecl>(*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<FunctionProtoType>(),
+ Specialization->getLocation(),
+ TSI->getType()->getAs<FunctionProtoType>(), 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)
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits