PR 12586: Fix assert while running libc++ testsuite: deal with exception
specifications on member function templates of class templates and other such
nested beasties. Store the function template from which we are to instantiate
an exception specification rather than trying to deduce it. Plus some
additional test cases.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155076 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 4d312f8..c7bd99c 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2251,6 +2251,8 @@
 static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
                                      const FunctionProtoType *Proto,
                            const MultiLevelTemplateArgumentList &TemplateArgs) {
+  assert(Proto->getExceptionSpecType() != EST_Uninstantiated);
+
   // C++11 [expr.prim.general]p3:
   //   If a declaration declares a member function or member function 
   //   template of a class X, the expression this is a prvalue of type 
@@ -2377,20 +2379,8 @@
 
 void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
                                     FunctionDecl *Decl) {
-  // Find the template declaration which contains the exception specification.
-  // Per [except.spec]p4, prefer the exception spec on the primary template
-  // if this is an explicit instantiation.
-  FunctionDecl *Tmpl = 0;
-  if (Decl->getPrimaryTemplate())
-    Tmpl = Decl->getPrimaryTemplate()->getTemplatedDecl();
-  else if (FunctionDecl *MemTmpl = Decl->getInstantiatedFromMemberFunction())
-    Tmpl = MemTmpl;
-  else
-    Tmpl = Decl->getTemplateInstantiationPattern();
-  assert(Tmpl && "can't instantiate non-template");
-
-  if (Decl->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()
-        != EST_Uninstantiated)
+  const FunctionProtoType *Proto = Decl->getType()->castAs<FunctionProtoType>();
+  if (Proto->getExceptionSpecType() != EST_Uninstantiated)
     return;
 
   InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,
@@ -2406,10 +2396,12 @@
   MultiLevelTemplateArgumentList TemplateArgs =
     getTemplateInstantiationArgs(Decl, 0, /*RelativeToPrimary*/true);
 
-  addInstantiatedParametersToScope(*this, Decl, Tmpl, Scope, TemplateArgs);
+  FunctionDecl *Template = Proto->getExceptionSpecTemplate();
+  addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs);
 
-  const FunctionProtoType *Proto = Tmpl->getType()->castAs<FunctionProtoType>();
-  ::InstantiateExceptionSpec(*this, Decl, Proto, TemplateArgs);
+  ::InstantiateExceptionSpec(*this, Decl,
+                             Template->getType()->castAs<FunctionProtoType>(),
+                             TemplateArgs);
 }
 
 /// \brief Initializes the common fields of an instantiation function
@@ -2457,6 +2449,10 @@
         EPI.ExceptionSpecType != EST_None &&
         EPI.ExceptionSpecType != EST_DynamicNone &&
         EPI.ExceptionSpecType != EST_BasicNoexcept) {
+      FunctionDecl *ExceptionSpecTemplate = Tmpl;
+      if (EPI.ExceptionSpecType == EST_Uninstantiated)
+        ExceptionSpecTemplate = EPI.ExceptionSpecTemplate;
+
       // Mark the function has having an uninstantiated exception specification.
       const FunctionProtoType *NewProto
         = New->getType()->getAs<FunctionProtoType>();
@@ -2464,6 +2460,7 @@
       EPI = NewProto->getExtProtoInfo();
       EPI.ExceptionSpecType = EST_Uninstantiated;
       EPI.ExceptionSpecDecl = New;
+      EPI.ExceptionSpecTemplate = ExceptionSpecTemplate;
       New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
                                                    NewProto->arg_type_begin(),
                                                    NewProto->getNumArgs(),