<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">Approved.<div><br><div><div>On Apr 18, 2012, at 6:25 PM, Richard Smith wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite">This fixes release blocker PR12586. Requesting branch merge approval! :)<br><br><div class="gmail_quote">On Wed, Apr 18, 2012 at 5:08 PM, Richard Smith <span dir="ltr"><<a href="mailto:richard-llvm@metafoo.co.uk">richard-llvm@metafoo.co.uk</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Wed Apr 18 19:08:28 2012<br>
New Revision: 155076<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=155076&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=155076&view=rev</a><br>
Log:<br>
PR 12586: Fix assert while running libc++ testsuite: deal with exception<br>
specifications on member function templates of class templates and other such<br>
nested beasties. Store the function template from which we are to instantiate<br>
an exception specification rather than trying to deduce it. Plus some<br>
additional test cases.<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/AST/Type.h<br>
    cfe/trunk/lib/AST/ASTContext.cpp<br>
    cfe/trunk/lib/AST/Type.cpp<br>
    cfe/trunk/lib/Sema/SemaExpr.cpp<br>
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
    cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp<br>
    cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/Type.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=155076&r1=155075&r2=155076&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=155076&r1=155075&r2=155076&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/include/clang/AST/Type.h (original)<br>
+++ cfe/trunk/include/clang/AST/Type.h Wed Apr 18 19:08:28 2012<br>
@@ -2701,7 +2701,8 @@<br>
     ExtProtoInfo() :<br>
       Variadic(false), HasTrailingReturn(false), TypeQuals(0),<br>
       ExceptionSpecType(EST_None), RefQualifier(RQ_None),<br>
-      NumExceptions(0), Exceptions(0), NoexceptExpr(0), ExceptionSpecDecl(0),<br>
+      NumExceptions(0), Exceptions(0), NoexceptExpr(0),<br>
+      ExceptionSpecDecl(0), ExceptionSpecTemplate(0),<br>
       ConsumedArguments(0) {}<br>
<br>
     FunctionType::ExtInfo ExtInfo;<br>
@@ -2714,6 +2715,7 @@<br>
     const QualType *Exceptions;<br>
     Expr *NoexceptExpr;<br>
     FunctionDecl *ExceptionSpecDecl;<br>
+    FunctionDecl *ExceptionSpecTemplate;<br>
     const bool *ConsumedArguments;<br>
   };<br>
<br>
@@ -2759,9 +2761,10 @@<br>
   // NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing<br>
   // to the expression in the noexcept() specifier.<br>
<br>
-  // ExceptionSpecDecl - Instead of Exceptions, there may be a single<br>
-  // FunctionDecl* pointing to the function which should be used to resolve<br>
-  // this function type's exception specification.<br>
+  // ExceptionSpecDecl, ExceptionSpecTemplate - Instead of Exceptions, there may<br>
+  // be a pair of FunctionDecl* pointing to the function which should be used to<br>
+  // instantiate this function type's exception specification, and the function<br>
+  // from which it should be instantiated.<br>
<br>
   // ConsumedArgs - A variable size array, following Exceptions<br>
   // and of length NumArgs, holding flags indicating which arguments<br>
@@ -2804,6 +2807,7 @@<br>
       EPI.NoexceptExpr = getNoexceptExpr();<br>
     } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {<br>
       EPI.ExceptionSpecDecl = getExceptionSpecDecl();<br>
+      EPI.ExceptionSpecTemplate = getExceptionSpecTemplate();<br>
     }<br>
     if (hasAnyConsumedArgs())<br>
       EPI.ConsumedArguments = getConsumedArgsBuffer();<br>
@@ -2847,10 +2851,22 @@<br>
     // NoexceptExpr sits where the arguments end.<br>
     return *reinterpret_cast<Expr *const *>(arg_type_end());<br>
   }<br>
