[cfe-commits] r154886 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/Analysis/ lib/Sema/ test/CXX/except/except.spec/ test/CodeGenCXX/ test/SemaTemplate/

Matthieu Monrocq matthieu.monrocq at gmail.com
Wed Apr 18 11:37:59 PDT 2012


Le 17 avril 2012 02:58, Richard Smith <richard-llvm at metafoo.co.uk> a écrit :

> Author: rsmith
> Date: Mon Apr 16 19:58:00 2012
> New Revision: 154886
>
> URL: http://llvm.org/viewvc/llvm-project?rev=154886&view=rev
> Log:
> Implement DR1330 in C++11 mode, to support libstdc++4.7 which uses it.
>
> We have a new flavor of exception specification, EST_Uninstantiated. A
> function
> type with this exception specification carries a pointer to a
> FunctionDecl, and
> the exception specification for that FunctionDecl is instantiated (if
> needed)
> and used in the place of the function type's exception specification.
>
> When a function template declaration with a non-trivial exception
> specification
> is instantiated, the specialization's exception specification is set to
> this
> new 'uninstantiated' kind rather than being instantiated immediately.
>
> Expr::CanThrow has migrated onto Sema, so it can instantiate exception
> specs
> on-demand. Also, any odr-use of a function triggers the instantiation of
> its
> exception specification (the exception specification could be needed by
> IRGen).
> In passing, fix two places where a DeclRefExpr was created but the
> corresponding
> function was not actually marked odr-used. We used to get away with this,
> but
> don't any more.
>
> Also fix a bug where instantiating an exception specification which refers
> to
> function parameters resulted in a crash. We still have the same bug in
> default
> arguments, which I'll be looking into next.
>
> This, plus a tiny patch to fix libstdc++'s common_type, is enough for
> clang to
> parse (and, in very limited testing, support) all of libstdc++4.7's
> standard
> headers.
>
>
Will it be available in Clang 3.1 ?


