[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-exceptio

Douglas Gregor dgregor at apple.com
Thu Apr 19 07:45:49 PDT 2012


Approved.

On Apr 18, 2012, at 6:25 PM, Richard Smith wrote:

> This fixes release blocker PR12586. Requesting branch merge approval! :)
> 
> On Wed, Apr 18, 2012 at 5:08 PM, Richard Smith <richard-llvm at metafoo.co.uk> wrote:
> 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}}
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20120419/707f37f4/attachment.html>


More information about the cfe-commits mailing list