+  /// \brief If this function type has an uninstantiated exception<br>
+  /// specification, this is the function whose exception specification<br>
+  /// is represented by this type.<br>
   FunctionDecl *getExceptionSpecDecl() const {<br>
     if (getExceptionSpecType() != EST_Uninstantiated)<br>
       return 0;<br>
-    return *reinterpret_cast<FunctionDecl * const *>(arg_type_end());<br>
+    return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[0];<br>
+  }<br>
+  /// \brief If this function type has an uninstantiated exception<br>
+  /// specification, this is the function whose exception specification<br>
+  /// should be instantiated to find the exception specification for<br>
+  /// this type.<br>
+  FunctionDecl *getExceptionSpecTemplate() const {<br>
+    if (getExceptionSpecType() != EST_Uninstantiated)<br>
+      return 0;<br>
+    return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[1];<br>
   }<br>
   bool isNothrow(ASTContext &Ctx) const {<br>
     ExceptionSpecificationType EST = getExceptionSpecType();<br>
<br>
Modified: cfe/trunk/lib/AST/ASTContext.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=155076&r1=155075&r2=155076&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=155076&r1=155075&r2=155076&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/AST/ASTContext.cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Apr 18 19:08:28 2012<br>
@@ -2195,7 +2195,7 @@<br>
   else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {<br>
     Size += sizeof(Expr*);<br>
   } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {<br>
-    Size += sizeof(FunctionDecl*);<br>
+    Size += 2 * sizeof(FunctionDecl*);<br>
   }<br>
   if (EPI.ConsumedArguments)<br>
     Size += NumArgs * sizeof(bool);<br>
<br>
Modified: cfe/trunk/lib/AST/Type.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=155076&r1=155075&r2=155076&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=155076&r1=155075&r2=155076&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/AST/Type.cpp (original)<br>
+++ cfe/trunk/lib/AST/Type.cpp Wed Apr 18 19:08:28 2012<br>
@@ -1550,7 +1550,8 @@<br>
     // Store the function decl from which we will resolve our<br>
     // exception specification.<br>
     FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);<br>
-    *slot = epi.ExceptionSpecDecl;<br>
+    slot[0] = epi.ExceptionSpecDecl;<br>
+    slot[1] = epi.ExceptionSpecTemplate;<br>
     // This exception specification doesn't make the type dependent, because<br>
     // it's not instantiated as part of instantiating the type.<br>
   }<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=155076&r1=155075&r2=155076&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=155076&r1=155075&r2=155076&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Apr 18 19:08:28 2012<br>
@@ -9776,9 +9776,8 @@<br>
<br>
   // Instantiate the exception specification for any function which is<br>
   // used: CodeGen will need it.<br>
-  if (Func->getTemplateInstantiationPattern() &&<br>
-      Func->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()<br>
-        == EST_Uninstantiated)<br>
+  const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();<br>
+  if (FPT && FPT->getExceptionSpecType() == EST_Uninstantiated)<br>
     InstantiateExceptionSpec(Loc, Func);<br>
<br>
   // Implicit instantiation of function templates and member functions of<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=155076&r1=155075&r2=155076&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=155076&r1=155075&r2=155076&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Apr 18 19:08:28 2012<br>