> Added:
>    cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp
>    cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
> Modified:
>    cfe/trunk/include/clang/AST/Expr.h
>    cfe/trunk/include/clang/AST/Type.h
>    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>    cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h
>    cfe/trunk/include/clang/Sema/Sema.h
>    cfe/trunk/lib/AST/ASTContext.cpp
>    cfe/trunk/lib/AST/Expr.cpp
>    cfe/trunk/lib/AST/Type.cpp
>    cfe/trunk/lib/Analysis/CFG.cpp
>    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
>    cfe/trunk/lib/Sema/SemaExpr.cpp
>    cfe/trunk/lib/Sema/SemaExprCXX.cpp
>    cfe/trunk/lib/Sema/SemaOverload.cpp
>    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
>    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
>    cfe/trunk/lib/Sema/TreeTransform.h
>    cfe/trunk/test/CXX/except/except.spec/p1.cpp
>    cfe/trunk/test/SemaTemplate/instantiate-declref.cpp
>
> Modified: cfe/trunk/include/clang/AST/Expr.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Expr.h (original)
> +++ cfe/trunk/include/clang/AST/Expr.h Mon Apr 16 19:58:00 2012
> @@ -581,16 +581,6 @@
>   /// member expression.
>   static QualType findBoundMemberType(const Expr *expr);
>
> -  /// \brief Result type of CanThrow().
> -  enum CanThrowResult {
> -    CT_Cannot,
> -    CT_Dependent,
> -    CT_Can
> -  };
> -  /// \brief Test if this expression, if evaluated, might throw,
> according to
> -  ///        the rules of C++ [expr.unary.noexcept].
> -  CanThrowResult CanThrow(ASTContext &C) const;
> -
>   /// IgnoreImpCasts - Skip past any implicit casts which might
>   /// surround this expression.  Only skips ImplicitCastExprs.
>   Expr *IgnoreImpCasts() LLVM_READONLY;
>
> Modified: cfe/trunk/include/clang/AST/Type.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Type.h (original)
> +++ cfe/trunk/include/clang/AST/Type.h Mon Apr 16 19:58:00 2012
> @@ -79,6 +79,7 @@
>   class CXXRecordDecl;
>   class EnumDecl;
>   class FieldDecl;
> +  class FunctionDecl;
>   class ObjCInterfaceDecl;
>   class ObjCProtocolDecl;
>   class ObjCMethodDecl;
> @@ -2700,7 +2701,8 @@
>     ExtProtoInfo() :
>       Variadic(false), HasTrailingReturn(false), TypeQuals(0),
>       ExceptionSpecType(EST_None), RefQualifier(RQ_None),
> -      NumExceptions(0), Exceptions(0), NoexceptExpr(0),
> ConsumedArguments(0) {}
> +      NumExceptions(0), Exceptions(0), NoexceptExpr(0),
> ExceptionSpecDecl(0),
> +      ConsumedArguments(0) {}
>
>     FunctionType::ExtInfo ExtInfo;
>     bool Variadic : 1;
> @@ -2711,6 +2713,7 @@
>     unsigned NumExceptions;
>     const QualType *Exceptions;
>     Expr *NoexceptExpr;
> +    FunctionDecl *ExceptionSpecDecl;
>     const bool *ConsumedArguments;
>   };
>
> @@ -2756,6 +2759,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.
> +
>   // ConsumedArgs - A variable size array, following Exceptions
>   // and of length NumArgs, holding flags indicating which arguments
>   // are consumed.  This only appears if HasAnyConsumedArgs is true.
> @@ -2795,6 +2802,8 @@
>       EPI.Exceptions = exception_begin();
>     } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
>       EPI.NoexceptExpr = getNoexceptExpr();
> +    } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
> +      EPI.ExceptionSpecDecl = getExceptionSpecDecl();
>     }
>     if (hasAnyConsumedArgs())
>       EPI.ConsumedArguments = getConsumedArgsBuffer();
> @@ -2838,9 +2847,14 @@
>     // NoexceptExpr sits where the arguments end.
>     return *reinterpret_cast<Expr *const *>(arg_type_end());
>   }
> +  FunctionDecl *getExceptionSpecDecl() const {
> +    if (getExceptionSpecType() != EST_Uninstantiated)
> +      return 0;
> +    return *reinterpret_cast<FunctionDecl * const *>(arg_type_end());
> +  }
>   bool isNothrow(ASTContext &Ctx) const {
>     ExceptionSpecificationType EST = getExceptionSpecType();
> -    assert(EST != EST_Delayed);
> +    assert(EST != EST_Delayed && EST != EST_Uninstantiated);
>     if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
>       return true;
>     if (EST != EST_ComputedNoexcept)
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Apr 16
> 19:58:00 2012
> @@ -2583,6 +2583,8 @@
>   "in instantiation of enumeration %q0 requested here">;
>  def note_template_type_alias_instantiation_here : Note<
>   "in instantiation of template type alias %0 requested here">;
> +def note_template_exception_spec_instantiation_here : Note<
> +  "in instantiation of exception specification for %0 requested here">;
>
>  def note_default_arg_instantiation_here : Note<
>   "in instantiation of default argument for '%0' required here">;
>
> Modified: cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h (original)
> +++ cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h Mon Apr 16
> 19:58:00 2012
> @@ -16,7 +16,7 @@
>
>  namespace clang {
>
> -/// \brief The various types of exception specifications that exist in
> C++0x.
> +/// \brief The various types of exception specifications that exist in
> C++11.
>  enum ExceptionSpecificationType {
>   EST_None,             ///< no exception specification
>   EST_DynamicNone,      ///< throw()
> @@ -24,7 +24,8 @@
>   EST_MSAny,            ///< Microsoft throw(...) extension
>   EST_BasicNoexcept,    ///< noexcept
>   EST_ComputedNoexcept, ///< noexcept(expression)
> -  EST_Delayed           ///< not known yet
> +  EST_Delayed,          ///< not known yet
> +  EST_Uninstantiated    ///< not instantiated yet
>  };
>
>  inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
> @@ -35,6 +36,19 @@
>   return ESpecType == EST_BasicNoexcept || ESpecType ==
> EST_ComputedNoexcept;
>  }
>
> +/// \brief Possible results from evaluation of a noexcept expression.
> +enum CanThrowResult {
> +  CT_Cannot,
> +  CT_Dependent,
> +  CT_Can
> +};
> +
> +inline CanThrowResult mergeCanThrow(CanThrowResult CT1, CanThrowResult
> CT2) {
> +  // CanThrowResult constants are ordered so that the maximum is the
> correct
> +  // merge result.
> +  return CT1 > CT2 ? CT1 : CT2;
> +}
> +
>  } // end namespace clang
>
>  #endif // LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H
>
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Mon Apr 16 19:58:00 2012
> @@ -907,6 +907,9 @@
>   DeclarationNameInfo GetNameForDeclarator(Declarator &D);
>   DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name);
>   static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo
> = 0);
> +  CanThrowResult canThrow(const Expr *E);
> +  const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
> +                                                const FunctionProtoType
> *FPT);
>   bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
>   bool CheckDistantExceptionSpec(QualType T);
>   bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
> @@ -3050,7 +3053,7 @@
>   /// implicitly-declared special member functions.
>   class ImplicitExceptionSpecification {
>     // Pointer to allow copying
> -    ASTContext *Context;
> +    Sema *Self;
>     // We order exception specifications thus:
>     // noexcept is the most restrictive, but is only used in C++0x.
>     // throw() comes next.
> @@ -3074,9 +3077,9 @@
>     }
>
>   public:
> -    explicit ImplicitExceptionSpecification(ASTContext &Context)
> -      : Context(&Context), ComputedEST(EST_BasicNoexcept) {
> -      if (!Context.getLangOpts().CPlusPlus0x)
> +    explicit ImplicitExceptionSpecification(Sema &Self)
> +      : Self(&Self), ComputedEST(EST_BasicNoexcept) {
> +      if (!Self.Context.getLangOpts().CPlusPlus0x)
>         ComputedEST = EST_DynamicNone;
>     }
>
> @@ -3094,7 +3097,7 @@
>     const QualType *data() const { return Exceptions.data(); }
>
>     /// \brief Integrate another called method into the collected data.
> -    void CalledDecl(CXXMethodDecl *Method);
> +    void CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method);
>
>     /// \brief Integrate an invoked expression into the collected data.
>     void CalledExpr(Expr *E);
> @@ -5194,7 +5197,11 @@
>
>       /// We are checking the validity of a default template argument that
>       /// has been used when naming a template-id.
> -      DefaultTemplateArgumentChecking
> +      DefaultTemplateArgumentChecking,
> +
> +      /// We are instantiating the exception specification for a function
> +      /// template which was deferred until it was needed.
> +      ExceptionSpecInstantiation
>     } Kind;
>
>     /// \brief The point of instantiation within the source code.
> @@ -5242,6 +5249,7 @@
>
>       switch (X.Kind) {
>       case TemplateInstantiation:
> +      case ExceptionSpecInstantiation:
>         return true;
>
>       case PriorTemplateArgumentSubstitution:
> @@ -5359,6 +5367,13 @@
>                           Decl *Entity,
>                           SourceRange InstantiationRange = SourceRange());
>
> +    struct ExceptionSpecification {};
> +    /// \brief Note that we are instantiating an exception specification
> +    /// of a function template.
> +    InstantiatingTemplate(Sema &SemaRef, SourceLocation
> PointOfInstantiation,
> +                          FunctionDecl *Entity, ExceptionSpecification,
> +                          SourceRange InstantiationRange = SourceRange());
> +
>     /// \brief Note that we are instantiating a default argument in a
>     /// template-id.
>     InstantiatingTemplate(Sema &SemaRef, SourceLocation
> PointOfInstantiation,
> @@ -5658,6 +5673,8 @@
>              TemplateArgumentListInfo &Result,
>              const MultiLevelTemplateArgumentList &TemplateArgs);
>
> +  void InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
> +                                FunctionDecl *Function);
>   void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
>                                      FunctionDecl *Function,
>                                      bool Recursive = false,
>
> Modified: cfe/trunk/lib/AST/ASTContext.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ASTContext.cpp (original)
> +++ cfe/trunk/lib/AST/ASTContext.cpp Mon Apr 16 19:58:00 2012
> @@ -2194,6 +2194,8 @@
>     Size += EPI.NumExceptions * sizeof(QualType);
>   else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
>     Size += sizeof(Expr*);
> +  } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
> +    Size += sizeof(FunctionDecl*);
>   }
>   if (EPI.ConsumedArguments)
>     Size += NumArgs * sizeof(bool);
>
> Modified: cfe/trunk/lib/AST/Expr.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/Expr.cpp (original)
> +++ cfe/trunk/lib/AST/Expr.cpp Mon Apr 16 19:58:00 2012
> @@ -1996,331 +1996,6 @@
>   return QualType();
>  }
>
> -static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1,
> -                                          Expr::CanThrowResult CT2) {
> -  // CanThrowResult constants are ordered so that the maximum is the
> correct
> -  // merge result.
> -  return CT1 > CT2 ? CT1 : CT2;
> -}
> -
> -static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr
> *CE) {
> -  Expr *E = const_cast<Expr*>(CE);
> -  Expr::CanThrowResult R = Expr::CT_Cannot;
> -  for (Expr::child_range I = E->children(); I && R != Expr::CT_Can; ++I) {
> -    R = MergeCanThrow(R, cast<Expr>(*I)->CanThrow(C));
> -  }
> -  return R;
> -}
> -
> -static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E,
> -                                           const Decl *D,
> -                                           bool NullThrows = true) {
> -  if (!D)
> -    return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
> -
> -  // See if we can get a function type from the decl somehow.
> -  const ValueDecl *VD = dyn_cast<ValueDecl>(D);
> -  if (!VD) // If we have no clue what we're calling, assume the worst.
> -    return Expr::CT_Can;
> -
> -  // As an extension, we assume that __attribute__((nothrow)) functions
> don't
> -  // throw.
> -  if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
> -    return Expr::CT_Cannot;
> -
> -  QualType T = VD->getType();
> -  const FunctionProtoType *FT;
> -  if ((FT = T->getAs<FunctionProtoType>())) {
> -  } else if (const PointerType *PT = T->getAs<PointerType>())
> -    FT = PT->getPointeeType()->getAs<FunctionProtoType>();
> -  else if (const ReferenceType *RT = T->getAs<ReferenceType>())
> -    FT = RT->getPointeeType()->getAs<FunctionProtoType>();
> -  else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
> -    FT = MT->getPointeeType()->getAs<FunctionProtoType>();
> -  else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
> -    FT = BT->getPointeeType()->getAs<FunctionProtoType>();
> -
> -  if (!FT)
> -    return Expr::CT_Can;
> -
> -  if (FT->getExceptionSpecType() == EST_Delayed) {
> -    assert(isa<CXXConstructorDecl>(D) &&
> -           "only constructor exception specs can be unknown");
> -    Ctx.getDiagnostics().Report(E->getLocStart(),
> -                                diag::err_exception_spec_unknown)
> -      << E->getSourceRange();
> -    return Expr::CT_Can;
> -  }
> -
> -  return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can;
> -}
> -
> -static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr
> *DC) {
> -  if (DC->isTypeDependent())
> -    return Expr::CT_Dependent;
> -
> -  if (!DC->getTypeAsWritten()->isReferenceType())
> -    return Expr::CT_Cannot;
> -
> -  if (DC->getSubExpr()->isTypeDependent())
> -    return Expr::CT_Dependent;
> -
> -  return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can :
> Expr::CT_Cannot;
> -}
> -
> -static Expr::CanThrowResult CanTypeidThrow(ASTContext &C,
> -                                           const CXXTypeidExpr *DC) {
> -  if (DC->isTypeOperand())
> -    return Expr::CT_Cannot;
> -
> -  Expr *Op = DC->getExprOperand();
> -  if (Op->isTypeDependent())
> -    return Expr::CT_Dependent;
> -
> -  const RecordType *RT = Op->getType()->getAs<RecordType>();
> -  if (!RT)
> -    return Expr::CT_Cannot;
> -
> -  if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
> -    return Expr::CT_Cannot;
> -
> -  if (Op->Classify(C).isPRValue())
> -    return Expr::CT_Cannot;
> -
> -  return Expr::CT_Can;
> -}
> -
> -Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
> -  // C++ [expr.unary.noexcept]p3:
> -  //   [Can throw] if in a potentially-evaluated context the expression
> would
> -  //   contain:
> -  switch (getStmtClass()) {
> -  case CXXThrowExprClass:
> -    //   - a potentially evaluated throw-expression
> -    return CT_Can;
> -
> -  case CXXDynamicCastExprClass: {
> -    //   - a potentially evaluated dynamic_cast expression
> dynamic_cast<T>(v),
> -    //     where T is a reference type, that requires a run-time check
> -    CanThrowResult CT =
> CanDynamicCastThrow(cast<CXXDynamicCastExpr>(this));
> -    if (CT == CT_Can)
> -      return CT;
> -    return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> -  }
> -
> -  case CXXTypeidExprClass:
> -    //   - a potentially evaluated typeid expression applied to a glvalue
> -    //     expression whose type is a polymorphic class type
> -    return CanTypeidThrow(C, cast<CXXTypeidExpr>(this));
> -
> -    //   - a potentially evaluated call to a function, member function,
> function
> -    //     pointer, or member function pointer that does not have a
> non-throwing
> -    //     exception-specification
> -  case CallExprClass:
> -  case CXXMemberCallExprClass:
> -  case CXXOperatorCallExprClass:
> -  case UserDefinedLiteralClass: {
> -    const CallExpr *CE = cast<CallExpr>(this);
> -    CanThrowResult CT;
> -    if (isTypeDependent())
> -      CT = CT_Dependent;
> -    else if
> (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
> -      CT = CT_Cannot;
> -    else
> -      CT = CanCalleeThrow(C, this, CE->getCalleeDecl());
> -    if (CT == CT_Can)
> -      return CT;
> -    return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> -  }
> -
> -  case CXXConstructExprClass:
> -  case CXXTemporaryObjectExprClass: {
> -    CanThrowResult CT = CanCalleeThrow(C, this,
> -        cast<CXXConstructExpr>(this)->getConstructor());
> -    if (CT == CT_Can)
> -      return CT;
> -    return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> -  }
> -
> -  case LambdaExprClass: {
> -    const LambdaExpr *Lambda = cast<LambdaExpr>(this);
> -    CanThrowResult CT = Expr::CT_Cannot;
> -    for (LambdaExpr::capture_init_iterator Cap =
> Lambda->capture_init_begin(),
> -                                        CapEnd =
> Lambda->capture_init_end();
> -         Cap != CapEnd; ++Cap)
> -      CT = MergeCanThrow(CT, (*Cap)->CanThrow(C));
> -    return CT;
> -  }
> -
> -  case CXXNewExprClass: {
> -    CanThrowResult CT;
> -    if (isTypeDependent())
> -      CT = CT_Dependent;
> -    else
> -      CT = CanCalleeThrow(C, this,
> cast<CXXNewExpr>(this)->getOperatorNew());
> -    if (CT == CT_Can)
> -      return CT;
> -    return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> -  }
> -
> -  case CXXDeleteExprClass: {
> -    CanThrowResult CT;
> -    QualType DTy = cast<CXXDeleteExpr>(this)->getDestroyedType();
> -    if (DTy.isNull() || DTy->isDependentType()) {
> -      CT = CT_Dependent;
> -    } else {
> -      CT = CanCalleeThrow(C, this,
> -                          cast<CXXDeleteExpr>(this)->getOperatorDelete());
> -      if (const RecordType *RT = DTy->getAs<RecordType>()) {
> -        const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
> -        CT = MergeCanThrow(CT, CanCalleeThrow(C, this,
> RD->getDestructor()));
> -      }
> -      if (CT == CT_Can)
> -        return CT;
> -    }
> -    return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> -  }
> -
> -  case CXXBindTemporaryExprClass: {
> -    // The bound temporary has to be destroyed again, which might throw.
> -    CanThrowResult CT = CanCalleeThrow(C, this,
> -      cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());
> -    if (CT == CT_Can)
> -      return CT;
> -    return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> -  }
> -
> -    // ObjC message sends are like function calls, but never have
> exception
> -    // specs.
> -  case ObjCMessageExprClass:
> -  case ObjCPropertyRefExprClass:
> -  case ObjCSubscriptRefExprClass:
> -    return CT_Can;
> -
> -    // All the ObjC literals that are implemented as calls are
> -    // potentially throwing unless we decide to close off that
> -    // possibility.
> -  case ObjCArrayLiteralClass:
> -  case ObjCDictionaryLiteralClass:
> -  case ObjCNumericLiteralClass:
> -    return CT_Can;
> -
> -    // Many other things have subexpressions, so we have to test those.
> -    // Some are simple:
> -  case ConditionalOperatorClass:
> -  case CompoundLiteralExprClass:
> -  case CXXConstCastExprClass:
> -  case CXXDefaultArgExprClass:
> -  case CXXReinterpretCastExprClass:
> -  case DesignatedInitExprClass:
> -  case ExprWithCleanupsClass:
> -  case ExtVectorElementExprClass:
> -  case InitListExprClass:
> -  case MemberExprClass:
> -  case ObjCIsaExprClass:
> -  case ObjCIvarRefExprClass:
> -  case ParenExprClass:
> -  case ParenListExprClass:
> -  case ShuffleVectorExprClass:
> -  case VAArgExprClass:
> -    return CanSubExprsThrow(C, this);
> -
> -    // Some might be dependent for other reasons.
> -  case ArraySubscriptExprClass:
> -  case BinaryOperatorClass:
> -  case CompoundAssignOperatorClass:
> -  case CStyleCastExprClass:
> -  case CXXStaticCastExprClass:
> -  case CXXFunctionalCastExprClass:
> -  case ImplicitCastExprClass:
> -  case MaterializeTemporaryExprClass:
> -  case UnaryOperatorClass: {
> -    CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot;
> -    return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> -  }
> -
> -    // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of
> worms.
> -  case StmtExprClass:
> -    return CT_Can;
> -
> -  case ChooseExprClass:
> -    if (isTypeDependent() || isValueDependent())
> -      return CT_Dependent;
> -    return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C);
> -
> -  case GenericSelectionExprClass:
> -    if (cast<GenericSelectionExpr>(this)->isResultDependent())
> -      return CT_Dependent;
> -    return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C);
> -
> -    // Some expressions are always dependent.
> -  case CXXDependentScopeMemberExprClass:
> -  case CXXUnresolvedConstructExprClass:
> -  case DependentScopeDeclRefExprClass:
> -    return CT_Dependent;
> -
> -  case AtomicExprClass:
> -  case AsTypeExprClass:
> -  case BinaryConditionalOperatorClass:
> -  case BlockExprClass:
> -  case CUDAKernelCallExprClass:
> -  case DeclRefExprClass:
> -  case ObjCBridgedCastExprClass:
> -  case ObjCIndirectCopyRestoreExprClass:
> -  case ObjCProtocolExprClass:
> -  case ObjCSelectorExprClass:
> -  case OffsetOfExprClass:
> -  case PackExpansionExprClass:
> -  case PseudoObjectExprClass:
> -  case SubstNonTypeTemplateParmExprClass:
> -  case SubstNonTypeTemplateParmPackExprClass:
> -  case UnaryExprOrTypeTraitExprClass:
> -  case UnresolvedLookupExprClass:
> -  case UnresolvedMemberExprClass:
> -    // FIXME: Can any of the above throw?  If so, when?
> -    return CT_Cannot;
> -
> -  case AddrLabelExprClass:
> -  case ArrayTypeTraitExprClass:
> -  case BinaryTypeTraitExprClass:
> -  case TypeTraitExprClass:
> -  case CXXBoolLiteralExprClass:
> -  case CXXNoexceptExprClass:
> -  case CXXNullPtrLiteralExprClass:
> -  case CXXPseudoDestructorExprClass:
> -  case CXXScalarValueInitExprClass:
> -  case CXXThisExprClass:
> -  case CXXUuidofExprClass:
> -  case CharacterLiteralClass:
> -  case ExpressionTraitExprClass:
> -  case FloatingLiteralClass:
> -  case GNUNullExprClass:
> -  case ImaginaryLiteralClass:
> -  case ImplicitValueInitExprClass:
> -  case IntegerLiteralClass:
> -  case ObjCEncodeExprClass:
> -  case ObjCStringLiteralClass:
> -  case ObjCBoolLiteralExprClass:
> -  case OpaqueValueExprClass:
> -  case PredefinedExprClass:
> -  case SizeOfPackExprClass:
> -  case StringLiteralClass:
> -  case UnaryTypeTraitExprClass:
> -    // These expressions can never throw.
> -    return CT_Cannot;
> -
> -#define STMT(CLASS, PARENT) case CLASS##Class:
> -#define STMT_RANGE(Base, First, Last)
> -#define LAST_STMT_RANGE(BASE, FIRST, LAST)
> -#define EXPR(CLASS, PARENT)
> -#define ABSTRACT_STMT(STMT)
> -#include "clang/AST/StmtNodes.inc"
> -  case NoStmtClass:
> -    llvm_unreachable("Invalid class for expression");
> -  }
> -  llvm_unreachable("Bogus StmtClass");
> -}
> -
>  Expr* Expr::IgnoreParens() {
>   Expr* E = this;
>   while (true) {
>
> Modified: cfe/trunk/lib/AST/Type.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/Type.cpp (original)
> +++ cfe/trunk/lib/AST/Type.cpp Mon Apr 16 19:58:00 2012
> @@ -1546,6 +1546,13 @@
>       else if (epi.NoexceptExpr->isInstantiationDependent())
>         setInstantiationDependent();
>     }
> +  } else if (getExceptionSpecType() == EST_Uninstantiated) {
> +    // Store the function decl from which we will resolve our
> +    // exception specification.
> +    FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot +
> numArgs);
> +    *slot = epi.ExceptionSpecDecl;
> +    // This exception specification doesn't make the type dependent,
> because
> +    // it's not instantiated as part of instantiating the type.
>   }
>
>   if (epi.ConsumedArguments) {
> @@ -1629,6 +1636,8 @@
>       ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());
>   } else if (epi.ExceptionSpecType == EST_ComputedNoexcept &&
> epi.NoexceptExpr){
>     epi.NoexceptExpr->Profile(ID, Context, false);
> +  } else if (epi.ExceptionSpecType == EST_Uninstantiated) {
> +    ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl());
>   }
>   if (epi.ConsumedArguments) {
>     for (unsigned i = 0; i != NumArgs; ++i)
>
> Modified: cfe/trunk/lib/Analysis/CFG.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/CFG.cpp (original)
> +++ cfe/trunk/lib/Analysis/CFG.cpp Mon Apr 16 19:58:00 2012
> @@ -1284,7 +1284,8 @@
>   const FunctionType *FT = Ty->getAs<FunctionType>();
>   if (FT) {
>     if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
> -      if (Proto->isNothrow(Ctx))
> +      if (Proto->getExceptionSpecType() != EST_Uninstantiated &&
> +          Proto->isNothrow(Ctx))
>         return false;
>   }
>   return true;
>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Apr 16 19:58:00 2012
> @@ -125,14 +125,17 @@
>   }
>  }
>
> -void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl
> *Method) {
> -  assert(Context && "ImplicitExceptionSpecification without an
> ASTContext");
> +void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation
> CallLoc,
> +                                                      CXXMethodDecl
> *Method) {
>   // If we have an MSAny or unknown spec already, don't bother.
>   if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
>     return;
>
>   const FunctionProtoType *Proto
>     = Method->getType()->getAs<FunctionProtoType>();
> +  Proto = Self->ResolveExceptionSpec(CallLoc, Proto);
> +  if (!Proto)
> +    return;
>
>   ExceptionSpecificationType EST = Proto->getExceptionSpecType();
>
> @@ -164,7 +167,8 @@
>
>   // Check out noexcept specs.
>   if (EST == EST_ComputedNoexcept) {
> -    FunctionProtoType::NoexceptResult NR =
> Proto->getNoexceptSpec(*Context);
> +    FunctionProtoType::NoexceptResult NR =
> +        Proto->getNoexceptSpec(Self->Context);
>     assert(NR != FunctionProtoType::NR_NoNoexcept &&
>            "Must have noexcept result for EST_ComputedNoexcept.");
>     assert(NR != FunctionProtoType::NR_Dependent &&
> @@ -188,7 +192,7 @@
>   for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
>                                           EEnd = Proto->exception_end();
>        E != EEnd; ++E)
> -    if (ExceptionsSeen.insert(Context->getCanonicalType(*E)))
> +    if (ExceptionsSeen.insert(Self->Context.getCanonicalType(*E)))
>       Exceptions.push_back(*E);
>  }
>
> @@ -217,7 +221,7 @@
>   // implicit definition. For now, we assume that any non-nothrow
> expression can
>   // throw any exception.
>
> -  if (E->CanThrow(*Context))
> +  if (Self->canThrow(E))
>     ComputedEST = EST_None;
>  }
>
> @@ -3922,7 +3926,7 @@
>     HadError = true;
>   }
>
> -  ImplicitExceptionSpecification Spec(Context);
> +  ImplicitExceptionSpecification Spec(*this);
>   bool Const;
>   llvm::tie(Spec, Const) =
>     ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent());
> @@ -4031,7 +4035,7 @@
>     HadError = true;
>   }
>
> -  ImplicitExceptionSpecification Spec(Context);
> +  ImplicitExceptionSpecification Spec(*this);
>   bool Const;
>   llvm::tie(Spec, Const) =
>     ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent());
> @@ -6814,7 +6818,7 @@
>   // C++ [except.spec]p14:
>   //   An implicitly declared special member function (Clause 12) shall
> have an
>   //   exception-specification. [...]
> -  ImplicitExceptionSpecification ExceptSpec(Context);
> +  ImplicitExceptionSpecification ExceptSpec(*this);
>   if (ClassDecl->isInvalidDecl())
>     return ExceptSpec;
>
> @@ -6831,7 +6835,7 @@
>       // If this is a deleted function, add it anyway. This might be
> conformant
>       // with the standard. This might not. I'm not sure. It might not
> matter.
>       if (Constructor)
> -        ExceptSpec.CalledDecl(Constructor);
> +        ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
>     }
>   }
>
> @@ -6845,7 +6849,7 @@
>       // If this is a deleted function, add it anyway. This might be
> conformant
>       // with the standard. This might not. I'm not sure. It might not
> matter.
>       if (Constructor)
> -        ExceptSpec.CalledDecl(Constructor);
> +        ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
>     }
>   }
>
> @@ -6868,7 +6872,7 @@
>       // might just be ill-formed because this function attempts to refer
> to
>       // a deleted function here.
>       if (Constructor)
> -        ExceptSpec.CalledDecl(Constructor);
> +        ExceptSpec.CalledDecl(F->getLocation(), Constructor);
>     }
>   }
>
> @@ -6990,6 +6994,7 @@
>   const FunctionProtoType *CtorTy =
>     CtorDecl->getType()->castAs<FunctionProtoType>();
>   if (CtorTy->getExceptionSpecType() == EST_Delayed) {
> +    // FIXME: Don't do this unless the exception spec is needed.
>     ImplicitExceptionSpecification Spec =
>       ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
>     FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
> @@ -7190,7 +7195,7 @@
>   // C++ [except.spec]p14:
>   //   An implicitly declared special member function (Clause 12) shall
> have
>   //   an exception-specification.
> -  ImplicitExceptionSpecification ExceptSpec(Context);
> +  ImplicitExceptionSpecification ExceptSpec(*this);
>   if (ClassDecl->isInvalidDecl())
>     return ExceptSpec;
>
> @@ -7202,7 +7207,7 @@
>       continue;
>
>     if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
> -      ExceptSpec.CalledDecl(
> +      ExceptSpec.CalledDecl(B->getLocStart(),
>
>  LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
>   }
>
> @@ -7211,7 +7216,7 @@
>                                        BEnd = ClassDecl->vbases_end();
>        B != BEnd; ++B) {
>     if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
> -      ExceptSpec.CalledDecl(
> +      ExceptSpec.CalledDecl(B->getLocStart(),
>
> LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
>   }
>
> @@ -7221,7 +7226,7 @@
>        F != FEnd; ++F) {
>     if (const RecordType *RecordTy
>         = Context.getBaseElementType(F->getType())->getAs<RecordType>())
> -      ExceptSpec.CalledDecl(
> +      ExceptSpec.CalledDecl(F->getLocation(),
>
> LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
>   }
>
> @@ -7546,7 +7551,7 @@
>  Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
>                                                    CXXRecordDecl
> *ClassDecl) {
>   if (ClassDecl->isInvalidDecl())
> -    return std::make_pair(ImplicitExceptionSpecification(Context), false);
> +    return std::make_pair(ImplicitExceptionSpecification(*this), false);
>
>   // C++ [class.copy]p10:
>   //   If the class definition does not explicitly declare a copy
> @@ -7619,7 +7624,7 @@
>   // Based on a similar decision made for constness in C++0x, we're erring
> on
>   // the side of assuming such calls to be made regardless of whether they
>   // actually happen.
> -  ImplicitExceptionSpecification ExceptSpec(Context);
> +  ImplicitExceptionSpecification ExceptSpec(*this);
>   unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0;
>   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
>                                        BaseEnd = ClassDecl->bases_end();
> @@ -7631,7 +7636,7 @@
>       =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
>     if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
>                                                             ArgQuals,
> false, 0))
> -      ExceptSpec.CalledDecl(CopyAssign);
> +      ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign);
>   }
>
>   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
> @@ -7641,7 +7646,7 @@
>       =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
>     if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
>                                                             ArgQuals,
> false, 0))
> -      ExceptSpec.CalledDecl(CopyAssign);
> +      ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign);
>   }
>
>   for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
> @@ -7652,7 +7657,7 @@
>     if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
>       if (CXXMethodDecl *CopyAssign =
>           LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0))
> -        ExceptSpec.CalledDecl(CopyAssign);
> +        ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign);
>     }
>   }
>
> @@ -7665,7 +7670,7 @@
>   // for determining the argument type of the operator. Note also that
>   // operators taking an object instead of a reference are allowed.
>
> -  ImplicitExceptionSpecification Spec(Context);
> +  ImplicitExceptionSpecification Spec(*this);
>   bool Const;
>   llvm::tie(Spec, Const) =
>     ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl);
> @@ -8032,7 +8037,7 @@
>
>  Sema::ImplicitExceptionSpecification
>  Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl
> *ClassDecl) {
> -  ImplicitExceptionSpecification ExceptSpec(Context);
> +  ImplicitExceptionSpecification ExceptSpec(*this);
>
>   if (ClassDecl->isInvalidDecl())
>     return ExceptSpec;
> @@ -8059,7 +8064,7 @@
>       =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
>     if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
>                                                            false, 0))
> -      ExceptSpec.CalledDecl(MoveAssign);
> +      ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
>   }
>
>   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
> @@ -8069,7 +8074,7 @@
>       =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
>     if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
>                                                            false, 0))
> -      ExceptSpec.CalledDecl(MoveAssign);
> +      ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
>   }
>
>   for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
> @@ -8080,7 +8085,7 @@
>     if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
>       if (CXXMethodDecl *MoveAssign =
> LookupMovingAssignment(FieldClassDecl,
>                                                              false, 0))
> -        ExceptSpec.CalledDecl(MoveAssign);
> +        ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign);
>     }
>   }
>
> @@ -8578,7 +8583,7 @@
>  std::pair<Sema::ImplicitExceptionSpecification, bool>
>  Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl
> *ClassDecl) {
>   if (ClassDecl->isInvalidDecl())
> -    return std::make_pair(ImplicitExceptionSpecification(Context), false);
> +    return std::make_pair(ImplicitExceptionSpecification(*this), false);
>
>   // C++ [class.copy]p5:
>   //   The implicitly-declared copy constructor for a class X will
> @@ -8639,7 +8644,7 @@
>   // C++ [except.spec]p14:
>   //   An implicitly declared special member function (Clause 12) shall
> have an
>   //   exception-specification. [...]
> -  ImplicitExceptionSpecification ExceptSpec(Context);
> +  ImplicitExceptionSpecification ExceptSpec(*this);
>   unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0;
>   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
>                                        BaseEnd = ClassDecl->bases_end();
> @@ -8653,7 +8658,7 @@
>       =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
>     if (CXXConstructorDecl *CopyConstructor =
>           LookupCopyingConstructor(BaseClassDecl, Quals))
> -      ExceptSpec.CalledDecl(CopyConstructor);
> +      ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor);
>   }
>   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
>                                        BaseEnd = ClassDecl->vbases_end();
> @@ -8663,7 +8668,7 @@
>       =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
>     if (CXXConstructorDecl *CopyConstructor =
>           LookupCopyingConstructor(BaseClassDecl, Quals))
> -      ExceptSpec.CalledDecl(CopyConstructor);
> +      ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor);
>   }
>   for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
>                                   FieldEnd = ClassDecl->field_end();
> @@ -8673,7 +8678,7 @@
>     if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
>       if (CXXConstructorDecl *CopyConstructor =
>         LookupCopyingConstructor(FieldClassDecl, Quals))
> -      ExceptSpec.CalledDecl(CopyConstructor);
> +      ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor);
>     }
>   }
>
> @@ -8686,7 +8691,7 @@
>   //   If the class definition does not explicitly declare a copy
>   //   constructor, one is declared implicitly.
>
> -  ImplicitExceptionSpecification Spec(Context);
> +  ImplicitExceptionSpecification Spec(*this);
>   bool Const;
>   llvm::tie(Spec, Const) =
>     ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl);
> @@ -8784,7 +8789,7 @@
>   // C++ [except.spec]p14:
>   //   An implicitly declared special member function (Clause 12) shall
> have an
>   //   exception-specification. [...]
> -  ImplicitExceptionSpecification ExceptSpec(Context);
> +  ImplicitExceptionSpecification ExceptSpec(*this);
>   if (ClassDecl->isInvalidDecl())
>     return ExceptSpec;
>
> @@ -8801,7 +8806,7 @@
>       // If this is a deleted function, add it anyway. This might be
> conformant
>       // with the standard. This might not. I'm not sure. It might not
> matter.
>       if (Constructor)
> -        ExceptSpec.CalledDecl(Constructor);
> +        ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
>     }
>   }
>
> @@ -8815,7 +8820,7 @@
>       // If this is a deleted function, add it anyway. This might be
> conformant
>       // with the standard. This might not. I'm not sure. It might not
> matter.
>       if (Constructor)
> -        ExceptSpec.CalledDecl(Constructor);
> +        ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
>     }
>   }
>
> @@ -8833,7 +8838,7 @@
>       // might just be ill-formed because this function attempts to refer
> to
>       // a deleted function here.
>       if (Constructor)
> -        ExceptSpec.CalledDecl(Constructor);
> +        ExceptSpec.CalledDecl(F->getLocation(), Constructor);
>     }
>   }
>
> @@ -11116,6 +11121,7 @@
>   FindCXXThisExpr Finder(*this);
>
>   switch (Proto->getExceptionSpecType()) {
> +  case EST_Uninstantiated:
>   case EST_BasicNoexcept:
>   case EST_Delayed:
>   case EST_DynamicNone:
>
> Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Mon Apr 16 19:58:00 2012
> @@ -96,6 +96,26 @@
>   return FnT->hasExceptionSpec();
>  }
>
> +const FunctionProtoType *
> +Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType
> *FPT) {
> +  // FIXME: If FD is a special member, we should delay computing its
> exception
> +  // specification until this point.
> +  if (FPT->getExceptionSpecType() != EST_Uninstantiated)
> +    return FPT;
> +
> +  FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();
> +  const FunctionProtoType *SourceFPT =
> +      SourceDecl->getType()->castAs<FunctionProtoType>();
> +
> +  if (SourceFPT->getExceptionSpecType() != EST_Uninstantiated)
> +    return SourceFPT;
> +
> +  // Instantiate the exception specification now.
> +  InstantiateExceptionSpec(Loc, SourceDecl);
> +
> +  return SourceDecl->getType()->castAs<FunctionProtoType>();
> +}
> +
>  bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl
> *New) {
>   OverloadedOperatorKind OO =
> New->getDeclName().getCXXOverloadedOperator();
>   bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
> @@ -104,7 +124,7 @@
>   unsigned DiagID = diag::err_mismatched_exception_spec;
>   if (getLangOpts().MicrosoftExt)
>     DiagID = diag::warn_mismatched_exception_spec;
> -
> +
>   if (!CheckEquivalentExceptionSpec(PDiag(DiagID),
>                                     PDiag(diag::note_previous_declaration),
>
> Old->getType()->getAs<FunctionProtoType>(),
> @@ -295,6 +315,13 @@
>   if (MissingEmptyExceptionSpecification)
>     *MissingEmptyExceptionSpecification = false;
>
> +  Old = ResolveExceptionSpec(NewLoc, Old);
> +  if (!Old)
> +    return false;
> +  New = ResolveExceptionSpec(NewLoc, New);
> +  if (!New)
> +    return false;
> +
>   // C++0x [except.spec]p3: Two exception-specifications are compatible if:
>   //   - both are non-throwing, regardless of their form,
>   //   - both have the form noexcept(constant-expression) and the constant-
> @@ -318,6 +345,7 @@
>   ExceptionSpecificationType NewEST = New->getExceptionSpecType();
>
>   assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&
> +         OldEST != EST_Uninstantiated && NewEST != EST_Uninstantiated &&
>          "Shouldn't see unknown exception specifications here");
>
>   // Shortcut the case where both have no spec.
> @@ -483,6 +511,14 @@
>   if (!SubLoc.isValid())
>     SubLoc = SuperLoc;
>
> +  // Resolve the exception specifications, if needed.
> +  Superset = ResolveExceptionSpec(SuperLoc, Superset);
> +  if (!Superset)
> +    return false;
> +  Subset = ResolveExceptionSpec(SubLoc, Subset);
> +  if (!Subset)
> +    return false;
> +
>   ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType();
>
>   // If superset contains everything, we're done.
> @@ -507,6 +543,7 @@
>   ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
>
>   assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&
> +         SuperEST != EST_Uninstantiated && SubEST != EST_Uninstantiated &&
>          "Shouldn't see unknown exception specifications here");
>
>   // It does not. If the subset contains everything, we've failed.
> @@ -726,4 +763,324 @@
>                                   New->getLocation());
>  }
>
> +static CanThrowResult canSubExprsThrow(Sema &S, const Expr *CE) {
> +  Expr *E = const_cast<Expr*>(CE);
> +  CanThrowResult R = CT_Cannot;
> +  for (Expr::child_range I = E->children(); I && R != CT_Can; ++I)
> +    R = mergeCanThrow(R, S.canThrow(cast<Expr>(*I)));
> +  return R;
> +}
> +
> +static CanThrowResult canCalleeThrow(Sema &S, const Expr *E,
> +                                           const Decl *D,
> +                                           bool NullThrows = true) {
> +  if (!D)
> +    return NullThrows ? CT_Can : CT_Cannot;
> +
> +  // See if we can get a function type from the decl somehow.
> +  const ValueDecl *VD = dyn_cast<ValueDecl>(D);
> +  if (!VD) // If we have no clue what we're calling, assume the worst.
> +    return CT_Can;
> +
> +  // As an extension, we assume that __attribute__((nothrow)) functions
> don't
> +  // throw.
> +  if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
> +    return CT_Cannot;
> +
> +  QualType T = VD->getType();
> +  const FunctionProtoType *FT;
> +  if ((FT = T->getAs<FunctionProtoType>())) {
> +  } else if (const PointerType *PT = T->getAs<PointerType>())
> +    FT = PT->getPointeeType()->getAs<FunctionProtoType>();
> +  else if (const ReferenceType *RT = T->getAs<ReferenceType>())
> +    FT = RT->getPointeeType()->getAs<FunctionProtoType>();
> +  else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
> +    FT = MT->getPointeeType()->getAs<FunctionProtoType>();
> +  else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
> +    FT = BT->getPointeeType()->getAs<FunctionProtoType>();
> +
> +  if (!FT)
> +    return CT_Can;
> +
> +  FT = S.ResolveExceptionSpec(E->getLocStart(), FT);
> +  if (!FT)
> +    return CT_Can;
> +
> +  if (FT->getExceptionSpecType() == EST_Delayed) {
> +    // FIXME: Try to resolve a delayed exception spec in
> ResolveExceptionSpec.
> +    assert(isa<CXXConstructorDecl>(D) &&
> +           "only constructor exception specs can be unknown");
> +    S.Diag(E->getLocStart(), diag::err_exception_spec_unknown)
> +      << E->getSourceRange();
> +    return CT_Can;
> +  }
> +
> +  return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;
> +}
> +
> +static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
> +  if (DC->isTypeDependent())
> +    return CT_Dependent;
> +
> +  if (!DC->getTypeAsWritten()->isReferenceType())
> +    return CT_Cannot;
> +
> +  if (DC->getSubExpr()->isTypeDependent())
> +    return CT_Dependent;
> +
> +  return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot;
> +}
> +
> +static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
> +  if (DC->isTypeOperand())
> +    return CT_Cannot;
> +
> +  Expr *Op = DC->getExprOperand();
> +  if (Op->isTypeDependent())
> +    return CT_Dependent;
> +
> +  const RecordType *RT = Op->getType()->getAs<RecordType>();
> +  if (!RT)
> +    return CT_Cannot;
> +
> +  if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
> +    return CT_Cannot;
> +
> +  if (Op->Classify(S.Context).isPRValue())
> +    return CT_Cannot;
> +
> +  return CT_Can;
> +}
> +
> +CanThrowResult Sema::canThrow(const Expr *E) {
> +  // C++ [expr.unary.noexcept]p3:
> +  //   [Can throw] if in a potentially-evaluated context the expression
> would
> +  //   contain:
> +  switch (E->getStmtClass()) {
> +  case Expr::CXXThrowExprClass:
> +    //   - a potentially evaluated throw-expression
> +    return CT_Can;
> +
> +  case Expr::CXXDynamicCastExprClass: {
> +    //   - a potentially evaluated dynamic_cast expression
> dynamic_cast<T>(v),
> +    //     where T is a reference type, that requires a run-time check
> +    CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E));
> +    if (CT == CT_Can)
> +      return CT;
> +    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> +  }
> +
> +  case Expr::CXXTypeidExprClass:
> +    //   - a potentially evaluated typeid expression applied to a glvalue
> +    //     expression whose type is a polymorphic class type
> +    return canTypeidThrow(*this, cast<CXXTypeidExpr>(E));
> +
> +    //   - a potentially evaluated call to a function, member function,
> function
> +    //     pointer, or member function pointer that does not have a
> non-throwing
> +    //     exception-specification
> +  case Expr::CallExprClass:
> +  case Expr::CXXMemberCallExprClass:
> +  case Expr::CXXOperatorCallExprClass:
> +  case Expr::UserDefinedLiteralClass: {
> +    const CallExpr *CE = cast<CallExpr>(E);
> +    CanThrowResult CT;
> +    if (E->isTypeDependent())
> +      CT = CT_Dependent;
> +    else if
> (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
> +      CT = CT_Cannot;
> +    else
> +      CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
> +    if (CT == CT_Can)
> +      return CT;
> +    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> +  }
> +
> +  case Expr::CXXConstructExprClass:
> +  case Expr::CXXTemporaryObjectExprClass: {
> +    CanThrowResult CT = canCalleeThrow(*this, E,
> +        cast<CXXConstructExpr>(E)->getConstructor());
> +    if (CT == CT_Can)
> +      return CT;
> +    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> +  }
> +
> +  case Expr::LambdaExprClass: {
> +    const LambdaExpr *Lambda = cast<LambdaExpr>(E);
> +    CanThrowResult CT = CT_Cannot;
> +    for (LambdaExpr::capture_init_iterator Cap =
> Lambda->capture_init_begin(),
> +                                        CapEnd =
> Lambda->capture_init_end();
> +         Cap != CapEnd; ++Cap)
> +      CT = mergeCanThrow(CT, canThrow(*Cap));
> +    return CT;
> +  }
> +
> +  case Expr::CXXNewExprClass: {
> +    CanThrowResult CT;
> +    if (E->isTypeDependent())
> +      CT = CT_Dependent;
> +    else
> +      CT = canCalleeThrow(*this, E,
> cast<CXXNewExpr>(E)->getOperatorNew());
> +    if (CT == CT_Can)
> +      return CT;
> +    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> +  }
> +
> +  case Expr::CXXDeleteExprClass: {
> +    CanThrowResult CT;
> +    QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType();
> +    if (DTy.isNull() || DTy->isDependentType()) {
> +      CT = CT_Dependent;
> +    } else {
> +      CT = canCalleeThrow(*this, E,
> +                          cast<CXXDeleteExpr>(E)->getOperatorDelete());
> +      if (const RecordType *RT = DTy->getAs<RecordType>()) {
> +        const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
> +        CT = mergeCanThrow(CT, canCalleeThrow(*this, E,
> RD->getDestructor()));
> +      }
> +      if (CT == CT_Can)
> +        return CT;
> +    }
> +    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> +  }
> +
> +  case Expr::CXXBindTemporaryExprClass: {
> +    // The bound temporary has to be destroyed again, which might throw.
> +    CanThrowResult CT = canCalleeThrow(*this, E,
> +      cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor());
> +    if (CT == CT_Can)
> +      return CT;
> +    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> +  }
> +
> +    // ObjC message sends are like function calls, but never have
> exception
> +    // specs.
> +  case Expr::ObjCMessageExprClass:
> +  case Expr::ObjCPropertyRefExprClass:
> +  case Expr::ObjCSubscriptRefExprClass:
> +    return CT_Can;
> +
> +    // All the ObjC literals that are implemented as calls are
> +    // potentially throwing unless we decide to close off that
> +    // possibility.
> +  case Expr::ObjCArrayLiteralClass:
> +  case Expr::ObjCDictionaryLiteralClass:
> +  case Expr::ObjCNumericLiteralClass:
> +    return CT_Can;
> +
> +    // Many other things have subexpressions, so we have to test those.
> +    // Some are simple:
> +  case Expr::ConditionalOperatorClass:
> +  case Expr::CompoundLiteralExprClass:
> +  case Expr::CXXConstCastExprClass:
> +  case Expr::CXXDefaultArgExprClass:
> +  case Expr::CXXReinterpretCastExprClass:
> +  case Expr::DesignatedInitExprClass:
> +  case Expr::ExprWithCleanupsClass:
> +  case Expr::ExtVectorElementExprClass:
> +  case Expr::InitListExprClass:
> +  case Expr::MemberExprClass:
> +  case Expr::ObjCIsaExprClass:
> +  case Expr::ObjCIvarRefExprClass:
> +  case Expr::ParenExprClass:
> +  case Expr::ParenListExprClass:
> +  case Expr::ShuffleVectorExprClass:
> +  case Expr::VAArgExprClass:
> +    return canSubExprsThrow(*this, E);
> +
> +    // Some might be dependent for other reasons.
> +  case Expr::ArraySubscriptExprClass:
> +  case Expr::BinaryOperatorClass:
> +  case Expr::CompoundAssignOperatorClass:
> +  case Expr::CStyleCastExprClass:
> +  case Expr::CXXStaticCastExprClass:
> +  case Expr::CXXFunctionalCastExprClass:
> +  case Expr::ImplicitCastExprClass:
> +  case Expr::MaterializeTemporaryExprClass:
> +  case Expr::UnaryOperatorClass: {
> +    CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot;
> +    return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> +  }
> +
> +    // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of
> worms.
> +  case Expr::StmtExprClass:
> +    return CT_Can;
> +
> +  case Expr::ChooseExprClass:
> +    if (E->isTypeDependent() || E->isValueDependent())
> +      return CT_Dependent;
> +    return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr(Context));
> +
> +  case Expr::GenericSelectionExprClass:
> +    if (cast<GenericSelectionExpr>(E)->isResultDependent())
> +      return CT_Dependent;
> +    return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr());
> +
> +    // Some expressions are always dependent.
> +  case Expr::CXXDependentScopeMemberExprClass:
> +  case Expr::CXXUnresolvedConstructExprClass:
> +  case Expr::DependentScopeDeclRefExprClass:
> +    return CT_Dependent;
> +
> +  case Expr::AsTypeExprClass:
> +  case Expr::BinaryConditionalOperatorClass:
> +  case Expr::BlockExprClass:
> +  case Expr::CUDAKernelCallExprClass:
> +  case Expr::DeclRefExprClass:
> +  case Expr::ObjCBridgedCastExprClass:
> +  case Expr::ObjCIndirectCopyRestoreExprClass:
> +  case Expr::ObjCProtocolExprClass:
> +  case Expr::ObjCSelectorExprClass:
> +  case Expr::OffsetOfExprClass:
> +  case Expr::PackExpansionExprClass:
> +  case Expr::PseudoObjectExprClass:
> +  case Expr::SubstNonTypeTemplateParmExprClass:
> +  case Expr::SubstNonTypeTemplateParmPackExprClass:
> +  case Expr::UnaryExprOrTypeTraitExprClass:
> +  case Expr::UnresolvedLookupExprClass:
> +  case Expr::UnresolvedMemberExprClass:
> +    // FIXME: Can any of the above throw?  If so, when?
> +    return CT_Cannot;
> +
> +  case Expr::AddrLabelExprClass:
> +  case Expr::ArrayTypeTraitExprClass:
> +  case Expr::AtomicExprClass:
> +  case Expr::BinaryTypeTraitExprClass:
> +  case Expr::TypeTraitExprClass:
> +  case Expr::CXXBoolLiteralExprClass:
> +  case Expr::CXXNoexceptExprClass:
> +  case Expr::CXXNullPtrLiteralExprClass:
> +  case Expr::CXXPseudoDestructorExprClass:
> +  case Expr::CXXScalarValueInitExprClass:
> +  case Expr::CXXThisExprClass:
> +  case Expr::CXXUuidofExprClass:
> +  case Expr::CharacterLiteralClass:
> +  case Expr::ExpressionTraitExprClass:
> +  case Expr::FloatingLiteralClass:
> +  case Expr::GNUNullExprClass:
> +  case Expr::ImaginaryLiteralClass:
> +  case Expr::ImplicitValueInitExprClass:
> +  case Expr::IntegerLiteralClass:
> +  case Expr::ObjCEncodeExprClass:
> +  case Expr::ObjCStringLiteralClass:
> +  case Expr::ObjCBoolLiteralExprClass:
> +  case Expr::OpaqueValueExprClass:
> +  case Expr::PredefinedExprClass:
> +  case Expr::SizeOfPackExprClass:
> +  case Expr::StringLiteralClass:
> +  case Expr::UnaryTypeTraitExprClass:
> +    // These expressions can never throw.
> +    return CT_Cannot;
> +
> +#define STMT(CLASS, PARENT) case Expr::CLASS##Class:
> +#define STMT_RANGE(Base, First, Last)
> +#define LAST_STMT_RANGE(BASE, FIRST, LAST)
> +#define EXPR(CLASS, PARENT)
> +#define ABSTRACT_STMT(STMT)
> +#include "clang/AST/StmtNodes.inc"
> +  case Expr::NoStmtClass:
> +    llvm_unreachable("Invalid class for expression");
> +  }
> +  llvm_unreachable("Bogus StmtClass");
> +}
> +
>  } // end namespace clang
>
> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Apr 16 19:58:00 2012
> @@ -9773,6 +9773,13 @@
>   // FIXME: Is this really right?
>   if (CurContext == Func) return;
>
> +  // Instantiate the exception specification for any function which is
> +  // used: CodeGen will need it.
> +  if (Func->getTemplateInstantiationPattern() &&
> +      Func->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()
> +        == EST_Uninstantiated)
> +    InstantiateExceptionSpec(Loc, Func);
> +
>   // Implicit instantiation of function templates and member functions of
>   // class templates.
>   if (Func->isImplicitlyInstantiable()) {
>
> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Apr 16 19:58:00 2012
> @@ -3135,6 +3135,9 @@
>             FoundAssign = true;
>             const FunctionProtoType *CPT
>                 = Operator->getType()->getAs<FunctionProtoType>();
> +            CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
> +            if (!CPT)
> +              return false;
>             if (CPT->getExceptionSpecType() == EST_Delayed)
>               return false;
>             if (!CPT->isNothrow(Self.Context))
> @@ -3174,6 +3177,9 @@
>           FoundConstructor = true;
>           const FunctionProtoType *CPT
>               = Constructor->getType()->getAs<FunctionProtoType>();
> +          CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
> +          if (!CPT)
> +            return false;
>           if (CPT->getExceptionSpecType() == EST_Delayed)
>             return false;
>           // FIXME: check whether evaluating default arguments can throw.
> @@ -3209,6 +3215,9 @@
>         if (Constructor->isDefaultConstructor()) {
>           const FunctionProtoType *CPT
>               = Constructor->getType()->getAs<FunctionProtoType>();
> +          CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
> +          if (!CPT)
> +            return false;
>           if (CPT->getExceptionSpecType() == EST_Delayed)
>             return false;
>           // TODO: check whether evaluating default arguments can throw.
> @@ -5203,9 +5212,9 @@
>
>  ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr
> *Operand,
>                                       SourceLocation RParen) {
> +  CanThrowResult CanThrow = canThrow(Operand);
>   return Owned(new (Context) CXXNoexceptExpr(Context.BoolTy, Operand,
> -                                             Operand->CanThrow(Context),
> -                                             KeyLoc, RParen));
> +                                             CanThrow, KeyLoc, RParen));
>  }
>
>  ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
>
> Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Apr 16 19:58:00 2012
> @@ -11150,6 +11150,7 @@
>                                            VK_LValue,
>                                            Found.getDecl(),
>                                            TemplateArgs);
> +    MarkDeclRefReferenced(DRE);
>     DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1);
>     return DRE;
>   }
> @@ -11178,6 +11179,7 @@
>                                                VK_LValue,
>                                                Found.getDecl(),
>                                                TemplateArgs);
> +        MarkDeclRefReferenced(DRE);
>         DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1);
>         return DRE;
>       } else {
>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Apr 16 19:58:00 2012
> @@ -153,6 +153,7 @@
>  bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
>   switch (Kind) {
>   case TemplateInstantiation:
> +  case ExceptionSpecInstantiation:
>   case DefaultTemplateArgumentInstantiation:
>   case DefaultFunctionArgumentInstantiation:
>     return true;
> @@ -190,6 +191,29 @@
>   }
>  }
>
> +Sema::InstantiatingTemplate::
> +InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
> +                      FunctionDecl *Entity, ExceptionSpecification,
> +                      SourceRange InstantiationRange)
> +  : SemaRef(SemaRef),
> +    SavedInNonInstantiationSFINAEContext(
> +
>  SemaRef.InNonInstantiationSFINAEContext)
> +{
> +  Invalid = CheckInstantiationDepth(PointOfInstantiation,
> +                                    InstantiationRange);
> +  if (!Invalid) {
> +    ActiveTemplateInstantiation Inst;
> +    Inst.Kind = ActiveTemplateInstantiation::ExceptionSpecInstantiation;
> +    Inst.PointOfInstantiation = PointOfInstantiation;
> +    Inst.Entity = reinterpret_cast<uintptr_t>(Entity);
> +    Inst.TemplateArgs = 0;
> +    Inst.NumTemplateArgs = 0;
> +    Inst.InstantiationRange = InstantiationRange;
> +    SemaRef.InNonInstantiationSFINAEContext = false;
> +    SemaRef.ActiveTemplateInstantiations.push_back(Inst);
> +  }
> +}
> +
>  Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
>                                          SourceLocation
> PointOfInstantiation,
>                                          TemplateDecl *Template,
> @@ -592,6 +616,13 @@
>         << Active->InstantiationRange;
>       break;
>     }
> +
> +    case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
> +      Diags.Report(Active->PointOfInstantiation,
> +                   diag::note_template_exception_spec_instantiation_here)
> +        << cast<FunctionDecl>((Decl *)Active->Entity)
> +        << Active->InstantiationRange;
> +      break;
>     }
>   }
>  }
> @@ -609,6 +640,7 @@
>     switch(Active->Kind) {
>     case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
>     case ActiveTemplateInstantiation::TemplateInstantiation:
> +    case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
>       // This is a template instantiation, so there is no SFINAE.
>       return llvm::Optional<TemplateDeductionInfo *>();
>
>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Apr 16 19:58:00
> 2012
> @@ -2215,6 +2215,194 @@
>   return NewTInfo;
>  }
>
> +/// Introduce the instantiated function parameters into the local
> +/// instantiation scope, and set the parameter names to those used
> +/// in the template.
> +static void addInstantiatedParametersToScope(Sema &S, FunctionDecl
> *Function,
> +                                             const FunctionDecl
> *PatternDecl,
> +                                             LocalInstantiationScope
> &Scope,
> +                           const MultiLevelTemplateArgumentList
> &TemplateArgs) {
> +  unsigned FParamIdx = 0;
> +  for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
> +    const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
> +    if (!PatternParam->isParameterPack()) {
> +      // Simple case: not a parameter pack.
> +      assert(FParamIdx < Function->getNumParams());
> +      ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
> +      FunctionParam->setDeclName(PatternParam->getDeclName());
> +      Scope.InstantiatedLocal(PatternParam, FunctionParam);
> +      ++FParamIdx;
> +      continue;
> +    }
> +
> +    // Expand the parameter pack.
> +    Scope.MakeInstantiatedLocalArgPack(PatternParam);
> +    unsigned NumArgumentsInExpansion
> +      = S.getNumArgumentsInExpansion(PatternParam->getType(),
> TemplateArgs);
> +    for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) {
> +      ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
> +      FunctionParam->setDeclName(PatternParam->getDeclName());
> +      Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
> +      ++FParamIdx;
> +    }
> +  }
> +}
> +
> +static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
> +                                     const FunctionProtoType *Proto,
> +                           const MultiLevelTemplateArgumentList
> &TemplateArgs) {
> +  // 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
> +  //   "pointer to cv-qualifier-seq X" between the optional
> cv-qualifer-seq
> +  //   and the end of the function-definition, member-declarator, or
> +  //   declarator.
> +  CXXRecordDecl *ThisContext = 0;
> +  unsigned ThisTypeQuals = 0;
> +  if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) {
> +    ThisContext = Method->getParent();
> +    ThisTypeQuals = Method->getTypeQualifiers();
> +  }
> +  Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,
> +                                   SemaRef.getLangOpts().CPlusPlus0x);
> +
> +  // The function has an exception specification or a "noreturn"
> +  // attribute. Substitute into each of the exception types.
> +  SmallVector<QualType, 4> Exceptions;
> +  for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) {
> +    // FIXME: Poor location information!
> +    if (const PackExpansionType *PackExpansion
> +          = Proto->getExceptionType(I)->getAs<PackExpansionType>()) {
> +      // We have a pack expansion. Instantiate it.
> +      SmallVector<UnexpandedParameterPack, 2> Unexpanded;
> +      SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
> +                                              Unexpanded);
> +      assert(!Unexpanded.empty() &&
> +             "Pack expansion without parameter packs?");
> +
> +      bool Expand = false;
> +      bool RetainExpansion = false;
> +      llvm::Optional<unsigned> NumExpansions
> +                                        =
> PackExpansion->getNumExpansions();
> +      if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
> +                                                  SourceRange(),
> +                                                  Unexpanded,
> +                                                  TemplateArgs,
> +                                                  Expand,
> +                                                  RetainExpansion,
> +                                                  NumExpansions))
> +        break;
> +
> +      if (!Expand) {
> +        // We can't expand this pack expansion into separate arguments
> yet;
> +        // just substitute into the pattern and create a new pack
> expansion
> +        // type.
> +        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
> +        QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
> +                                       TemplateArgs,
> +                                     New->getLocation(),
> New->getDeclName());
> +        if (T.isNull())
> +          break;
> +
> +        T = SemaRef.Context.getPackExpansionType(T, NumExpansions);
> +        Exceptions.push_back(T);
> +        continue;
> +      }
> +
> +      // Substitute into the pack expansion pattern for each template
> +      bool Invalid = false;
> +      for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
> +        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef,
> ArgIdx);
> +
> +        QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
> +                                       TemplateArgs,
> +                                     New->getLocation(),
> New->getDeclName());
> +        if (T.isNull()) {
> +          Invalid = true;
> +          break;
> +        }
> +
> +        Exceptions.push_back(T);
> +      }
> +
> +      if (Invalid)
> +        break;
> +
> +      continue;
> +    }
> +
> +    QualType T
> +      = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,
> +                          New->getLocation(), New->getDeclName());
> +    if (T.isNull() ||
> +        SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))
> +      continue;
> +
> +    Exceptions.push_back(T);
> +  }
> +  Expr *NoexceptExpr = 0;
> +  if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
> +    EnterExpressionEvaluationContext Unevaluated(SemaRef,
> +                                                 Sema::ConstantEvaluated);
> +    ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
> +    if (E.isUsable())
> +      E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart());
> +
> +    if (E.isUsable()) {
> +      NoexceptExpr = E.take();
> +      if (!NoexceptExpr->isTypeDependent() &&
> +          !NoexceptExpr->isValueDependent())
> +        NoexceptExpr =
> SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,
> +          0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression),
> +          /*AllowFold*/ false).take();
> +    }
> +  }
> +
> +  // Rebuild the function type
> +  const FunctionProtoType *NewProto
> +    = New->getType()->getAs<FunctionProtoType>();
> +  assert(NewProto && "Template instantiation without function
> prototype?");
> +
> +  FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
> +  EPI.ExceptionSpecType = Proto->getExceptionSpecType();
> +  EPI.NumExceptions = Exceptions.size();
> +  EPI.Exceptions = Exceptions.data();
> +  EPI.NoexceptExpr = NoexceptExpr;
> +
> +  New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
> +                                               NewProto->arg_type_begin(),
> +                                               NewProto->getNumArgs(),
> +                                               EPI));
> +}
> +
> +void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
> +                                    FunctionDecl *Decl) {
> +  FunctionDecl *Tmpl = Decl->getTemplateInstantiationPattern();
> +  assert(Tmpl && "can't instantiate non-template");
> +
> +  if (Decl->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()
> +        != EST_Uninstantiated)
> +    return;
> +
> +  InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,
> +
> InstantiatingTemplate::ExceptionSpecification());
> +  if (Inst)
> +    return;
> +
> +  // Enter the scope of this instantiation. We don't use
> +  // PushDeclContext because we don't have a scope.
> +  Sema::ContextRAII savedContext(*this, Decl);
> +  LocalInstantiationScope Scope(*this);
> +
> +  MultiLevelTemplateArgumentList TemplateArgs =
> +    getTemplateInstantiationArgs(Decl, 0, /*RelativeToPrimary*/true);
> +
> +  addInstantiatedParametersToScope(*this, Decl, Tmpl, Scope,
> TemplateArgs);
> +
> +  const FunctionProtoType *Proto =
> Tmpl->getType()->castAs<FunctionProtoType>();
> +  ::InstantiateExceptionSpec(*this, Decl, Proto, TemplateArgs);
> +}
> +
>  /// \brief Initializes the common fields of an instantiation function
>  /// declaration (New) from the corresponding fields of its template
> (Tmpl).
>  ///
> @@ -2252,135 +2440,32 @@
>   assert(Proto && "Function template without prototype?");
>
>   if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) {
> -    // 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
> -    //   "pointer to cv-qualifier-seq X" between the optional
> cv-qualifer-seq
> -    //   and the end of the function-definition, member-declarator, or
> -    //   declarator.
> -    CXXRecordDecl *ThisContext = 0;
> -    unsigned ThisTypeQuals = 0;
> -    if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) {
> -      ThisContext = Method->getParent();
> -      ThisTypeQuals = Method->getTypeQualifiers();
> -    }
> -    Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,
> -                                     SemaRef.getLangOpts().CPlusPlus0x);
> -
> -
> -    // The function has an exception specification or a "noreturn"
> -    // attribute. Substitute into each of the exception types.
> -    SmallVector<QualType, 4> Exceptions;
> -    for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) {
> -      // FIXME: Poor location information!
> -      if (const PackExpansionType *PackExpansion
> -            = Proto->getExceptionType(I)->getAs<PackExpansionType>()) {
> -        // We have a pack expansion. Instantiate it.
> -        SmallVector<UnexpandedParameterPack, 2> Unexpanded;
> -
>  SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
> -                                                Unexpanded);
> -        assert(!Unexpanded.empty() &&
> -               "Pack expansion without parameter packs?");
> -
> -        bool Expand = false;
> -        bool RetainExpansion = false;
> -        llvm::Optional<unsigned> NumExpansions
> -                                          =
> PackExpansion->getNumExpansions();
> -        if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
> -                                                    SourceRange(),
> -                                                    Unexpanded,
> -                                                    TemplateArgs,
> -                                                    Expand,
> -                                                    RetainExpansion,
> -                                                    NumExpansions))
> -          break;
> -
> -        if (!Expand) {
> -          // We can't expand this pack expansion into separate arguments
> yet;
> -          // just substitute into the pattern and create a new pack
> expansion
> -          // type.
> -          Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
> -          QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
> -                                         TemplateArgs,
> -                                       New->getLocation(),
> New->getDeclName());
> -          if (T.isNull())
> -            break;
> -
> -          T = SemaRef.Context.getPackExpansionType(T, NumExpansions);
> -          Exceptions.push_back(T);
> -          continue;
> -        }
> -
> -        // Substitute into the pack expansion pattern for each template
> -        bool Invalid = false;
> -        for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
> -          Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef,
> ArgIdx);
> -
> -          QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
> -                                         TemplateArgs,
> -                                       New->getLocation(),
> New->getDeclName());
> -          if (T.isNull()) {
> -            Invalid = true;
> -            break;
> -          }
> -
> -          Exceptions.push_back(T);
> -        }
> -
> -        if (Invalid)
> -          break;
> -
> -        continue;
> -      }
> -
> -      QualType T
> -        = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,
> -                            New->getLocation(), New->getDeclName());
> -      if (T.isNull() ||
> -          SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))
> -        continue;
> +    FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
>
> -      Exceptions.push_back(T);
> -    }
> -    Expr *NoexceptExpr = 0;
> -    if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
> -      EnterExpressionEvaluationContext Unevaluated(SemaRef,
> -
> Sema::ConstantEvaluated);
> -      ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
> -      if (E.isUsable())
> -        E = SemaRef.CheckBooleanCondition(E.get(),
> E.get()->getLocStart());
> -
> -      if (E.isUsable()) {
> -        NoexceptExpr = E.take();
> -        if (!NoexceptExpr->isTypeDependent() &&
> -            !NoexceptExpr->isValueDependent())
> -          NoexceptExpr =
> SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,
> -            0,
> SemaRef.PDiag(diag::err_noexcept_needs_constant_expression),
> -            /*AllowFold*/ false).take();
> -      }
> +    // DR1330: In C++11, defer instantiation of a non-trivial
> +    // exception specification.
> +    if (SemaRef.getLangOpts().CPlusPlus0x &&
> +        EPI.ExceptionSpecType != EST_None &&
> +        EPI.ExceptionSpecType != EST_DynamicNone &&
> +        EPI.ExceptionSpecType != EST_BasicNoexcept) {
> +      // Mark the function has having an uninstantiated exception
> specification.
> +      const FunctionProtoType *NewProto
> +        = New->getType()->getAs<FunctionProtoType>();
> +      assert(NewProto && "Template instantiation without function
> prototype?");
> +      EPI = NewProto->getExtProtoInfo();
> +      EPI.ExceptionSpecType = EST_Uninstantiated;
> +      EPI.ExceptionSpecDecl = New;
> +
>  New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
> +
> NewProto->arg_type_begin(),
> +                                                   NewProto->getNumArgs(),
> +                                                   EPI));
> +    } else {
> +      ::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);
>     }
> -
> -    // Rebuild the function type
> -
> -    FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
> -    EPI.ExceptionSpecType = Proto->getExceptionSpecType();
> -    EPI.NumExceptions = Exceptions.size();
> -    EPI.Exceptions = Exceptions.data();
> -    EPI.NoexceptExpr = NoexceptExpr;
> -    EPI.ExtInfo = Proto->getExtInfo();
> -
> -    const FunctionProtoType *NewProto
> -      = New->getType()->getAs<FunctionProtoType>();
> -    assert(NewProto && "Template instantiation without function
> prototype?");
> -
>  New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
> -
> NewProto->arg_type_begin(),
> -                                                 NewProto->getNumArgs(),
> -                                                 EPI));
>   }
>
> -  const FunctionDecl* Definition = Tmpl;
> -
>   // Get the definition. Leaves the variable unchanged if undefined.
> +  const FunctionDecl *Definition = Tmpl;
>   Tmpl->isDefined(Definition);
>
>   SemaRef.InstantiateAttrs(TemplateArgs, Definition, New,
> @@ -2538,33 +2623,8 @@
>   MultiLevelTemplateArgumentList TemplateArgs =
>     getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
>
> -  // Introduce the instantiated function parameters into the local
> -  // instantiation scope, and set the parameter names to those used
> -  // in the template.
> -  unsigned FParamIdx = 0;
> -  for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
> -    const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
> -    if (!PatternParam->isParameterPack()) {
> -      // Simple case: not a parameter pack.
> -      assert(FParamIdx < Function->getNumParams());
> -      ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
> -      FunctionParam->setDeclName(PatternParam->getDeclName());
> -      Scope.InstantiatedLocal(PatternParam, FunctionParam);
> -      ++FParamIdx;
> -      continue;
> -    }
> -
> -    // Expand the parameter pack.
> -    Scope.MakeInstantiatedLocalArgPack(PatternParam);
> -    unsigned NumArgumentsInExpansion
> -      = getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
> -    for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) {
> -      ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
> -      FunctionParam->setDeclName(PatternParam->getDeclName());
> -      Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
> -      ++FParamIdx;
> -    }
> -  }
> +  addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
> +                                   TemplateArgs);
>
>   if (PatternDecl->isDefaulted()) {
>     ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);
>
> Modified: cfe/trunk/lib/Sema/TreeTransform.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/TreeTransform.h (original)
> +++ cfe/trunk/lib/Sema/TreeTransform.h Mon Apr 16 19:58:00 2012
> @@ -4181,10 +4181,7 @@
>                                                    unsigned ThisTypeQuals)
> {
>   // Transform the parameters and return type.
>   //
> -  // We instantiate in source order, with the return type first followed
> by
> -  // the parameters, because users tend to expect this (even if they
> shouldn't
> -  // rely on it!).
> -  //
> +  // We are required to instantiate the params and return type in source
> order.
>   // When the function has a trailing return type, we instantiate the
>   // parameters before the return type,  since the return type can then
> refer
>   // to the parameters themselves (via decltype, sizeof, etc.).
> @@ -4230,6 +4227,8 @@
>       return QualType();
>   }
>
> +  // FIXME: Need to transform the exception-specification too.
> +
>   QualType Result = TL.getType();
>   if (getDerived().AlwaysRebuild() ||
>       ResultType != T->getResultType() ||
>
> Modified: cfe/trunk/test/CXX/except/except.spec/p1.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p1.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CXX/except/except.spec/p1.cpp (original)
> +++ cfe/trunk/test/CXX/except/except.spec/p1.cpp Mon Apr 16 19:58:00 2012
> @@ -65,7 +65,7 @@
>   }
>
>   template<typename T>
> -  void g(T x) noexcept((sizeof(T) == sizeof(int)) || f(x)) { }
> +  void g(T x) noexcept((sizeof(T) == sizeof(int)) || noexcept(f(x))) { }
>
>   void h() {
>     g(1);
> @@ -77,5 +77,5 @@
>     static int f() noexcept(1/X) { return 10; }  //
> expected-error{{argument to noexcept specifier must be a constant
> expression}} expected-note{{division by zero}}
>   };
>
> -  void g() { A<0>::f(); } // expected-note{{in instantiation of template
> class 'PR11084::A<0>' requested here}}
> +  void g() { A<0>::f(); } // expected-note{{in instantiation of exception
> specification for 'f' requested here}}
>  }
>
> Added: cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp?rev=154886&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp (added)
> +++ cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp Mon Apr 16 19:58:00
> 2012
> @@ -0,0 +1,18 @@
> +// RUN: %clang_cc1 -std=c++11 -verify -emit-llvm %s -o - | FileCheck %s
> +
> +template<typename T> void f() noexcept(sizeof(T) == 4);
> +
> +void g() {
> +  // CHECK: declare void @_Z1fIiEvv() nounwind
> +  f<int>();
> +  // CHECK: declare void @_Z1fIA2_iEvv()
> +  f<int[2]>();
> +  // CHECK: declare void @_Z1fIfEvv() nounwind
> +  void (*f1)() = &f<float>;
> +  // CHECK: declare void @_Z1fIdEvv()
> +  void (*f2)() = &f<double>;
> +  // CHECK: declare void @_Z1fIA4_cEvv() nounwind
> +  (void)&f<char[4]>;
> +  // CHECK: declare void @_Z1fIcEvv()
> +  (void)&f<char>;
> +}
>
> Modified: cfe/trunk/test/SemaTemplate/instantiate-declref.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-declref.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/SemaTemplate/instantiate-declref.cpp (original)
> +++ cfe/trunk/test/SemaTemplate/instantiate-declref.cpp Mon Apr 16
> 19:58:00 2012
> @@ -105,3 +105,13 @@
>   }
>   template void f(int const &); // expected-note {{requested here}}
>  }
> +
> +namespace test2 {
> +  template<typename T> void f() {
> +    T::error; // expected-error {{no member}}
> +  }
> +  void g() {
> +    // This counts as an odr-use, so should trigger the instantiation of
> f<int>.
> +    (void)&f<int>; // expected-note {{here}}
> +  }
> +}
>
> Added: 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=154886&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
> (added)
> +++ cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp Mon
> Apr 16 19:58:00 2012
> @@ -0,0 +1,107 @@
> +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 %s
> +
> +// DR1330: an exception specification for a function template is only
> +// instantiated when it is needed.
> +
> +template<typename T> void f1(T*) throw(T); // expected-error{{incomplete
> type 'Incomplete' is not allowed in exception specification}}
> +struct Incomplete; // expected-note{{forward}}
> +
> +void test_f1(Incomplete *incomplete_p, int *int_p) {
> +  f1(int_p);
> +  f1(incomplete_p); // expected-note{{instantiation of exception spec}}
> +}
> +
> +template<typename T> struct A {
> +  template<typename U> struct B {
> +    static void f() noexcept(A<U>().n);
> +  };
> +
> +  constexpr A() : n(true) {}
> +  bool n;
> +};
> +
> +static_assert(noexcept(A<int>::B<char>::f()), "");
> +
> +template<unsigned N> struct S {
> +  static void recurse() noexcept(noexcept(S<N+1>::recurse())); // \
> +  // expected-error {{no member named 'recurse'}} \
> +  // expected-note 9{{instantiation of exception spec}}
> +};
> +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}}
> +
> +
> +template<typename T> T go(T a) noexcept(noexcept(go(a))); // \
> +// expected-error 16{{call to function 'go' that is neither visible}} \
> +// expected-note 16{{'go' should be declared prior to the call site}} \
> +// expected-error {{recursive template instantiation exceeded maximum
> depth of 16}} \
> +// expected-error {{use of undeclared identifier 'go'}} \
> +
> +void f() {
> +  int k = go(0); // \
> +  // expected-note {{in instantiation of exception specification for
> 'go<int>' requested here}}
> +}
> +
> +
> +namespace dr1330_example {
> +  template <class T> struct A {
> +    void f(...) throw (typename T::X); // expected-error {{'int'}}
> +    void f(int);
> +  };
> +
> +  int main() {
> +    A<int>().f(42);
> +  }
> +
> +  int test2() {
> +    struct S {
> +      template<typename T>
> +      static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; }
> // \
> +      // expected-note {{instantiation of exception spec}}
> +      typedef decltype(f<S>()) X;
> +    };
> +    S().f<S>(); // ok
> +    S().f<int>(); // expected-note {{instantiation of exception spec}}
> +  }
> +}
> +
> +namespace core_19754_example {
> +  template<typename T> T declval() noexcept;
> +
> +  template<typename T, typename = decltype(T(declval<T&&>()))>
> +  struct is_movable { static const bool value = true; };
> +
> +  template<typename T>
> +  struct wrap {
> +    T val;
> +    void irrelevant(wrap &p) noexcept(is_movable<T>::value);
> +  };
> +
> +  template<typename T>
> +  struct base {
> +     base() {}
> +     base(const typename T::type1 &);
> +     base(const typename T::type2 &);
> +  };
> +
> +  template<typename T>
> +  struct type1 {
> +     wrap<typename T::base> base;
> +  };
> +
> +  template<typename T>
> +  struct type2 {
> +     wrap<typename T::base> base;
> +  };
> +
> +  struct types {
> +     typedef base<types> base;
> +     typedef type1<types> type1;
> +     typedef type2<types> type2;
> +  };
> +
> +  base<types> val = base<types>();
> +}
>
>
> _______________________________________________
> 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/20120418/f4c5a3ee/attachment.html>


More information about the cfe-commits mailing list