[cfe-commits] r155076 - in /cfe/trunk: include/clang/AST/Type.h lib/AST/ASTContext.cpp lib/AST/Type.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CodeGenCXX/cxx11-exception-spec.cpp test/SemaTemplate/instantiate-exception-spec-cxx11.cpp

Richard Smith richard-llvm at metafoo.co.uk
Wed Apr 18 17:08:28 PDT 2012


Author: rsmith
Date: Wed Apr 18 19:08:28 2012
New Revision: 155076

URL: http://llvm.org/viewvc/llvm-project?rev=155076&view=rev
Log:
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.

Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp
    cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp

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

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

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

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

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=155076&r1=155075&r2=155076&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Apr 18 19:08:28 2012
@@ -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(),

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

Modified: cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp?rev=155076&r1=155075&r2=155076&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp Wed Apr 18 19:08:28 2012
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 -fcxx-exceptions -fexceptions %s
 
 // DR1330: an exception specification for a function template is only
 // instantiated when it is needed.
@@ -31,7 +31,7 @@
 decltype(&S<0>::recurse) pFn = 0; // ok, exception spec not needed
 
 template<> struct S<10> {};
-void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of exception spec}}
+void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of exception spec}} expected-error {{not superset}}
 
 
 template<typename T> T go(T a) noexcept(noexcept(go(a))); // \
@@ -118,3 +118,16 @@
     f2(0); // expected-error {{ambiguous}}
   }
 }
+
+struct Exc1 { char c[4]; };
+struct Exc2 { double x, y, z; };
+struct Base {
+  virtual void f() noexcept; // expected-note {{overridden}}
+};
+template<typename T> struct Derived : Base {
+  void f() noexcept (sizeof(T) == 4); // expected-error {{is more lax}}
+  void g() noexcept (T::error);
+};
+
+Derived<Exc1> d1; // ok
+Derived<Exc2> d2; // expected-note {{in instantiation of}}





More information about the cfe-commits mailing list