@@ -2251,6 +2251,8 @@<br>
 static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,<br>
                                      const FunctionProtoType *Proto,<br>
                            const MultiLevelTemplateArgumentList &TemplateArgs) {<br>
+  assert(Proto->getExceptionSpecType() != EST_Uninstantiated);<br>
+<br>
   // C++11 [expr.prim.general]p3:<br>
   //   If a declaration declares a member function or member function<br>
   //   template of a class X, the expression this is a prvalue of type<br>
@@ -2377,20 +2379,8 @@<br>
<br>
 void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,<br>
                                     FunctionDecl *Decl) {<br>
-  // Find the template declaration which contains the exception specification.<br>
-  // Per [except.spec]p4, prefer the exception spec on the primary template<br>
-  // if this is an explicit instantiation.<br>
-  FunctionDecl *Tmpl = 0;<br>
-  if (Decl->getPrimaryTemplate())<br>
-    Tmpl = Decl->getPrimaryTemplate()->getTemplatedDecl();<br>
-  else if (FunctionDecl *MemTmpl = Decl->getInstantiatedFromMemberFunction())<br>
-    Tmpl = MemTmpl;<br>
-  else<br>
-    Tmpl = Decl->getTemplateInstantiationPattern();<br>
-  assert(Tmpl && "can't instantiate non-template");<br>
-<br>
-  if (Decl->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()<br>
-        != EST_Uninstantiated)<br>
+  const FunctionProtoType *Proto = Decl->getType()->castAs<FunctionProtoType>();<br>
+  if (Proto->getExceptionSpecType() != EST_Uninstantiated)<br>
     return;<br>
<br>
   InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,<br>
@@ -2406,10 +2396,12 @@<br>
   MultiLevelTemplateArgumentList TemplateArgs =<br>
     getTemplateInstantiationArgs(Decl, 0, /*RelativeToPrimary*/true);<br>
<br>
-  addInstantiatedParametersToScope(*this, Decl, Tmpl, Scope, TemplateArgs);<br>
+  FunctionDecl *Template = Proto->getExceptionSpecTemplate();<br>
+  addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs);<br>
<br>
-  const FunctionProtoType *Proto = Tmpl->getType()->castAs<FunctionProtoType>();<br>
-  ::InstantiateExceptionSpec(*this, Decl, Proto, TemplateArgs);<br>
+  ::InstantiateExceptionSpec(*this, Decl,<br>
+                             Template->getType()->castAs<FunctionProtoType>(),<br>
+                             TemplateArgs);<br>
 }<br>
<br>
 /// \brief Initializes the common fields of an instantiation function<br>
@@ -2457,6 +2449,10 @@<br>
         EPI.ExceptionSpecType != EST_None &&<br>
         EPI.ExceptionSpecType != EST_DynamicNone &&<br>
         EPI.ExceptionSpecType != EST_BasicNoexcept) {<br>
+      FunctionDecl *ExceptionSpecTemplate = Tmpl;<br>
+      if (EPI.ExceptionSpecType == EST_Uninstantiated)<br>
+        ExceptionSpecTemplate = EPI.ExceptionSpecTemplate;<br>
+<br>
       // Mark the function has having an uninstantiated exception specification.<br>
       const FunctionProtoType *NewProto<br>
         = New->getType()->getAs<FunctionProtoType>();<br>
@@ -2464,6 +2460,7 @@<br>
       EPI = NewProto->getExtProtoInfo();<br>
       EPI.ExceptionSpecType = EST_Uninstantiated;<br>
       EPI.ExceptionSpecDecl = New;<br>
+      EPI.ExceptionSpecTemplate = ExceptionSpecTemplate;<br>
       New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),<br>
                                                    NewProto->arg_type_begin(),<br>
                                                    NewProto->getNumArgs(),<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp?rev=155076&r1=155075&r2=155076&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp?rev=155076&r1=155075&r2=155076&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp Wed Apr 18 19:08:28 2012<br>
@@ -3,9 +3,11 @@<br>
 void h();<br>
<br>
 template<typename T> void f() noexcept(sizeof(T) == 4) { h(); }<br>
+template<typename T> void g() noexcept(sizeof(T) == 4);<br>
<br>
 template<typename T> struct S {<br>
   static void f() noexcept(sizeof(T) == 4) { h(); }<br>
+  static void g() noexcept(sizeof(T) == 4);<br>
 };<br>
<br>
 // CHECK: define {{.*}} @_Z1fIsEvv() {<br>
@@ -30,7 +32,7 @@<br>
 // CHECK: define {{.*}} @_ZN1SIA2_DsE1fEv() nounwind<br>
 template void S<char16_t[2]>::f();<br>
