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>