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

Reply via email to