<br>
-void g() {<br>
+void h() {<br>
   // CHECK: define {{.*}} @_Z1fIiEvv() nounwind {<br>
   f<int>();<br>
   // CHECK: define {{.*}} @_Z1fIA2_iEvv() {<br>
@@ -64,3 +66,55 @@<br>
   // CHECK-NOT: nounwind<br>
   (void)&S<char>::f;<br>
 }<br>
+<br>
+// CHECK: define {{.*}} @_Z1iv<br>
+void i() {<br>
+  // CHECK: declare {{.*}} @_Z1gIiEvv() nounwind<br>
+  g<int>();<br>
+  // CHECK: declare {{.*}} @_Z1gIA2_iEvv()<br>
+  // CHECK-NOT: nounwind<br>
+  g<int[2]>();<br>
+<br>
+  // CHECK: declare {{.*}} @_ZN1SIiE1gEv() nounwind<br>
+  S<int>::g();<br>
+  // CHECK: declare {{.*}} @_ZN1SIA2_iE1gEv()<br>
+  // CHECK-NOT: nounwind<br>
+  S<int[2]>::g();<br>
+<br>
+  // CHECK: declare {{.*}} @_Z1gIfEvv() nounwind<br>
+  void (*g1)() = &g<float>;<br>
+  // CHECK: declare {{.*}} @_Z1gIdEvv()<br>
+  // CHECK-NOT: nounwind<br>
+  void (*g2)() = &g<double>;<br>
+<br>
+  // CHECK: declare {{.*}} @_ZN1SIfE1gEv() nounwind<br>
+  void (*g3)() = &S<float>::g;<br>
+  // CHECK: declare {{.*}} @_ZN1SIdE1gEv()<br>
+  // CHECK-NOT: nounwind<br>
+  void (*g4)() = &S<double>::g;<br>
+<br>
+  // CHECK: declare {{.*}} @_Z1gIA4_cEvv() nounwind<br>
+  (void)&g<char[4]>;<br>
+  // CHECK: declare {{.*}} @_Z1gIcEvv()<br>
+  // CHECK-NOT: nounwind<br>
+  (void)&g<char>;<br>
+<br>
+  // CHECK: declare {{.*}} @_ZN1SIA4_cE1gEv() nounwind<br>
+  (void)&S<char[4]>::g;<br>
+  // CHECK: declare {{.*}} @_ZN1SIcE1gEv()<br>
+  // CHECK-NOT: nounwind<br>
+  (void)&S<char>::g;<br>
+}<br>
+<br>
+template<typename T> struct Nested {<br>
+  template<bool b, typename U> void f() noexcept(sizeof(T) == sizeof(U));<br>
+};<br>
+<br>
+// CHECK: define {{.*}} @_Z1jv<br>
+void j() {<br>
+  // CHECK: declare {{.*}} @_ZN6NestedIiE1fILb1EcEEvv(<br>
+  // CHECK-NOT: nounwind<br>
+  Nested<int>().f<true, char>();<br>
+  // CHECK: declare {{.*}} @_ZN6NestedIlE1fILb0ElEEvv({{.*}}) nounwind<br>
+  Nested<long>().f<false, long>();<br>
+}<br>
<br>
Modified: cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp?rev=155076&r1=155075&r2=155076&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp?rev=155076&r1=155075&r2=155076&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp (original)<br>
+++ cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp Wed Apr 18 19:08:28 2012<br>
@@ -1,4 +1,4 @@<br>
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 %s<br>
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 -fcxx-exceptions -fexceptions %s<br>
<br>
 // DR1330: an exception specification for a function template is only<br>
 // instantiated when it is needed.<br>
@@ -31,7 +31,7 @@<br>
 decltype(&S<0>::recurse) pFn = 0; // ok, exception spec not needed<br>
<br>
 template<> struct S<10> {};<br>
-void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of exception spec}}<br>
+void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of exception spec}} expected-error {{not superset}}<br>
<br>
<br>
 template<typename T> T go(T a) noexcept(noexcept(go(a))); // \<br>
@@ -118,3 +118,16 @@<br>
     f2(0); // expected-error {{ambiguous}}<br>
   }<br>
 }<br>
+<br>
+struct Exc1 { char c[4]; };<br>
+struct Exc2 { double x, y, z; };<br>
+struct Base {<br>
+  virtual void f() noexcept; // expected-note {{overridden}}<br>
+};<br>
+template<typename T> struct Derived : Base {<br>
+  void f() noexcept (sizeof(T) == 4); // expected-error {{is more lax}}<br>
+  void g() noexcept (T::error);<br>
+};<br>
+<br>
+Derived<Exc1> d1; // ok<br>
+Derived<Exc2> d2; // expected-note {{in instantiation of}}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br>
</blockquote></div><br></div></body></html>