]> granicus.if.org Git - clang/commitdiff
PR 12586: Fix assert while running libc++ testsuite: deal with exception
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 19 Apr 2012 00:08:28 +0000 (00:08 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 19 Apr 2012 00:08:28 +0000 (00:08 +0000)
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

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

index 9fd490167297612ae43d7a86505d86e24edc83ec..7b615c19dcc40f4ea81a9f8b4e06588be3829aeb 100644 (file)
@@ -2701,7 +2701,8 @@ public:
     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 @@ public:
     const QualType *Exceptions;
     Expr *NoexceptExpr;
     FunctionDecl *ExceptionSpecDecl;
+    FunctionDecl *ExceptionSpecTemplate;
     const bool *ConsumedArguments;
   };
 
@@ -2759,9 +2761,10 @@ private:
   // 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 @@ public:
       EPI.NoexceptExpr = getNoexceptExpr();
     } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
       EPI.ExceptionSpecDecl = getExceptionSpecDecl();
+      EPI.ExceptionSpecTemplate = getExceptionSpecTemplate();
     }
     if (hasAnyConsumedArgs())
       EPI.ConsumedArguments = getConsumedArgsBuffer();
@@ -2847,10 +2851,22 @@ public:
     // 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();
index 65ddc059fa7044c2b82a9d32cd7aed44a8a9e648..cb4d336de1576e82ebacc7716b97b26f05630358 100644 (file)
@@ -2195,7 +2195,7 @@ ASTContext::getFunctionType(QualType ResultTy,
   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);
index 10c1adc875d59f0d6480210df1f5902dfb98623a..3f6a09457d1e433181f82de927087f9268921d4c 100644 (file)
@@ -1550,7 +1550,8 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
     // 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.
   }
index 669ba3ad37611ec53604d7cfc4e1f87910f2c03b..d2e0e6b63b4df611ad8c1f1d56835e92c6162adc 100644 (file)
@@ -9776,9 +9776,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
 
   // 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
index 4d312f855f569dffa4187cc5b3604f60d8ea3045..c7bd99c1ca6a5d46e0c213bd2daaab94fcd7d1cd 100644 (file)
@@ -2251,6 +2251,8 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
 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 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
 
 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 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
   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 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
         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 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
       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(),
index 4e08dce2ae77e8fb0dd2d528043ad0272cf20dc0..194b80cdd47e873428c7acbbfffd49b88e0f0dd6 100644 (file)
@@ -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 @@ template void S<char16_t>::f();
 // 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 @@ void g() {
   // 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>();
+}
index d29c8862b9aec6772734c3fda0d6bad78a788b47..8a6f9efa68eca6cb615913f74181552aaf8f22a8 100644 (file)
@@ -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()) *pVoid1 = 0; // ok, exception spec not needed
 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 @@ namespace pr9485 {
     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}}