From f945e9022eef9de82804907e77cc29ccc9e5be1a Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev@hotmail.com>
Date: Thu, 6 Nov 2014 10:10:50 +0000
Subject: [PATCH] Fix for exception specification mismatch in explicit
 instantiation. 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. Differential Revision:
 http://reviews.llvm.org/D5822

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@221448 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Basic/DiagnosticSemaKinds.td   |  5 +++++
 lib/Sema/SemaTemplate.cpp                    | 23 ++++++++++++++++++++
 test/SemaTemplate/explicit-instantiation.cpp | 23 ++++++++++++++++----
 3 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 6503aef324f..9f561164c5d 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3658,6 +3658,11 @@ def err_invalid_var_template_spec_type : Error<"type %2 "
   "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 instantiated one">;
+def ext_mismatched_exception_spec_explicit_instantiation : ExtWarn<
+  "exception specification in explicit instantiation does not match instantiated one">,
+  InGroup<Microsoft>;
   
 // 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 57d1ab8d75b..1bddfe21846 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -7627,6 +7627,29 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
   // 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 (auto *FPT = R->getAs<FunctionProtoType>())
+    if (FPT->hasExceptionSpec()) {
+      unsigned DiagID =
+          diag::err_mismatched_exception_spec_explicit_instantiation;
+      if (getLangOpts().MicrosoftExt)
+        DiagID = diag::ext_mismatched_exception_spec_explicit_instantiation;
+      bool Result = CheckEquivalentExceptionSpec(
+          PDiag(DiagID) << Specialization->getType(),
+          PDiag(diag::note_explicit_instantiation_here),
+          Specialization->getType()->getAs<FunctionProtoType>(),
+          Specialization->getLocation(), FPT, 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)
diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp
index c28c5d18315..71121ad2b37 100644
--- a/test/SemaTemplate/explicit-instantiation.cpp
+++ b/test/SemaTemplate/explicit-instantiation.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fcxx-exceptions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fcxx-exceptions -std=c++11 %s
 
 template void *; // expected-error{{expected unqualified-id}}
 
@@ -13,8 +14,8 @@ struct X0 {
   
   T f0(T x) {
     return x + 1;  // expected-error{{invalid operands}}
-  } 
-  T* f0(T*, T*) { return T(); } // expected-warning{{expression which evaluates to zero treated as a null pointer constant of type 'int *'}}
+  }
+  T *f0(T *, T *) { return T(); } // expected-warning 0-1 {{expression which evaluates to zero treated as a null pointer constant of type 'int *'}} expected-error 0-1 {{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 *'}}
@@ -25,7 +26,7 @@ T X0<T>::value; // expected-error{{no matching constructor}}
 
 template int X0<int>::value;
 
-struct NotDefaultConstructible { // expected-note{{candidate constructor (the implicit copy constructor)}}
+struct NotDefaultConstructible { // expected-note{{candidate constructor (the implicit copy constructor)}} expected-note 0-1 {{candidate constructor (the implicit move constructor)}}
   NotDefaultConstructible(int); // expected-note{{candidate constructor}}
 };
 
@@ -149,3 +150,17 @@ namespace undefined_static_data_member {
   template int C<int>::b<int>;
   template int D::c<int>;
 }
+
+// expected-note@+1 3-4 {{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 instantiated one}}
+template void Foo(int a) throw(char);
+// expected-error@+1 {{exception specification in explicit instantiation does not match instantiated one}}
+template void Foo(double a) throw();
+// expected-error@+1 1 {{exception specification in explicit instantiation does not match instantiated one}}
+template void Foo(long a) throw(long, char);
+template void Foo(float a);
+#if __cplusplus >= 201103L
+// expected-error@+1 0-1 {{exception specification in explicit instantiation does not match instantiated one}}
+template void Foo(double a) noexcept;
+#endif
-- 
GitLab