<br><br><div class="gmail_quote">Le 17 avril 2012 02:58, Richard Smith <span dir="ltr"><<a href="mailto:richard-llvm@metafoo.co.uk">richard-llvm@metafoo.co.uk</a>></span> a écrit :<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Author: rsmith<br>
Date: Mon Apr 16 19:58:00 2012<br>
New Revision: 154886<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=154886&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=154886&view=rev</a><br>
Log:<br>
Implement DR1330 in C++11 mode, to support libstdc++4.7 which uses it.<br>
<br>
We have a new flavor of exception specification, EST_Uninstantiated. A function<br>
type with this exception specification carries a pointer to a FunctionDecl, and<br>
the exception specification for that FunctionDecl is instantiated (if needed)<br>
and used in the place of the function type's exception specification.<br>
<br>
When a function template declaration with a non-trivial exception specification<br>
is instantiated, the specialization's exception specification is set to this<br>
new 'uninstantiated' kind rather than being instantiated immediately.<br>
<br>
Expr::CanThrow has migrated onto Sema, so it can instantiate exception specs<br>
on-demand. Also, any odr-use of a function triggers the instantiation of its<br>
exception specification (the exception specification could be needed by IRGen).<br>
In passing, fix two places where a DeclRefExpr was created but the corresponding<br>
function was not actually marked odr-used. We used to get away with this, but<br>
don't any more.<br>
<br>
Also fix a bug where instantiating an exception specification which refers to<br>
function parameters resulted in a crash. We still have the same bug in default<br>
arguments, which I'll be looking into next.<br>
<br>
This, plus a tiny patch to fix libstdc++'s common_type, is enough for clang to<br>
parse (and, in very limited testing, support) all of libstdc++4.7's standard<br>
headers.<br>
<br></blockquote><div><br>Will it be available in Clang 3.1 ?<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Added:<br>
    cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp<br>
    cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp<br>
Modified:<br>
    cfe/trunk/include/clang/AST/Expr.h<br>
    cfe/trunk/include/clang/AST/Type.h<br>
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
    cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h<br>
    cfe/trunk/include/clang/Sema/Sema.h<br>
    cfe/trunk/lib/AST/ASTContext.cpp<br>
    cfe/trunk/lib/AST/Expr.cpp<br>
    cfe/trunk/lib/AST/Type.cpp<br>
    cfe/trunk/lib/Analysis/CFG.cpp<br>
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp<br>
    cfe/trunk/lib/Sema/SemaExpr.cpp<br>
    cfe/trunk/lib/Sema/SemaExprCXX.cpp<br>
    cfe/trunk/lib/Sema/SemaOverload.cpp<br>
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp<br>
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
    cfe/trunk/lib/Sema/TreeTransform.h<br>
    cfe/trunk/test/CXX/except/except.spec/p1.cpp<br>
    cfe/trunk/test/SemaTemplate/instantiate-declref.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/Expr.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/include/clang/AST/Expr.h (original)<br>
+++ cfe/trunk/include/clang/AST/Expr.h Mon Apr 16 19:58:00 2012<br>
@@ -581,16 +581,6 @@<br>
   /// member expression.<br>
   static QualType findBoundMemberType(const Expr *expr);<br>
<br>
-  /// \brief Result type of CanThrow().<br>
-  enum CanThrowResult {<br>
-    CT_Cannot,<br>
-    CT_Dependent,<br>
-    CT_Can<br>
-  };<br>
-  /// \brief Test if this expression, if evaluated, might throw, according to<br>
-  ///        the rules of C++ [expr.unary.noexcept].<br>
-  CanThrowResult CanThrow(ASTContext &C) const;<br>
-<br>
   /// IgnoreImpCasts - Skip past any implicit casts which might<br>
   /// surround this expression.  Only skips ImplicitCastExprs.<br>
   Expr *IgnoreImpCasts() LLVM_READONLY;<br>
<br>
Modified: cfe/trunk/include/clang/AST/Type.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/include/clang/AST/Type.h (original)<br>
+++ cfe/trunk/include/clang/AST/Type.h Mon Apr 16 19:58:00 2012<br>
@@ -79,6 +79,7 @@<br>
   class CXXRecordDecl;<br>
   class EnumDecl;<br>
   class FieldDecl;<br>
+  class FunctionDecl;<br>
   class ObjCInterfaceDecl;<br>
   class ObjCProtocolDecl;<br>
   class ObjCMethodDecl;<br>
@@ -2700,7 +2701,8 @@<br>
     ExtProtoInfo() :<br>
       Variadic(false), HasTrailingReturn(false), TypeQuals(0),<br>
       ExceptionSpecType(EST_None), RefQualifier(RQ_None),<br>
-      NumExceptions(0), Exceptions(0), NoexceptExpr(0), ConsumedArguments(0) {}<br>
+      NumExceptions(0), Exceptions(0), NoexceptExpr(0), ExceptionSpecDecl(0),<br>
+      ConsumedArguments(0) {}<br>
<br>
     FunctionType::ExtInfo ExtInfo;<br>
     bool Variadic : 1;<br>
@@ -2711,6 +2713,7 @@<br>
     unsigned NumExceptions;<br>
     const QualType *Exceptions;<br>
     Expr *NoexceptExpr;<br>
+    FunctionDecl *ExceptionSpecDecl;<br>
     const bool *ConsumedArguments;<br>
   };<br>
<br>
@@ -2756,6 +2759,10 @@<br>
   // NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing<br>
   // to the expression in the noexcept() specifier.<br>
<br>
+  // ExceptionSpecDecl - Instead of Exceptions, there may be a single<br>
+  // FunctionDecl* pointing to the function which should be used to resolve<br>
+  // this function type's exception specification.<br>
+<br>
   // ConsumedArgs - A variable size array, following Exceptions<br>
   // and of length NumArgs, holding flags indicating which arguments<br>
   // are consumed.  This only appears if HasAnyConsumedArgs is true.<br>
@@ -2795,6 +2802,8 @@<br>
       EPI.Exceptions = exception_begin();<br>
     } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {<br>
       EPI.NoexceptExpr = getNoexceptExpr();<br>
+    } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {<br>
+      EPI.ExceptionSpecDecl = getExceptionSpecDecl();<br>
     }<br>
     if (hasAnyConsumedArgs())<br>
       EPI.ConsumedArguments = getConsumedArgsBuffer();<br>
@@ -2838,9 +2847,14 @@<br>
     // NoexceptExpr sits where the arguments end.<br>
     return *reinterpret_cast<Expr *const *>(arg_type_end());<br>
   }<br>
+  FunctionDecl *getExceptionSpecDecl() const {<br>
+    if (getExceptionSpecType() != EST_Uninstantiated)<br>
+      return 0;<br>
+    return *reinterpret_cast<FunctionDecl * const *>(arg_type_end());<br>
+  }<br>
   bool isNothrow(ASTContext &Ctx) const {<br>
     ExceptionSpecificationType EST = getExceptionSpecType();<br>
-    assert(EST != EST_Delayed);<br>
+    assert(EST != EST_Delayed && EST != EST_Uninstantiated);<br>
     if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)<br>
       return true;<br>
     if (EST != EST_ComputedNoexcept)<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Apr 16 19:58:00 2012<br>
@@ -2583,6 +2583,8 @@<br>
   "in instantiation of enumeration %q0 requested here">;<br>
 def note_template_type_alias_instantiation_here : Note<<br>
   "in instantiation of template type alias %0 requested here">;<br>
+def note_template_exception_spec_instantiation_here : Note<<br>
+  "in instantiation of exception specification for %0 requested here">;<br>
<br>
 def note_default_arg_instantiation_here : Note<<br>
   "in instantiation of default argument for '%0' required here">;<br>
<br>
Modified: cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h (original)<br>
+++ cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h Mon Apr 16 19:58:00 2012<br>
@@ -16,7 +16,7 @@<br>
<br>
 namespace clang {<br>
<br>
-/// \brief The various types of exception specifications that exist in C++0x.<br>
+/// \brief The various types of exception specifications that exist in C++11.<br>
 enum ExceptionSpecificationType {<br>
   EST_None,             ///< no exception specification<br>
   EST_DynamicNone,      ///< throw()<br>
@@ -24,7 +24,8 @@<br>
   EST_MSAny,            ///< Microsoft throw(...) extension<br>
   EST_BasicNoexcept,    ///< noexcept<br>
   EST_ComputedNoexcept, ///< noexcept(expression)<br>
-  EST_Delayed           ///< not known yet<br>
+  EST_Delayed,          ///< not known yet<br>
+  EST_Uninstantiated    ///< not instantiated yet<br>
 };<br>
<br>
 inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {<br>
@@ -35,6 +36,19 @@<br>
   return ESpecType == EST_BasicNoexcept || ESpecType == EST_ComputedNoexcept;<br>
 }<br>
<br>
+/// \brief Possible results from evaluation of a noexcept expression.<br>
+enum CanThrowResult {<br>
+  CT_Cannot,<br>
+  CT_Dependent,<br>
+  CT_Can<br>
+};<br>
+<br>
+inline CanThrowResult mergeCanThrow(CanThrowResult CT1, CanThrowResult CT2) {<br>
+  // CanThrowResult constants are ordered so that the maximum is the correct<br>
+  // merge result.<br>
+  return CT1 > CT2 ? CT1 : CT2;<br>
+}<br>
+<br>
 } // end namespace clang<br>
<br>
 #endif // LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H<br>
<br>
Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Apr 16 19:58:00 2012<br>
@@ -907,6 +907,9 @@<br>
   DeclarationNameInfo GetNameForDeclarator(Declarator &D);<br>
   DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name);<br>
   static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo = 0);<br>
+  CanThrowResult canThrow(const Expr *E);<br>
+  const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,<br>
+                                                const FunctionProtoType *FPT);<br>
   bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);<br>
   bool CheckDistantExceptionSpec(QualType T);<br>
   bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);<br>
@@ -3050,7 +3053,7 @@<br>
   /// implicitly-declared special member functions.<br>
   class ImplicitExceptionSpecification {<br>
     // Pointer to allow copying<br>
-    ASTContext *Context;<br>
+    Sema *Self;<br>
     // We order exception specifications thus:<br>
     // noexcept is the most restrictive, but is only used in C++0x.<br>
     // throw() comes next.<br>
@@ -3074,9 +3077,9 @@<br>
     }<br>
<br>
   public:<br>
-    explicit ImplicitExceptionSpecification(ASTContext &Context)<br>
-      : Context(&Context), ComputedEST(EST_BasicNoexcept) {<br>
-      if (!Context.getLangOpts().CPlusPlus0x)<br>
+    explicit ImplicitExceptionSpecification(Sema &Self)<br>
+      : Self(&Self), ComputedEST(EST_BasicNoexcept) {<br>
+      if (!Self.Context.getLangOpts().CPlusPlus0x)<br>
         ComputedEST = EST_DynamicNone;<br>
     }<br>
<br>
@@ -3094,7 +3097,7 @@<br>
     const QualType *data() const { return Exceptions.data(); }<br>
<br>
     /// \brief Integrate another called method into the collected data.<br>
-    void CalledDecl(CXXMethodDecl *Method);<br>
+    void CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method);<br>
<br>
     /// \brief Integrate an invoked expression into the collected data.<br>
     void CalledExpr(Expr *E);<br>
@@ -5194,7 +5197,11 @@<br>
<br>
       /// We are checking the validity of a default template argument that<br>
       /// has been used when naming a template-id.<br>
-      DefaultTemplateArgumentChecking<br>
+      DefaultTemplateArgumentChecking,<br>
+<br>
+      /// We are instantiating the exception specification for a function<br>
+      /// template which was deferred until it was needed.<br>
+      ExceptionSpecInstantiation<br>
     } Kind;<br>
<br>
     /// \brief The point of instantiation within the source code.<br>
@@ -5242,6 +5249,7 @@<br>
<br>
       switch (X.Kind) {<br>
       case TemplateInstantiation:<br>
+      case ExceptionSpecInstantiation:<br>
         return true;<br>
<br>
       case PriorTemplateArgumentSubstitution:<br>
@@ -5359,6 +5367,13 @@<br>
                           Decl *Entity,<br>
                           SourceRange InstantiationRange = SourceRange());<br>
<br>
+    struct ExceptionSpecification {};<br>
+    /// \brief Note that we are instantiating an exception specification<br>
+    /// of a function template.<br>
+    InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,<br>
+                          FunctionDecl *Entity, ExceptionSpecification,<br>
+                          SourceRange InstantiationRange = SourceRange());<br>
+<br>
     /// \brief Note that we are instantiating a default argument in a<br>
     /// template-id.<br>
     InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,<br>
@@ -5658,6 +5673,8 @@<br>
              TemplateArgumentListInfo &Result,<br>
              const MultiLevelTemplateArgumentList &TemplateArgs);<br>
<br>
+  void InstantiateExceptionSpec(SourceLocation PointOfInstantiation,<br>
+                                FunctionDecl *Function);<br>
   void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,<br>
                                      FunctionDecl *Function,<br>
                                      bool Recursive = false,<br>
<br>
Modified: cfe/trunk/lib/AST/ASTContext.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/AST/ASTContext.cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Apr 16 19:58:00 2012<br>
@@ -2194,6 +2194,8 @@<br>
     Size += EPI.NumExceptions * sizeof(QualType);<br>
   else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {<br>
     Size += sizeof(Expr*);<br>
+  } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {<br>
+    Size += sizeof(FunctionDecl*);<br>
   }<br>
   if (EPI.ConsumedArguments)<br>
     Size += NumArgs * sizeof(bool);<br>
<br>
Modified: cfe/trunk/lib/AST/Expr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/AST/Expr.cpp (original)<br>
+++ cfe/trunk/lib/AST/Expr.cpp Mon Apr 16 19:58:00 2012<br>
@@ -1996,331 +1996,6 @@<br>
   return QualType();<br>
 }<br>
<br>
-static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1,<br>
-                                          Expr::CanThrowResult CT2) {<br>
-  // CanThrowResult constants are ordered so that the maximum is the correct<br>
-  // merge result.<br>
-  return CT1 > CT2 ? CT1 : CT2;<br>
-}<br>
-<br>
-static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) {<br>
-  Expr *E = const_cast<Expr*>(CE);<br>
-  Expr::CanThrowResult R = Expr::CT_Cannot;<br>
-  for (Expr::child_range I = E->children(); I && R != Expr::CT_Can; ++I) {<br>
-    R = MergeCanThrow(R, cast<Expr>(*I)->CanThrow(C));<br>
-  }<br>
-  return R;<br>
-}<br>
-<br>
-static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E,<br>
-                                           const Decl *D,<br>
-                                           bool NullThrows = true) {<br>
-  if (!D)<br>
-    return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;<br>
-<br>
-  // See if we can get a function type from the decl somehow.<br>
-  const ValueDecl *VD = dyn_cast<ValueDecl>(D);<br>
-  if (!VD) // If we have no clue what we're calling, assume the worst.<br>
-    return Expr::CT_Can;<br>
-<br>
-  // As an extension, we assume that __attribute__((nothrow)) functions don't<br>
-  // throw.<br>
-  if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())<br>
-    return Expr::CT_Cannot;<br>
-<br>
-  QualType T = VD->getType();<br>
-  const FunctionProtoType *FT;<br>
-  if ((FT = T->getAs<FunctionProtoType>())) {<br>
-  } else if (const PointerType *PT = T->getAs<PointerType>())<br>
-    FT = PT->getPointeeType()->getAs<FunctionProtoType>();<br>
-  else if (const ReferenceType *RT = T->getAs<ReferenceType>())<br>
-    FT = RT->getPointeeType()->getAs<FunctionProtoType>();<br>
-  else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())<br>
-    FT = MT->getPointeeType()->getAs<FunctionProtoType>();<br>
-  else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())<br>
-    FT = BT->getPointeeType()->getAs<FunctionProtoType>();<br>
-<br>
-  if (!FT)<br>
-    return Expr::CT_Can;<br>
-<br>
-  if (FT->getExceptionSpecType() == EST_Delayed) {<br>
-    assert(isa<CXXConstructorDecl>(D) &&<br>
-           "only constructor exception specs can be unknown");<br>
-    Ctx.getDiagnostics().Report(E->getLocStart(),<br>
-                                diag::err_exception_spec_unknown)<br>
-      << E->getSourceRange();<br>
-    return Expr::CT_Can;<br>
-  }<br>
-<br>
-  return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can;<br>
-}<br>
-<br>
-static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) {<br>
-  if (DC->isTypeDependent())<br>
-    return Expr::CT_Dependent;<br>
-<br>
-  if (!DC->getTypeAsWritten()->isReferenceType())<br>
-    return Expr::CT_Cannot;<br>
-<br>
-  if (DC->getSubExpr()->isTypeDependent())<br>
-    return Expr::CT_Dependent;<br>
-<br>
-  return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot;<br>
-}<br>
-<br>
-static Expr::CanThrowResult CanTypeidThrow(ASTContext &C,<br>
-                                           const CXXTypeidExpr *DC) {<br>
-  if (DC->isTypeOperand())<br>
-    return Expr::CT_Cannot;<br>
-<br>
-  Expr *Op = DC->getExprOperand();<br>
-  if (Op->isTypeDependent())<br>
-    return Expr::CT_Dependent;<br>
-<br>
-  const RecordType *RT = Op->getType()->getAs<RecordType>();<br>
-  if (!RT)<br>
-    return Expr::CT_Cannot;<br>
-<br>
-  if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())<br>
-    return Expr::CT_Cannot;<br>
-<br>
-  if (Op->Classify(C).isPRValue())<br>
-    return Expr::CT_Cannot;<br>
-<br>
-  return Expr::CT_Can;<br>
-}<br>
-<br>
-Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {<br>
-  // C++ [expr.unary.noexcept]p3:<br>
-  //   [Can throw] if in a potentially-evaluated context the expression would<br>
-  //   contain:<br>
-  switch (getStmtClass()) {<br>
-  case CXXThrowExprClass:<br>
-    //   - a potentially evaluated throw-expression<br>
-    return CT_Can;<br>
-<br>
-  case CXXDynamicCastExprClass: {<br>
-    //   - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),<br>
-    //     where T is a reference type, that requires a run-time check<br>
-    CanThrowResult CT = CanDynamicCastThrow(cast<CXXDynamicCastExpr>(this));<br>
-    if (CT == CT_Can)<br>
-      return CT;<br>
-    return MergeCanThrow(CT, CanSubExprsThrow(C, this));<br>
-  }<br>
-<br>
-  case CXXTypeidExprClass:<br>
-    //   - a potentially evaluated typeid expression applied to a glvalue<br>
-    //     expression whose type is a polymorphic class type<br>
-    return CanTypeidThrow(C, cast<CXXTypeidExpr>(this));<br>
-<br>
-    //   - a potentially evaluated call to a function, member function, function<br>
-    //     pointer, or member function pointer that does not have a non-throwing<br>
-    //     exception-specification<br>
-  case CallExprClass:<br>
-  case CXXMemberCallExprClass:<br>
-  case CXXOperatorCallExprClass:<br>
-  case UserDefinedLiteralClass: {<br>
-    const CallExpr *CE = cast<CallExpr>(this);<br>
-    CanThrowResult CT;<br>
-    if (isTypeDependent())<br>
-      CT = CT_Dependent;<br>
-    else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))<br>
-      CT = CT_Cannot;<br>
-    else<br>
-      CT = CanCalleeThrow(C, this, CE->getCalleeDecl());<br>
-    if (CT == CT_Can)<br>
-      return CT;<br>
-    return MergeCanThrow(CT, CanSubExprsThrow(C, this));<br>
-  }<br>
-<br>
-  case CXXConstructExprClass:<br>
-  case CXXTemporaryObjectExprClass: {<br>
-    CanThrowResult CT = CanCalleeThrow(C, this,<br>
-        cast<CXXConstructExpr>(this)->getConstructor());<br>
-    if (CT == CT_Can)<br>
-      return CT;<br>
-    return MergeCanThrow(CT, CanSubExprsThrow(C, this));<br>
-  }<br>
-<br>
-  case LambdaExprClass: {<br>
-    const LambdaExpr *Lambda = cast<LambdaExpr>(this);<br>
-    CanThrowResult CT = Expr::CT_Cannot;<br>
-    for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(),<br>
-                                        CapEnd = Lambda->capture_init_end();<br>
-         Cap != CapEnd; ++Cap)<br>
-      CT = MergeCanThrow(CT, (*Cap)->CanThrow(C));<br>
-    return CT;<br>
-  }<br>
-<br>
-  case CXXNewExprClass: {<br>
-    CanThrowResult CT;<br>
-    if (isTypeDependent())<br>
-      CT = CT_Dependent;<br>
-    else<br>
-      CT = CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew());<br>
-    if (CT == CT_Can)<br>
-      return CT;<br>
-    return MergeCanThrow(CT, CanSubExprsThrow(C, this));<br>
-  }<br>
-<br>
-  case CXXDeleteExprClass: {<br>
-    CanThrowResult CT;<br>
-    QualType DTy = cast<CXXDeleteExpr>(this)->getDestroyedType();<br>
-    if (DTy.isNull() || DTy->isDependentType()) {<br>
-      CT = CT_Dependent;<br>
-    } else {<br>
-      CT = CanCalleeThrow(C, this,<br>
-                          cast<CXXDeleteExpr>(this)->getOperatorDelete());<br>
-      if (const RecordType *RT = DTy->getAs<RecordType>()) {<br>
-        const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());<br>
-        CT = MergeCanThrow(CT, CanCalleeThrow(C, this, RD->getDestructor()));<br>
-      }<br>
-      if (CT == CT_Can)<br>
-        return CT;<br>
-    }<br>
-    return MergeCanThrow(CT, CanSubExprsThrow(C, this));<br>
-  }<br>
-<br>
-  case CXXBindTemporaryExprClass: {<br>
-    // The bound temporary has to be destroyed again, which might throw.<br>
-    CanThrowResult CT = CanCalleeThrow(C, this,<br>
-      cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());<br>
-    if (CT == CT_Can)<br>
-      return CT;<br>
-    return MergeCanThrow(CT, CanSubExprsThrow(C, this));<br>
-  }<br>
-<br>
-    // ObjC message sends are like function calls, but never have exception<br>
-    // specs.<br>
-  case ObjCMessageExprClass:<br>
-  case ObjCPropertyRefExprClass:<br>
-  case ObjCSubscriptRefExprClass:<br>
-    return CT_Can;<br>
-<br>
-    // All the ObjC literals that are implemented as calls are<br>
-    // potentially throwing unless we decide to close off that<br>
-    // possibility.<br>
-  case ObjCArrayLiteralClass:<br>
-  case ObjCDictionaryLiteralClass:<br>
-  case ObjCNumericLiteralClass:<br>
-    return CT_Can;<br>
-<br>
-    // Many other things have subexpressions, so we have to test those.<br>
-    // Some are simple:<br>
-  case ConditionalOperatorClass:<br>
-  case CompoundLiteralExprClass:<br>
-  case CXXConstCastExprClass:<br>
-  case CXXDefaultArgExprClass:<br>
-  case CXXReinterpretCastExprClass:<br>
-  case DesignatedInitExprClass:<br>
-  case ExprWithCleanupsClass:<br>
-  case ExtVectorElementExprClass:<br>
-  case InitListExprClass:<br>
-  case MemberExprClass:<br>
-  case ObjCIsaExprClass:<br>
-  case ObjCIvarRefExprClass:<br>
-  case ParenExprClass:<br>
-  case ParenListExprClass:<br>
-  case ShuffleVectorExprClass:<br>
-  case VAArgExprClass:<br>
-    return CanSubExprsThrow(C, this);<br>
-<br>
-    // Some might be dependent for other reasons.<br>
-  case ArraySubscriptExprClass:<br>
-  case BinaryOperatorClass:<br>
-  case CompoundAssignOperatorClass:<br>
-  case CStyleCastExprClass:<br>
-  case CXXStaticCastExprClass:<br>
-  case CXXFunctionalCastExprClass:<br>
-  case ImplicitCastExprClass:<br>
-  case MaterializeTemporaryExprClass:<br>
-  case UnaryOperatorClass: {<br>
-    CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot;<br>
-    return MergeCanThrow(CT, CanSubExprsThrow(C, this));<br>
-  }<br>
-<br>
-    // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.<br>
-  case StmtExprClass:<br>
-    return CT_Can;<br>
-<br>
-  case ChooseExprClass:<br>
-    if (isTypeDependent() || isValueDependent())<br>
-      return CT_Dependent;<br>
-    return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C);<br>
-<br>
-  case GenericSelectionExprClass:<br>
-    if (cast<GenericSelectionExpr>(this)->isResultDependent())<br>
-      return CT_Dependent;<br>
-    return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C);<br>
-<br>
-    // Some expressions are always dependent.<br>
-  case CXXDependentScopeMemberExprClass:<br>
-  case CXXUnresolvedConstructExprClass:<br>
-  case DependentScopeDeclRefExprClass:<br>
-    return CT_Dependent;<br>
-<br>
-  case AtomicExprClass:<br>
-  case AsTypeExprClass:<br>
-  case BinaryConditionalOperatorClass:<br>
-  case BlockExprClass:<br>
-  case CUDAKernelCallExprClass:<br>
-  case DeclRefExprClass:<br>
-  case ObjCBridgedCastExprClass:<br>
-  case ObjCIndirectCopyRestoreExprClass:<br>
-  case ObjCProtocolExprClass:<br>
-  case ObjCSelectorExprClass:<br>
-  case OffsetOfExprClass:<br>
-  case PackExpansionExprClass:<br>
-  case PseudoObjectExprClass:<br>
-  case SubstNonTypeTemplateParmExprClass:<br>
-  case SubstNonTypeTemplateParmPackExprClass:<br>
-  case UnaryExprOrTypeTraitExprClass:<br>
-  case UnresolvedLookupExprClass:<br>
-  case UnresolvedMemberExprClass:<br>
-    // FIXME: Can any of the above throw?  If so, when?<br>
-    return CT_Cannot;<br>
-<br>
-  case AddrLabelExprClass:<br>
-  case ArrayTypeTraitExprClass:<br>
-  case BinaryTypeTraitExprClass:<br>
-  case TypeTraitExprClass:<br>
-  case CXXBoolLiteralExprClass:<br>
-  case CXXNoexceptExprClass:<br>
-  case CXXNullPtrLiteralExprClass:<br>
-  case CXXPseudoDestructorExprClass:<br>
-  case CXXScalarValueInitExprClass:<br>
-  case CXXThisExprClass:<br>
-  case CXXUuidofExprClass:<br>
-  case CharacterLiteralClass:<br>
-  case ExpressionTraitExprClass:<br>
-  case FloatingLiteralClass:<br>
-  case GNUNullExprClass:<br>
-  case ImaginaryLiteralClass:<br>
-  case ImplicitValueInitExprClass:<br>
-  case IntegerLiteralClass:<br>
-  case ObjCEncodeExprClass:<br>
-  case ObjCStringLiteralClass:<br>
-  case ObjCBoolLiteralExprClass:<br>
-  case OpaqueValueExprClass:<br>
-  case PredefinedExprClass:<br>
-  case SizeOfPackExprClass:<br>
-  case StringLiteralClass:<br>
-  case UnaryTypeTraitExprClass:<br>
-    // These expressions can never throw.<br>
-    return CT_Cannot;<br>
-<br>
-#define STMT(CLASS, PARENT) case CLASS##Class:<br>
-#define STMT_RANGE(Base, First, Last)<br>
-#define LAST_STMT_RANGE(BASE, FIRST, LAST)<br>
-#define EXPR(CLASS, PARENT)<br>
-#define ABSTRACT_STMT(STMT)<br>
-#include "clang/AST/StmtNodes.inc"<br>
-  case NoStmtClass:<br>
-    llvm_unreachable("Invalid class for expression");<br>
-  }<br>
-  llvm_unreachable("Bogus StmtClass");<br>
-}<br>
-<br>
 Expr* Expr::IgnoreParens() {<br>
   Expr* E = this;<br>
   while (true) {<br>
<br>
Modified: cfe/trunk/lib/AST/Type.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/AST/Type.cpp (original)<br>
+++ cfe/trunk/lib/AST/Type.cpp Mon Apr 16 19:58:00 2012<br>
@@ -1546,6 +1546,13 @@<br>
       else if (epi.NoexceptExpr->isInstantiationDependent())<br>
         setInstantiationDependent();<br>
     }<br>
+  } else if (getExceptionSpecType() == EST_Uninstantiated) {<br>
+    // Store the function decl from which we will resolve our<br>
+    // exception specification.<br>
+    FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);<br>
+    *slot = epi.ExceptionSpecDecl;<br>
+    // This exception specification doesn't make the type dependent, because<br>
+    // it's not instantiated as part of instantiating the type.<br>
   }<br>
<br>
   if (epi.ConsumedArguments) {<br>
@@ -1629,6 +1636,8 @@<br>
       ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());<br>
   } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){<br>
     epi.NoexceptExpr->Profile(ID, Context, false);<br>
+  } else if (epi.ExceptionSpecType == EST_Uninstantiated) {<br>
+    ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl());<br>
   }<br>
   if (epi.ConsumedArguments) {<br>
     for (unsigned i = 0; i != NumArgs; ++i)<br>
<br>
Modified: cfe/trunk/lib/Analysis/CFG.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Analysis/CFG.cpp (original)<br>
+++ cfe/trunk/lib/Analysis/CFG.cpp Mon Apr 16 19:58:00 2012<br>
@@ -1284,7 +1284,8 @@<br>
   const FunctionType *FT = Ty->getAs<FunctionType>();<br>
   if (FT) {<br>
     if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))<br>
-      if (Proto->isNothrow(Ctx))<br>
+      if (Proto->getExceptionSpecType() != EST_Uninstantiated &&<br>
+          Proto->isNothrow(Ctx))<br>
         return false;<br>
   }<br>
   return true;<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Apr 16 19:58:00 2012<br>
@@ -125,14 +125,17 @@<br>
   }<br>
 }<br>
<br>
-void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {<br>
-  assert(Context && "ImplicitExceptionSpecification without an ASTContext");<br>
+void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,<br>
+                                                      CXXMethodDecl *Method) {<br>
   // If we have an MSAny or unknown spec already, don't bother.<br>
   if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)<br>
     return;<br>
<br>
   const FunctionProtoType *Proto<br>
     = Method->getType()->getAs<FunctionProtoType>();<br>
+  Proto = Self->ResolveExceptionSpec(CallLoc, Proto);<br>
+  if (!Proto)<br>
+    return;<br>
<br>
   ExceptionSpecificationType EST = Proto->getExceptionSpecType();<br>
<br>
@@ -164,7 +167,8 @@<br>
<br>
   // Check out noexcept specs.<br>
   if (EST == EST_ComputedNoexcept) {<br>
-    FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(*Context);<br>
+    FunctionProtoType::NoexceptResult NR =<br>
+        Proto->getNoexceptSpec(Self->Context);<br>
     assert(NR != FunctionProtoType::NR_NoNoexcept &&<br>
            "Must have noexcept result for EST_ComputedNoexcept.");<br>
     assert(NR != FunctionProtoType::NR_Dependent &&<br>
@@ -188,7 +192,7 @@<br>
   for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),<br>
                                           EEnd = Proto->exception_end();<br>
        E != EEnd; ++E)<br>
-    if (ExceptionsSeen.insert(Context->getCanonicalType(*E)))<br>
+    if (ExceptionsSeen.insert(Self->Context.getCanonicalType(*E)))<br>
       Exceptions.push_back(*E);<br>
 }<br>
<br>
@@ -217,7 +221,7 @@<br>
   // implicit definition. For now, we assume that any non-nothrow expression can<br>
   // throw any exception.<br>
<br>
-  if (E->CanThrow(*Context))<br>
+  if (Self->canThrow(E))<br>
     ComputedEST = EST_None;<br>
 }<br>
<br>
@@ -3922,7 +3926,7 @@<br>
     HadError = true;<br>
   }<br>
<br>
-  ImplicitExceptionSpecification Spec(Context);<br>
+  ImplicitExceptionSpecification Spec(*this);<br>
   bool Const;<br>
   llvm::tie(Spec, Const) =<br>
     ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent());<br>
@@ -4031,7 +4035,7 @@<br>
     HadError = true;<br>
   }<br>
<br>
-  ImplicitExceptionSpecification Spec(Context);<br>
+  ImplicitExceptionSpecification Spec(*this);<br>
   bool Const;<br>
   llvm::tie(Spec, Const) =<br>
     ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent());<br>
@@ -6814,7 +6818,7 @@<br>
   // C++ [except.spec]p14:<br>
   //   An implicitly declared special member function (Clause 12) shall have an<br>
   //   exception-specification. [...]<br>
-  ImplicitExceptionSpecification ExceptSpec(Context);<br>
+  ImplicitExceptionSpecification ExceptSpec(*this);<br>
   if (ClassDecl->isInvalidDecl())<br>
     return ExceptSpec;<br>
<br>
@@ -6831,7 +6835,7 @@<br>
       // If this is a deleted function, add it anyway. This might be conformant<br>
       // with the standard. This might not. I'm not sure. It might not matter.<br>
       if (Constructor)<br>
-        ExceptSpec.CalledDecl(Constructor);<br>
+        ExceptSpec.CalledDecl(B->getLocStart(), Constructor);<br>
     }<br>
   }<br>
<br>
@@ -6845,7 +6849,7 @@<br>
       // If this is a deleted function, add it anyway. This might be conformant<br>
       // with the standard. This might not. I'm not sure. It might not matter.<br>
       if (Constructor)<br>
-        ExceptSpec.CalledDecl(Constructor);<br>
+        ExceptSpec.CalledDecl(B->getLocStart(), Constructor);<br>
     }<br>
   }<br>
<br>
@@ -6868,7 +6872,7 @@<br>
       // might just be ill-formed because this function attempts to refer to<br>
       // a deleted function here.<br>
       if (Constructor)<br>
-        ExceptSpec.CalledDecl(Constructor);<br>
+        ExceptSpec.CalledDecl(F->getLocation(), Constructor);<br>
     }<br>
   }<br>
<br>
@@ -6990,6 +6994,7 @@<br>
   const FunctionProtoType *CtorTy =<br>
     CtorDecl->getType()->castAs<FunctionProtoType>();<br>
   if (CtorTy->getExceptionSpecType() == EST_Delayed) {<br>
+    // FIXME: Don't do this unless the exception spec is needed.<br>
     ImplicitExceptionSpecification Spec =<br>
       ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);<br>
     FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();<br>
@@ -7190,7 +7195,7 @@<br>
   // C++ [except.spec]p14:<br>
   //   An implicitly declared special member function (Clause 12) shall have<br>
   //   an exception-specification.<br>
-  ImplicitExceptionSpecification ExceptSpec(Context);<br>
+  ImplicitExceptionSpecification ExceptSpec(*this);<br>
   if (ClassDecl->isInvalidDecl())<br>
     return ExceptSpec;<br>
<br>
@@ -7202,7 +7207,7 @@<br>
       continue;<br>
<br>
     if (const RecordType *BaseType = B->getType()->getAs<RecordType>())<br>
-      ExceptSpec.CalledDecl(<br>
+      ExceptSpec.CalledDecl(B->getLocStart(),<br>
                    LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));<br>
   }<br>
<br>
@@ -7211,7 +7216,7 @@<br>
                                        BEnd = ClassDecl->vbases_end();<br>
        B != BEnd; ++B) {<br>
     if (const RecordType *BaseType = B->getType()->getAs<RecordType>())<br>
-      ExceptSpec.CalledDecl(<br>
+      ExceptSpec.CalledDecl(B->getLocStart(),<br>
                   LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));<br>
   }<br>
<br>
@@ -7221,7 +7226,7 @@<br>
        F != FEnd; ++F) {<br>
     if (const RecordType *RecordTy<br>
         = Context.getBaseElementType(F->getType())->getAs<RecordType>())<br>
-      ExceptSpec.CalledDecl(<br>
+      ExceptSpec.CalledDecl(F->getLocation(),<br>
                   LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));<br>
   }<br>
<br>
@@ -7546,7 +7551,7 @@<br>
 Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(<br>
                                                    CXXRecordDecl *ClassDecl) {<br>
   if (ClassDecl->isInvalidDecl())<br>
-    return std::make_pair(ImplicitExceptionSpecification(Context), false);<br>
+    return std::make_pair(ImplicitExceptionSpecification(*this), false);<br>
<br>
   // C++ [class.copy]p10:<br>
   //   If the class definition does not explicitly declare a copy<br>
@@ -7619,7 +7624,7 @@<br>
   // Based on a similar decision made for constness in C++0x, we're erring on<br>
   // the side of assuming such calls to be made regardless of whether they<br>
   // actually happen.<br>
-  ImplicitExceptionSpecification ExceptSpec(Context);<br>
+  ImplicitExceptionSpecification ExceptSpec(*this);<br>
   unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0;<br>
   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),<br>
                                        BaseEnd = ClassDecl->bases_end();<br>
@@ -7631,7 +7636,7 @@<br>
       = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());<br>
     if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,<br>
                                                             ArgQuals, false, 0))<br>
-      ExceptSpec.CalledDecl(CopyAssign);<br>
+      ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign);<br>
   }<br>
<br>
   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),<br>
@@ -7641,7 +7646,7 @@<br>
       = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());<br>
     if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,<br>
                                                             ArgQuals, false, 0))<br>
-      ExceptSpec.CalledDecl(CopyAssign);<br>
+      ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign);<br>
   }<br>
<br>
   for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),<br>
@@ -7652,7 +7657,7 @@<br>
     if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {<br>
       if (CXXMethodDecl *CopyAssign =<br>
           LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0))<br>
-        ExceptSpec.CalledDecl(CopyAssign);<br>
+        ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign);<br>
     }<br>
   }<br>
<br>
@@ -7665,7 +7670,7 @@<br>
   // for determining the argument type of the operator. Note also that<br>
   // operators taking an object instead of a reference are allowed.<br>
<br>
-  ImplicitExceptionSpecification Spec(Context);<br>
+  ImplicitExceptionSpecification Spec(*this);<br>
   bool Const;<br>
   llvm::tie(Spec, Const) =<br>
     ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl);<br>
@@ -8032,7 +8037,7 @@<br>
<br>
 Sema::ImplicitExceptionSpecification<br>
 Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {<br>
-  ImplicitExceptionSpecification ExceptSpec(Context);<br>
+  ImplicitExceptionSpecification ExceptSpec(*this);<br>
<br>
   if (ClassDecl->isInvalidDecl())<br>
     return ExceptSpec;<br>
@@ -8059,7 +8064,7 @@<br>
       = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());<br>
     if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,<br>
                                                            false, 0))<br>
-      ExceptSpec.CalledDecl(MoveAssign);<br>
+      ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);<br>
   }<br>
<br>
   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),<br>
@@ -8069,7 +8074,7 @@<br>
       = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());<br>
     if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,<br>
                                                            false, 0))<br>
-      ExceptSpec.CalledDecl(MoveAssign);<br>
+      ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);<br>
   }<br>
<br>
   for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),<br>
@@ -8080,7 +8085,7 @@<br>
     if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {<br>
       if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(FieldClassDecl,<br>
                                                              false, 0))<br>
-        ExceptSpec.CalledDecl(MoveAssign);<br>
+        ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign);<br>
     }<br>
   }<br>
<br>
@@ -8578,7 +8583,7 @@<br>
 std::pair<Sema::ImplicitExceptionSpecification, bool><br>
 Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {<br>
   if (ClassDecl->isInvalidDecl())<br>
-    return std::make_pair(ImplicitExceptionSpecification(Context), false);<br>
+    return std::make_pair(ImplicitExceptionSpecification(*this), false);<br>
<br>
   // C++ [class.copy]p5:<br>
   //   The implicitly-declared copy constructor for a class X will<br>
@@ -8639,7 +8644,7 @@<br>
   // C++ [except.spec]p14:<br>
   //   An implicitly declared special member function (Clause 12) shall have an<br>
   //   exception-specification. [...]<br>
-  ImplicitExceptionSpecification ExceptSpec(Context);<br>
+  ImplicitExceptionSpecification ExceptSpec(*this);<br>
   unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0;<br>
   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),<br>
                                        BaseEnd = ClassDecl->bases_end();<br>
@@ -8653,7 +8658,7 @@<br>
       = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());<br>
     if (CXXConstructorDecl *CopyConstructor =<br>
           LookupCopyingConstructor(BaseClassDecl, Quals))<br>
-      ExceptSpec.CalledDecl(CopyConstructor);<br>
+      ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor);<br>
   }<br>
   for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),<br>
                                        BaseEnd = ClassDecl->vbases_end();<br>
@@ -8663,7 +8668,7 @@<br>
       = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());<br>
     if (CXXConstructorDecl *CopyConstructor =<br>
           LookupCopyingConstructor(BaseClassDecl, Quals))<br>
-      ExceptSpec.CalledDecl(CopyConstructor);<br>
+      ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor);<br>
   }<br>
   for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),<br>
                                   FieldEnd = ClassDecl->field_end();<br>
@@ -8673,7 +8678,7 @@<br>
     if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {<br>
       if (CXXConstructorDecl *CopyConstructor =<br>
         LookupCopyingConstructor(FieldClassDecl, Quals))<br>
-      ExceptSpec.CalledDecl(CopyConstructor);<br>
+      ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor);<br>
     }<br>
   }<br>
<br>
@@ -8686,7 +8691,7 @@<br>
   //   If the class definition does not explicitly declare a copy<br>
   //   constructor, one is declared implicitly.<br>
<br>
-  ImplicitExceptionSpecification Spec(Context);<br>
+  ImplicitExceptionSpecification Spec(*this);<br>
   bool Const;<br>
   llvm::tie(Spec, Const) =<br>
     ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl);<br>
@@ -8784,7 +8789,7 @@<br>
   // C++ [except.spec]p14:<br>
   //   An implicitly declared special member function (Clause 12) shall have an<br>
   //   exception-specification. [...]<br>
-  ImplicitExceptionSpecification ExceptSpec(Context);<br>
+  ImplicitExceptionSpecification ExceptSpec(*this);<br>
   if (ClassDecl->isInvalidDecl())<br>
     return ExceptSpec;<br>
<br>
@@ -8801,7 +8806,7 @@<br>
       // If this is a deleted function, add it anyway. This might be conformant<br>
       // with the standard. This might not. I'm not sure. It might not matter.<br>
       if (Constructor)<br>
-        ExceptSpec.CalledDecl(Constructor);<br>
+        ExceptSpec.CalledDecl(B->getLocStart(), Constructor);<br>
     }<br>
   }<br>
<br>
@@ -8815,7 +8820,7 @@<br>
       // If this is a deleted function, add it anyway. This might be conformant<br>
       // with the standard. This might not. I'm not sure. It might not matter.<br>
       if (Constructor)<br>
-        ExceptSpec.CalledDecl(Constructor);<br>
+        ExceptSpec.CalledDecl(B->getLocStart(), Constructor);<br>
     }<br>
   }<br>
<br>
@@ -8833,7 +8838,7 @@<br>
       // might just be ill-formed because this function attempts to refer to<br>
       // a deleted function here.<br>
       if (Constructor)<br>
-        ExceptSpec.CalledDecl(Constructor);<br>
+        ExceptSpec.CalledDecl(F->getLocation(), Constructor);<br>
     }<br>
   }<br>
<br>
@@ -11116,6 +11121,7 @@<br>
   FindCXXThisExpr Finder(*this);<br>
<br>
   switch (Proto->getExceptionSpecType()) {<br>
+  case EST_Uninstantiated:<br>
   case EST_BasicNoexcept:<br>
   case EST_Delayed:<br>
   case EST_DynamicNone:<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Mon Apr 16 19:58:00 2012<br>
@@ -96,6 +96,26 @@<br>
   return FnT->hasExceptionSpec();<br>
 }<br>
<br>
+const FunctionProtoType *<br>
+Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {<br>
+  // FIXME: If FD is a special member, we should delay computing its exception<br>
+  // specification until this point.<br>
+  if (FPT->getExceptionSpecType() != EST_Uninstantiated)<br>
+    return FPT;<br>
+<br>
+  FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();<br>
+  const FunctionProtoType *SourceFPT =<br>
+      SourceDecl->getType()->castAs<FunctionProtoType>();<br>
+<br>
+  if (SourceFPT->getExceptionSpecType() != EST_Uninstantiated)<br>
+    return SourceFPT;<br>
+<br>
+  // Instantiate the exception specification now.<br>
+  InstantiateExceptionSpec(Loc, SourceDecl);<br>
+<br>
+  return SourceDecl->getType()->castAs<FunctionProtoType>();<br>
+}<br>
+<br>
 bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {<br>
   OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();<br>
   bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;<br>
@@ -104,7 +124,7 @@<br>
   unsigned DiagID = diag::err_mismatched_exception_spec;<br>
   if (getLangOpts().MicrosoftExt)<br>
     DiagID = diag::warn_mismatched_exception_spec;<br>
-<br>
+<br>
   if (!CheckEquivalentExceptionSpec(PDiag(DiagID),<br>
                                     PDiag(diag::note_previous_declaration),<br>
                                     Old->getType()->getAs<FunctionProtoType>(),<br>
@@ -295,6 +315,13 @@<br>
   if (MissingEmptyExceptionSpecification)<br>
     *MissingEmptyExceptionSpecification = false;<br>
<br>
+  Old = ResolveExceptionSpec(NewLoc, Old);<br>
+  if (!Old)<br>
+    return false;<br>
+  New = ResolveExceptionSpec(NewLoc, New);<br>
+  if (!New)<br>
+    return false;<br>
+<br>
   // C++0x [except.spec]p3: Two exception-specifications are compatible if:<br>
   //   - both are non-throwing, regardless of their form,<br>
   //   - both have the form noexcept(constant-expression) and the constant-<br>
@@ -318,6 +345,7 @@<br>
   ExceptionSpecificationType NewEST = New->getExceptionSpecType();<br>
<br>
   assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&<br>
+         OldEST != EST_Uninstantiated && NewEST != EST_Uninstantiated &&<br>
          "Shouldn't see unknown exception specifications here");<br>
<br>
   // Shortcut the case where both have no spec.<br>
@@ -483,6 +511,14 @@<br>
   if (!SubLoc.isValid())<br>
     SubLoc = SuperLoc;<br>
<br>
+  // Resolve the exception specifications, if needed.<br>
+  Superset = ResolveExceptionSpec(SuperLoc, Superset);<br>
+  if (!Superset)<br>
+    return false;<br>
+  Subset = ResolveExceptionSpec(SubLoc, Subset);<br>
+  if (!Subset)<br>
+    return false;<br>
+<br>
   ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType();<br>
<br>
   // If superset contains everything, we're done.<br>
@@ -507,6 +543,7 @@<br>
   ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();<br>
<br>
   assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&<br>
+         SuperEST != EST_Uninstantiated && SubEST != EST_Uninstantiated &&<br>
          "Shouldn't see unknown exception specifications here");<br>
<br>
   // It does not. If the subset contains everything, we've failed.<br>
@@ -726,4 +763,324 @@<br>
                                   New->getLocation());<br>
 }<br>
<br>
+static CanThrowResult canSubExprsThrow(Sema &S, const Expr *CE) {<br>
+  Expr *E = const_cast<Expr*>(CE);<br>
+  CanThrowResult R = CT_Cannot;<br>
+  for (Expr::child_range I = E->children(); I && R != CT_Can; ++I)<br>
+    R = mergeCanThrow(R, S.canThrow(cast<Expr>(*I)));<br>
+  return R;<br>
+}<br>
+<br>
+static CanThrowResult canCalleeThrow(Sema &S, const Expr *E,<br>
+                                           const Decl *D,<br>
+                                           bool NullThrows = true) {<br>
+  if (!D)<br>
+    return NullThrows ? CT_Can : CT_Cannot;<br>
+<br>
+  // See if we can get a function type from the decl somehow.<br>
+  const ValueDecl *VD = dyn_cast<ValueDecl>(D);<br>
+  if (!VD) // If we have no clue what we're calling, assume the worst.<br>
+    return CT_Can;<br>
+<br>
+  // As an extension, we assume that __attribute__((nothrow)) functions don't<br>
+  // throw.<br>
+  if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())<br>
+    return CT_Cannot;<br>
+<br>
+  QualType T = VD->getType();<br>
+  const FunctionProtoType *FT;<br>
+  if ((FT = T->getAs<FunctionProtoType>())) {<br>
+  } else if (const PointerType *PT = T->getAs<PointerType>())<br>
+    FT = PT->getPointeeType()->getAs<FunctionProtoType>();<br>
+  else if (const ReferenceType *RT = T->getAs<ReferenceType>())<br>
+    FT = RT->getPointeeType()->getAs<FunctionProtoType>();<br>
+  else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())<br>
+    FT = MT->getPointeeType()->getAs<FunctionProtoType>();<br>
+  else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())<br>
+    FT = BT->getPointeeType()->getAs<FunctionProtoType>();<br>
+<br>
+  if (!FT)<br>
+    return CT_Can;<br>
+<br>
+  FT = S.ResolveExceptionSpec(E->getLocStart(), FT);<br>
+  if (!FT)<br>
+    return CT_Can;<br>
+<br>
+  if (FT->getExceptionSpecType() == EST_Delayed) {<br>
+    // FIXME: Try to resolve a delayed exception spec in ResolveExceptionSpec.<br>
+    assert(isa<CXXConstructorDecl>(D) &&<br>
+           "only constructor exception specs can be unknown");<br>
+    S.Diag(E->getLocStart(), diag::err_exception_spec_unknown)<br>
+      << E->getSourceRange();<br>
+    return CT_Can;<br>
+  }<br>
+<br>
+  return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;<br>
+}<br>
+<br>
+static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {<br>
+  if (DC->isTypeDependent())<br>
+    return CT_Dependent;<br>
+<br>
+  if (!DC->getTypeAsWritten()->isReferenceType())<br>
+    return CT_Cannot;<br>
+<br>
+  if (DC->getSubExpr()->isTypeDependent())<br>
+    return CT_Dependent;<br>
+<br>
+  return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot;<br>
+}<br>
+<br>
+static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {<br>
+  if (DC->isTypeOperand())<br>
+    return CT_Cannot;<br>
+<br>
+  Expr *Op = DC->getExprOperand();<br>
+  if (Op->isTypeDependent())<br>
+    return CT_Dependent;<br>
+<br>
+  const RecordType *RT = Op->getType()->getAs<RecordType>();<br>
+  if (!RT)<br>
+    return CT_Cannot;<br>
+<br>
+  if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())<br>
+    return CT_Cannot;<br>
+<br>
+  if (Op->Classify(S.Context).isPRValue())<br>
+    return CT_Cannot;<br>
+<br>
+  return CT_Can;<br>
+}<br>
+<br>
+CanThrowResult Sema::canThrow(const Expr *E) {<br>
+  // C++ [expr.unary.noexcept]p3:<br>
+  //   [Can throw] if in a potentially-evaluated context the expression would<br>
+  //   contain:<br>
+  switch (E->getStmtClass()) {<br>
+  case Expr::CXXThrowExprClass:<br>
+    //   - a potentially evaluated throw-expression<br>
+    return CT_Can;<br>
+<br>
+  case Expr::CXXDynamicCastExprClass: {<br>
+    //   - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),<br>
+    //     where T is a reference type, that requires a run-time check<br>
+    CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E));<br>
+    if (CT == CT_Can)<br>
+      return CT;<br>
+    return mergeCanThrow(CT, canSubExprsThrow(*this, E));<br>
+  }<br>
+<br>
+  case Expr::CXXTypeidExprClass:<br>
+    //   - a potentially evaluated typeid expression applied to a glvalue<br>
+    //     expression whose type is a polymorphic class type<br>
+    return canTypeidThrow(*this, cast<CXXTypeidExpr>(E));<br>
+<br>
+    //   - a potentially evaluated call to a function, member function, function<br>
+    //     pointer, or member function pointer that does not have a non-throwing<br>
+    //     exception-specification<br>
+  case Expr::CallExprClass:<br>
+  case Expr::CXXMemberCallExprClass:<br>
+  case Expr::CXXOperatorCallExprClass:<br>
+  case Expr::UserDefinedLiteralClass: {<br>
+    const CallExpr *CE = cast<CallExpr>(E);<br>
+    CanThrowResult CT;<br>
+    if (E->isTypeDependent())<br>
+      CT = CT_Dependent;<br>
+    else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))<br>
+      CT = CT_Cannot;<br>
+    else<br>
+      CT = canCalleeThrow(*this, E, CE->getCalleeDecl());<br>
+    if (CT == CT_Can)<br>
+      return CT;<br>
+    return mergeCanThrow(CT, canSubExprsThrow(*this, E));<br>
+  }<br>
+<br>
+  case Expr::CXXConstructExprClass:<br>
+  case Expr::CXXTemporaryObjectExprClass: {<br>
+    CanThrowResult CT = canCalleeThrow(*this, E,<br>
+        cast<CXXConstructExpr>(E)->getConstructor());<br>
+    if (CT == CT_Can)<br>
+      return CT;<br>
+    return mergeCanThrow(CT, canSubExprsThrow(*this, E));<br>
+  }<br>
+<br>
+  case Expr::LambdaExprClass: {<br>
+    const LambdaExpr *Lambda = cast<LambdaExpr>(E);<br>
+    CanThrowResult CT = CT_Cannot;<br>
+    for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(),<br>
+                                        CapEnd = Lambda->capture_init_end();<br>
+         Cap != CapEnd; ++Cap)<br>
+      CT = mergeCanThrow(CT, canThrow(*Cap));<br>
+    return CT;<br>
+  }<br>
+<br>
+  case Expr::CXXNewExprClass: {<br>
+    CanThrowResult CT;<br>
+    if (E->isTypeDependent())<br>
+      CT = CT_Dependent;<br>
+    else<br>
+      CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew());<br>
+    if (CT == CT_Can)<br>
+      return CT;<br>
+    return mergeCanThrow(CT, canSubExprsThrow(*this, E));<br>
+  }<br>
+<br>
+  case Expr::CXXDeleteExprClass: {<br>
+    CanThrowResult CT;<br>
+    QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType();<br>
+    if (DTy.isNull() || DTy->isDependentType()) {<br>
+      CT = CT_Dependent;<br>
+    } else {<br>
+      CT = canCalleeThrow(*this, E,<br>
+                          cast<CXXDeleteExpr>(E)->getOperatorDelete());<br>
+      if (const RecordType *RT = DTy->getAs<RecordType>()) {<br>
+        const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());<br>
+        CT = mergeCanThrow(CT, canCalleeThrow(*this, E, RD->getDestructor()));<br>
+      }<br>
+      if (CT == CT_Can)<br>
+        return CT;<br>
+    }<br>
+    return mergeCanThrow(CT, canSubExprsThrow(*this, E));<br>
+  }<br>
+<br>
+  case Expr::CXXBindTemporaryExprClass: {<br>
+    // The bound temporary has to be destroyed again, which might throw.<br>
+    CanThrowResult CT = canCalleeThrow(*this, E,<br>
+      cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor());<br>
+    if (CT == CT_Can)<br>
+      return CT;<br>
+    return mergeCanThrow(CT, canSubExprsThrow(*this, E));<br>
+  }<br>
+<br>
+    // ObjC message sends are like function calls, but never have exception<br>
+    // specs.<br>
+  case Expr::ObjCMessageExprClass:<br>
+  case Expr::ObjCPropertyRefExprClass:<br>
+  case Expr::ObjCSubscriptRefExprClass:<br>
+    return CT_Can;<br>
+<br>
+    // All the ObjC literals that are implemented as calls are<br>
+    // potentially throwing unless we decide to close off that<br>
+    // possibility.<br>
+  case Expr::ObjCArrayLiteralClass:<br>
+  case Expr::ObjCDictionaryLiteralClass:<br>
+  case Expr::ObjCNumericLiteralClass:<br>
+    return CT_Can;<br>
+<br>
+    // Many other things have subexpressions, so we have to test those.<br>
+    // Some are simple:<br>
+  case Expr::ConditionalOperatorClass:<br>
+  case Expr::CompoundLiteralExprClass:<br>
+  case Expr::CXXConstCastExprClass:<br>
+  case Expr::CXXDefaultArgExprClass:<br>
+  case Expr::CXXReinterpretCastExprClass:<br>
+  case Expr::DesignatedInitExprClass:<br>
+  case Expr::ExprWithCleanupsClass:<br>
+  case Expr::ExtVectorElementExprClass:<br>
+  case Expr::InitListExprClass:<br>
+  case Expr::MemberExprClass:<br>
+  case Expr::ObjCIsaExprClass:<br>
+  case Expr::ObjCIvarRefExprClass:<br>
+  case Expr::ParenExprClass:<br>
+  case Expr::ParenListExprClass:<br>
+  case Expr::ShuffleVectorExprClass:<br>
+  case Expr::VAArgExprClass:<br>
+    return canSubExprsThrow(*this, E);<br>
+<br>
+    // Some might be dependent for other reasons.<br>
+  case Expr::ArraySubscriptExprClass:<br>
+  case Expr::BinaryOperatorClass:<br>
+  case Expr::CompoundAssignOperatorClass:<br>
+  case Expr::CStyleCastExprClass:<br>
+  case Expr::CXXStaticCastExprClass:<br>
+  case Expr::CXXFunctionalCastExprClass:<br>
+  case Expr::ImplicitCastExprClass:<br>
+  case Expr::MaterializeTemporaryExprClass:<br>
+  case Expr::UnaryOperatorClass: {<br>
+    CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot;<br>
+    return mergeCanThrow(CT, canSubExprsThrow(*this, E));<br>
+  }<br>
+<br>
+    // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.<br>
+  case Expr::StmtExprClass:<br>
+    return CT_Can;<br>
+<br>
+  case Expr::ChooseExprClass:<br>
+    if (E->isTypeDependent() || E->isValueDependent())<br>
+      return CT_Dependent;<br>
+    return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr(Context));<br>
+<br>
+  case Expr::GenericSelectionExprClass:<br>
+    if (cast<GenericSelectionExpr>(E)->isResultDependent())<br>
+      return CT_Dependent;<br>
+    return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr());<br>
+<br>
+    // Some expressions are always dependent.<br>
+  case Expr::CXXDependentScopeMemberExprClass:<br>
+  case Expr::CXXUnresolvedConstructExprClass:<br>
+  case Expr::DependentScopeDeclRefExprClass:<br>
+    return CT_Dependent;<br>
+<br>
+  case Expr::AsTypeExprClass:<br>
+  case Expr::BinaryConditionalOperatorClass:<br>
+  case Expr::BlockExprClass:<br>
+  case Expr::CUDAKernelCallExprClass:<br>
+  case Expr::DeclRefExprClass:<br>
+  case Expr::ObjCBridgedCastExprClass:<br>
+  case Expr::ObjCIndirectCopyRestoreExprClass:<br>
+  case Expr::ObjCProtocolExprClass:<br>
+  case Expr::ObjCSelectorExprClass:<br>
+  case Expr::OffsetOfExprClass:<br>
+  case Expr::PackExpansionExprClass:<br>
+  case Expr::PseudoObjectExprClass:<br>
+  case Expr::SubstNonTypeTemplateParmExprClass:<br>
+  case Expr::SubstNonTypeTemplateParmPackExprClass:<br>
+  case Expr::UnaryExprOrTypeTraitExprClass:<br>
+  case Expr::UnresolvedLookupExprClass:<br>
+  case Expr::UnresolvedMemberExprClass:<br>
+    // FIXME: Can any of the above throw?  If so, when?<br>
+    return CT_Cannot;<br>
+<br>
+  case Expr::AddrLabelExprClass:<br>
+  case Expr::ArrayTypeTraitExprClass:<br>
+  case Expr::AtomicExprClass:<br>
+  case Expr::BinaryTypeTraitExprClass:<br>
+  case Expr::TypeTraitExprClass:<br>
+  case Expr::CXXBoolLiteralExprClass:<br>
+  case Expr::CXXNoexceptExprClass:<br>
+  case Expr::CXXNullPtrLiteralExprClass:<br>
+  case Expr::CXXPseudoDestructorExprClass:<br>
+  case Expr::CXXScalarValueInitExprClass:<br>
+  case Expr::CXXThisExprClass:<br>
+  case Expr::CXXUuidofExprClass:<br>
+  case Expr::CharacterLiteralClass:<br>
+  case Expr::ExpressionTraitExprClass:<br>
+  case Expr::FloatingLiteralClass:<br>
+  case Expr::GNUNullExprClass:<br>
+  case Expr::ImaginaryLiteralClass:<br>
+  case Expr::ImplicitValueInitExprClass:<br>
+  case Expr::IntegerLiteralClass:<br>
+  case Expr::ObjCEncodeExprClass:<br>
+  case Expr::ObjCStringLiteralClass:<br>
+  case Expr::ObjCBoolLiteralExprClass:<br>
+  case Expr::OpaqueValueExprClass:<br>
+  case Expr::PredefinedExprClass:<br>
+  case Expr::SizeOfPackExprClass:<br>
+  case Expr::StringLiteralClass:<br>
+  case Expr::UnaryTypeTraitExprClass:<br>
+    // These expressions can never throw.<br>
+    return CT_Cannot;<br>
+<br>
+#define STMT(CLASS, PARENT) case Expr::CLASS##Class:<br>
+#define STMT_RANGE(Base, First, Last)<br>
+#define LAST_STMT_RANGE(BASE, FIRST, LAST)<br>
+#define EXPR(CLASS, PARENT)<br>
+#define ABSTRACT_STMT(STMT)<br>
+#include "clang/AST/StmtNodes.inc"<br>
+  case Expr::NoStmtClass:<br>
+    llvm_unreachable("Invalid class for expression");<br>
+  }<br>
+  llvm_unreachable("Bogus StmtClass");<br>
+}<br>
+<br>
 } // end namespace clang<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Apr 16 19:58:00 2012<br>
@@ -9773,6 +9773,13 @@<br>
   // FIXME: Is this really right?<br>
   if (CurContext == Func) return;<br>
<br>
+  // Instantiate the exception specification for any function which is<br>
+  // used: CodeGen will need it.<br>
+  if (Func->getTemplateInstantiationPattern() &&<br>
+      Func->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()<br>
+        == EST_Uninstantiated)<br>
+    InstantiateExceptionSpec(Loc, Func);<br>
+<br>
   // Implicit instantiation of function templates and member functions of<br>
   // class templates.<br>
   if (Func->isImplicitlyInstantiable()) {<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Apr 16 19:58:00 2012<br>
@@ -3135,6 +3135,9 @@<br>
             FoundAssign = true;<br>
             const FunctionProtoType *CPT<br>
                 = Operator->getType()->getAs<FunctionProtoType>();<br>
+            CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);<br>
+            if (!CPT)<br>
+              return false;<br>
             if (CPT->getExceptionSpecType() == EST_Delayed)<br>
               return false;<br>
             if (!CPT->isNothrow(Self.Context))<br>
@@ -3174,6 +3177,9 @@<br>
           FoundConstructor = true;<br>
           const FunctionProtoType *CPT<br>
               = Constructor->getType()->getAs<FunctionProtoType>();<br>
+          CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);<br>
+          if (!CPT)<br>
+            return false;<br>
           if (CPT->getExceptionSpecType() == EST_Delayed)<br>
             return false;<br>
           // FIXME: check whether evaluating default arguments can throw.<br>
@@ -3209,6 +3215,9 @@<br>
         if (Constructor->isDefaultConstructor()) {<br>
           const FunctionProtoType *CPT<br>
               = Constructor->getType()->getAs<FunctionProtoType>();<br>
+          CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);<br>
+          if (!CPT)<br>
+            return false;<br>
           if (CPT->getExceptionSpecType() == EST_Delayed)<br>
             return false;<br>
           // TODO: check whether evaluating default arguments can throw.<br>
@@ -5203,9 +5212,9 @@<br>
<br>
 ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand,<br>
                                       SourceLocation RParen) {<br>
+  CanThrowResult CanThrow = canThrow(Operand);<br>
   return Owned(new (Context) CXXNoexceptExpr(Context.BoolTy, Operand,<br>
-                                             Operand->CanThrow(Context),<br>
-                                             KeyLoc, RParen));<br>
+                                             CanThrow, KeyLoc, RParen));<br>
 }<br>
<br>
 ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Apr 16 19:58:00 2012<br>
@@ -11150,6 +11150,7 @@<br>
                                            VK_LValue,<br>
                                            Found.getDecl(),<br>
                                            TemplateArgs);<br>
+    MarkDeclRefReferenced(DRE);<br>
     DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1);<br>
     return DRE;<br>
   }<br>
@@ -11178,6 +11179,7 @@<br>
                                                VK_LValue,<br>
                                                Found.getDecl(),<br>
                                                TemplateArgs);<br>
+        MarkDeclRefReferenced(DRE);<br>
         DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1);<br>
         return DRE;<br>
       } else {<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Apr 16 19:58:00 2012<br>
@@ -153,6 +153,7 @@<br>
 bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {<br>
   switch (Kind) {<br>
   case TemplateInstantiation:<br>
+  case ExceptionSpecInstantiation:<br>
   case DefaultTemplateArgumentInstantiation:<br>
   case DefaultFunctionArgumentInstantiation:<br>
     return true;<br>
@@ -190,6 +191,29 @@<br>
   }<br>
 }<br>
<br>
+Sema::InstantiatingTemplate::<br>
+InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,<br>
+                      FunctionDecl *Entity, ExceptionSpecification,<br>
+                      SourceRange InstantiationRange)<br>
+  : SemaRef(SemaRef),<br>
+    SavedInNonInstantiationSFINAEContext(<br>
+                                        SemaRef.InNonInstantiationSFINAEContext)<br>
+{<br>
+  Invalid = CheckInstantiationDepth(PointOfInstantiation,<br>
+                                    InstantiationRange);<br>
+  if (!Invalid) {<br>
+    ActiveTemplateInstantiation Inst;<br>
+    Inst.Kind = ActiveTemplateInstantiation::ExceptionSpecInstantiation;<br>
+    Inst.PointOfInstantiation = PointOfInstantiation;<br>
+    Inst.Entity = reinterpret_cast<uintptr_t>(Entity);<br>
+    Inst.TemplateArgs = 0;<br>
+    Inst.NumTemplateArgs = 0;<br>
+    Inst.InstantiationRange = InstantiationRange;<br>
+    SemaRef.InNonInstantiationSFINAEContext = false;<br>
+    SemaRef.ActiveTemplateInstantiations.push_back(Inst);<br>
+  }<br>
+}<br>
+<br>
 Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,<br>
                                          SourceLocation PointOfInstantiation,<br>
                                          TemplateDecl *Template,<br>
@@ -592,6 +616,13 @@<br>
         << Active->InstantiationRange;<br>
       break;<br>
     }<br>
+<br>
+    case ActiveTemplateInstantiation::ExceptionSpecInstantiation:<br>
+      Diags.Report(Active->PointOfInstantiation,<br>
+                   diag::note_template_exception_spec_instantiation_here)<br>
+        << cast<FunctionDecl>((Decl *)Active->Entity)<br>
+        << Active->InstantiationRange;<br>
+      break;<br>
     }<br>
   }<br>
 }<br>
@@ -609,6 +640,7 @@<br>
     switch(Active->Kind) {<br>
     case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:<br>
     case ActiveTemplateInstantiation::TemplateInstantiation:<br>
+    case ActiveTemplateInstantiation::ExceptionSpecInstantiation:<br>
       // This is a template instantiation, so there is no SFINAE.<br>
       return llvm::Optional<TemplateDeductionInfo *>();<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Apr 16 19:58:00 2012<br>
@@ -2215,6 +2215,194 @@<br>
   return NewTInfo;<br>
 }<br>
<br>
+/// Introduce the instantiated function parameters into the local<br>
+/// instantiation scope, and set the parameter names to those used<br>
+/// in the template.<br>
+static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,<br>
+                                             const FunctionDecl *PatternDecl,<br>
+                                             LocalInstantiationScope &Scope,<br>
+                           const MultiLevelTemplateArgumentList &TemplateArgs) {<br>
+  unsigned FParamIdx = 0;<br>
+  for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {<br>
+    const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);<br>
+    if (!PatternParam->isParameterPack()) {<br>
+      // Simple case: not a parameter pack.<br>
+      assert(FParamIdx < Function->getNumParams());<br>
+      ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);<br>
+      FunctionParam->setDeclName(PatternParam->getDeclName());<br>
+      Scope.InstantiatedLocal(PatternParam, FunctionParam);<br>
+      ++FParamIdx;<br>
+      continue;<br>
+    }<br>
+<br>
+    // Expand the parameter pack.<br>
+    Scope.MakeInstantiatedLocalArgPack(PatternParam);<br>
+    unsigned NumArgumentsInExpansion<br>
+      = S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);<br>
+    for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) {<br>
+      ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);<br>
+      FunctionParam->setDeclName(PatternParam->getDeclName());<br>
+      Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);<br>
+      ++FParamIdx;<br>
+    }<br>
+  }<br>
+}<br>
+<br>
+static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,<br>
+                                     const FunctionProtoType *Proto,<br>
+                           const MultiLevelTemplateArgumentList &TemplateArgs) {<br>
+  // C++11 [expr.prim.general]p3:<br>
+  //   If a declaration declares a member function or member function<br>
+  //   template of a class X, the expression this is a prvalue of type<br>
+  //   "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq<br>
+  //   and the end of the function-definition, member-declarator, or<br>
+  //   declarator.<br>
+  CXXRecordDecl *ThisContext = 0;<br>
+  unsigned ThisTypeQuals = 0;<br>
+  if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) {<br>
+    ThisContext = Method->getParent();<br>
+    ThisTypeQuals = Method->getTypeQualifiers();<br>
+  }<br>
+  Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,<br>
+                                   SemaRef.getLangOpts().CPlusPlus0x);<br>
+<br>
+  // The function has an exception specification or a "noreturn"<br>
+  // attribute. Substitute into each of the exception types.<br>
+  SmallVector<QualType, 4> Exceptions;<br>
+  for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) {<br>
+    // FIXME: Poor location information!<br>
+    if (const PackExpansionType *PackExpansion<br>
+          = Proto->getExceptionType(I)->getAs<PackExpansionType>()) {<br>
+      // We have a pack expansion. Instantiate it.<br>
+      SmallVector<UnexpandedParameterPack, 2> Unexpanded;<br>
+      SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),<br>
+                                              Unexpanded);<br>
+      assert(!Unexpanded.empty() &&<br>
+             "Pack expansion without parameter packs?");<br>
+<br>
+      bool Expand = false;<br>
+      bool RetainExpansion = false;<br>
+      llvm::Optional<unsigned> NumExpansions<br>
+                                        = PackExpansion->getNumExpansions();<br>
+      if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),<br>
+                                                  SourceRange(),<br>
+                                                  Unexpanded,<br>
+                                                  TemplateArgs,<br>
+                                                  Expand,<br>
+                                                  RetainExpansion,<br>
+                                                  NumExpansions))<br>
+        break;<br>
+<br>
+      if (!Expand) {<br>
+        // We can't expand this pack expansion into separate arguments yet;<br>
+        // just substitute into the pattern and create a new pack expansion<br>
+        // type.<br>
+        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);<br>
+        QualType T = SemaRef.SubstType(PackExpansion->getPattern(),<br>
+                                       TemplateArgs,<br>
+                                     New->getLocation(), New->getDeclName());<br>
+        if (T.isNull())<br>
+          break;<br>
+<br>
+        T = SemaRef.Context.getPackExpansionType(T, NumExpansions);<br>
+        Exceptions.push_back(T);<br>
+        continue;<br>
+      }<br>
+<br>
+      // Substitute into the pack expansion pattern for each template<br>
+      bool Invalid = false;<br>
+      for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {<br>
+        Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx);<br>
+<br>
+        QualType T = SemaRef.SubstType(PackExpansion->getPattern(),<br>
+                                       TemplateArgs,<br>
+                                     New->getLocation(), New->getDeclName());<br>
+        if (T.isNull()) {<br>
+          Invalid = true;<br>
+          break;<br>
+        }<br>
+<br>
+        Exceptions.push_back(T);<br>
+      }<br>
+<br>
+      if (Invalid)<br>
+        break;<br>
+<br>
+      continue;<br>
+    }<br>
+<br>
+    QualType T<br>
+      = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,<br>
+                          New->getLocation(), New->getDeclName());<br>
+    if (T.isNull() ||<br>
+        SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))<br>
+      continue;<br>
+<br>
+    Exceptions.push_back(T);<br>
+  }<br>
+  Expr *NoexceptExpr = 0;<br>
+  if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {<br>
+    EnterExpressionEvaluationContext Unevaluated(SemaRef,<br>
+                                                 Sema::ConstantEvaluated);<br>
+    ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);<br>
+    if (E.isUsable())<br>
+      E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart());<br>
+<br>
+    if (E.isUsable()) {<br>
+      NoexceptExpr = E.take();<br>
+      if (!NoexceptExpr->isTypeDependent() &&<br>
+          !NoexceptExpr->isValueDependent())<br>
+        NoexceptExpr = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,<br>
+          0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression),<br>
+          /*AllowFold*/ false).take();<br>
+    }<br>
+  }<br>
+<br>
+  // Rebuild the function type<br>
+  const FunctionProtoType *NewProto<br>
+    = New->getType()->getAs<FunctionProtoType>();<br>
+  assert(NewProto && "Template instantiation without function prototype?");<br>
+<br>
+  FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();<br>
+  EPI.ExceptionSpecType = Proto->getExceptionSpecType();<br>
+  EPI.NumExceptions = Exceptions.size();<br>
+  EPI.Exceptions = Exceptions.data();<br>
+  EPI.NoexceptExpr = NoexceptExpr;<br>
+<br>
+  New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),<br>
+                                               NewProto->arg_type_begin(),<br>
+                                               NewProto->getNumArgs(),<br>
+                                               EPI));<br>
+}<br>
+<br>
+void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,<br>
+                                    FunctionDecl *Decl) {<br>
+  FunctionDecl *Tmpl = Decl->getTemplateInstantiationPattern();<br>
+  assert(Tmpl && "can't instantiate non-template");<br>
+<br>
+  if (Decl->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()<br>
+        != EST_Uninstantiated)<br>
+    return;<br>
+<br>
+  InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,<br>
+                             InstantiatingTemplate::ExceptionSpecification());<br>
+  if (Inst)<br>
+    return;<br>
+<br>
+  // Enter the scope of this instantiation. We don't use<br>
+  // PushDeclContext because we don't have a scope.<br>
+  Sema::ContextRAII savedContext(*this, Decl);<br>
+  LocalInstantiationScope Scope(*this);<br>
+<br>
+  MultiLevelTemplateArgumentList TemplateArgs =<br>
+    getTemplateInstantiationArgs(Decl, 0, /*RelativeToPrimary*/true);<br>
+<br>
+  addInstantiatedParametersToScope(*this, Decl, Tmpl, Scope, TemplateArgs);<br>
+<br>
+  const FunctionProtoType *Proto = Tmpl->getType()->castAs<FunctionProtoType>();<br>
+  ::InstantiateExceptionSpec(*this, Decl, Proto, TemplateArgs);<br>
+}<br>
+<br>
 /// \brief Initializes the common fields of an instantiation function<br>
 /// declaration (New) from the corresponding fields of its template (Tmpl).<br>
 ///<br>
@@ -2252,135 +2440,32 @@<br>
   assert(Proto && "Function template without prototype?");<br>
<br>
   if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) {<br>
-    // C++11 [expr.prim.general]p3:<br>
-    //   If a declaration declares a member function or member function<br>
-    //   template of a class X, the expression this is a prvalue of type<br>
-    //   "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq<br>
-    //   and the end of the function-definition, member-declarator, or<br>
-    //   declarator.<br>
-    CXXRecordDecl *ThisContext = 0;<br>
-    unsigned ThisTypeQuals = 0;<br>
-    if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) {<br>
-      ThisContext = Method->getParent();<br>
-      ThisTypeQuals = Method->getTypeQualifiers();<br>
-    }<br>
-    Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,<br>
-                                     SemaRef.getLangOpts().CPlusPlus0x);<br>
-<br>
-<br>
-    // The function has an exception specification or a "noreturn"<br>
-    // attribute. Substitute into each of the exception types.<br>
-    SmallVector<QualType, 4> Exceptions;<br>
-    for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) {<br>
-      // FIXME: Poor location information!<br>
-      if (const PackExpansionType *PackExpansion<br>
-            = Proto->getExceptionType(I)->getAs<PackExpansionType>()) {<br>
-        // We have a pack expansion. Instantiate it.<br>
-        SmallVector<UnexpandedParameterPack, 2> Unexpanded;<br>
-        SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),<br>
-                                                Unexpanded);<br>
-        assert(!Unexpanded.empty() &&<br>
-               "Pack expansion without parameter packs?");<br>
-<br>
-        bool Expand = false;<br>
-        bool RetainExpansion = false;<br>
-        llvm::Optional<unsigned> NumExpansions<br>
-                                          = PackExpansion->getNumExpansions();<br>
-        if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),<br>
-                                                    SourceRange(),<br>
-                                                    Unexpanded,<br>
-                                                    TemplateArgs,<br>
-                                                    Expand,<br>
-                                                    RetainExpansion,<br>
-                                                    NumExpansions))<br>
-          break;<br>
-<br>
-        if (!Expand) {<br>
-          // We can't expand this pack expansion into separate arguments yet;<br>
-          // just substitute into the pattern and create a new pack expansion<br>
-          // type.<br>
-          Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);<br>
-          QualType T = SemaRef.SubstType(PackExpansion->getPattern(),<br>
-                                         TemplateArgs,<br>
-                                       New->getLocation(), New->getDeclName());<br>
-          if (T.isNull())<br>
-            break;<br>
-<br>
-          T = SemaRef.Context.getPackExpansionType(T, NumExpansions);<br>
-          Exceptions.push_back(T);<br>
-          continue;<br>
-        }<br>
-<br>
-        // Substitute into the pack expansion pattern for each template<br>
-        bool Invalid = false;<br>
-        for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {<br>
-          Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx);<br>
-<br>
-          QualType T = SemaRef.SubstType(PackExpansion->getPattern(),<br>
-                                         TemplateArgs,<br>
-                                       New->getLocation(), New->getDeclName());<br>
-          if (T.isNull()) {<br>
-            Invalid = true;<br>
-            break;<br>
-          }<br>
-<br>
-          Exceptions.push_back(T);<br>
-        }<br>
-<br>
-        if (Invalid)<br>
-          break;<br>
-<br>
-        continue;<br>
-      }<br>
-<br>
-      QualType T<br>
-        = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,<br>
-                            New->getLocation(), New->getDeclName());<br>
-      if (T.isNull() ||<br>
-          SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))<br>
-        continue;<br>
+    FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();<br>
<br>
-      Exceptions.push_back(T);<br>
-    }<br>
-    Expr *NoexceptExpr = 0;<br>
-    if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {<br>
-      EnterExpressionEvaluationContext Unevaluated(SemaRef,<br>
-                                                   Sema::ConstantEvaluated);<br>
-      ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);<br>
-      if (E.isUsable())<br>
-        E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart());<br>
-<br>
-      if (E.isUsable()) {<br>
-        NoexceptExpr = E.take();<br>
-        if (!NoexceptExpr->isTypeDependent() &&<br>
-            !NoexceptExpr->isValueDependent())<br>
-          NoexceptExpr = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,<br>
-            0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression),<br>
-            /*AllowFold*/ false).take();<br>
-      }<br>
+    // DR1330: In C++11, defer instantiation of a non-trivial<br>
+    // exception specification.<br>
+    if (SemaRef.getLangOpts().CPlusPlus0x &&<br>
+        EPI.ExceptionSpecType != EST_None &&<br>
+        EPI.ExceptionSpecType != EST_DynamicNone &&<br>
+        EPI.ExceptionSpecType != EST_BasicNoexcept) {<br>
+      // Mark the function has having an uninstantiated exception specification.<br>
+      const FunctionProtoType *NewProto<br>
+        = New->getType()->getAs<FunctionProtoType>();<br>
+      assert(NewProto && "Template instantiation without function prototype?");<br>
+      EPI = NewProto->getExtProtoInfo();<br>
+      EPI.ExceptionSpecType = EST_Uninstantiated;<br>
+      EPI.ExceptionSpecDecl = New;<br>
+      New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),<br>
+                                                   NewProto->arg_type_begin(),<br>
+                                                   NewProto->getNumArgs(),<br>
+                                                   EPI));<br>
+    } else {<br>
+      ::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);<br>
     }<br>
-<br>
-    // Rebuild the function type<br>
-<br>
-    FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();<br>
-    EPI.ExceptionSpecType = Proto->getExceptionSpecType();<br>
-    EPI.NumExceptions = Exceptions.size();<br>
-    EPI.Exceptions = Exceptions.data();<br>
-    EPI.NoexceptExpr = NoexceptExpr;<br>
-    EPI.ExtInfo = Proto->getExtInfo();<br>
-<br>
-    const FunctionProtoType *NewProto<br>
-      = New->getType()->getAs<FunctionProtoType>();<br>
-    assert(NewProto && "Template instantiation without function prototype?");<br>
-    New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),<br>
-                                                 NewProto->arg_type_begin(),<br>
-                                                 NewProto->getNumArgs(),<br>
-                                                 EPI));<br>
   }<br>
<br>
-  const FunctionDecl* Definition = Tmpl;<br>
-<br>
   // Get the definition. Leaves the variable unchanged if undefined.<br>
+  const FunctionDecl *Definition = Tmpl;<br>
   Tmpl->isDefined(Definition);<br>
<br>
   SemaRef.InstantiateAttrs(TemplateArgs, Definition, New,<br>
@@ -2538,33 +2623,8 @@<br>
   MultiLevelTemplateArgumentList TemplateArgs =<br>
     getTemplateInstantiationArgs(Function, 0, false, PatternDecl);<br>
<br>
-  // Introduce the instantiated function parameters into the local<br>
-  // instantiation scope, and set the parameter names to those used<br>
-  // in the template.<br>
-  unsigned FParamIdx = 0;<br>
-  for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {<br>
-    const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);<br>
-    if (!PatternParam->isParameterPack()) {<br>
-      // Simple case: not a parameter pack.<br>
-      assert(FParamIdx < Function->getNumParams());<br>
-      ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);<br>
-      FunctionParam->setDeclName(PatternParam->getDeclName());<br>
-      Scope.InstantiatedLocal(PatternParam, FunctionParam);<br>
-      ++FParamIdx;<br>
-      continue;<br>
-    }<br>
-<br>
-    // Expand the parameter pack.<br>
-    Scope.MakeInstantiatedLocalArgPack(PatternParam);<br>
-    unsigned NumArgumentsInExpansion<br>
-      = getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);<br>
-    for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) {<br>
-      ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);<br>
-      FunctionParam->setDeclName(PatternParam->getDeclName());<br>
-      Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);<br>
-      ++FParamIdx;<br>
-    }<br>
-  }<br>
+  addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,<br>
+                                   TemplateArgs);<br>
<br>
   if (PatternDecl->isDefaulted()) {<br>
     ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);<br>
<br>
Modified: cfe/trunk/lib/Sema/TreeTransform.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/TreeTransform.h (original)<br>
+++ cfe/trunk/lib/Sema/TreeTransform.h Mon Apr 16 19:58:00 2012<br>
@@ -4181,10 +4181,7 @@<br>
                                                    unsigned ThisTypeQuals) {<br>
   // Transform the parameters and return type.<br>
   //<br>
-  // We instantiate in source order, with the return type first followed by<br>
-  // the parameters, because users tend to expect this (even if they shouldn't<br>
-  // rely on it!).<br>
-  //<br>
+  // We are required to instantiate the params and return type in source order.<br>
   // When the function has a trailing return type, we instantiate the<br>
   // parameters before the return type,  since the return type can then refer<br>
   // to the parameters themselves (via decltype, sizeof, etc.).<br>
@@ -4230,6 +4227,8 @@<br>
       return QualType();<br>
   }<br>
<br>
+  // FIXME: Need to transform the exception-specification too.<br>
+<br>
   QualType Result = TL.getType();<br>
   if (getDerived().AlwaysRebuild() ||<br>
       ResultType != T->getResultType() ||<br>
<br>
Modified: cfe/trunk/test/CXX/except/except.spec/p1.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p1.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p1.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/CXX/except/except.spec/p1.cpp (original)<br>
+++ cfe/trunk/test/CXX/except/except.spec/p1.cpp Mon Apr 16 19:58:00 2012<br>
@@ -65,7 +65,7 @@<br>
   }<br>
<br>
   template<typename T><br>
-  void g(T x) noexcept((sizeof(T) == sizeof(int)) || f(x)) { }<br>
+  void g(T x) noexcept((sizeof(T) == sizeof(int)) || noexcept(f(x))) { }<br>
<br>
   void h() {<br>
     g(1);<br>
@@ -77,5 +77,5 @@<br>
     static int f() noexcept(1/X) { return 10; }  // expected-error{{argument to noexcept specifier must be a constant expression}} expected-note{{division by zero}}<br>
   };<br>
<br>
-  void g() { A<0>::f(); } // expected-note{{in instantiation of template class 'PR11084::A<0>' requested here}}<br>
+  void g() { A<0>::f(); } // expected-note{{in instantiation of exception specification for 'f' requested here}}<br>
 }<br>
<br>
Added: cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp?rev=154886&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp?rev=154886&view=auto</a><br>

==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp (added)<br>
+++ cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp Mon Apr 16 19:58:00 2012<br>
@@ -0,0 +1,18 @@<br>
+// RUN: %clang_cc1 -std=c++11 -verify -emit-llvm %s -o - | FileCheck %s<br>
+<br>
+template<typename T> void f() noexcept(sizeof(T) == 4);<br>
+<br>
+void g() {<br>
+  // CHECK: declare void @_Z1fIiEvv() nounwind<br>
+  f<int>();<br>
+  // CHECK: declare void @_Z1fIA2_iEvv()<br>
+  f<int[2]>();<br>
+  // CHECK: declare void @_Z1fIfEvv() nounwind<br>
+  void (*f1)() = &f<float>;<br>
+  // CHECK: declare void @_Z1fIdEvv()<br>
+  void (*f2)() = &f<double>;<br>
+  // CHECK: declare void @_Z1fIA4_cEvv() nounwind<br>
+  (void)&f<char[4]>;<br>
+  // CHECK: declare void @_Z1fIcEvv()<br>
+  (void)&f<char>;<br>
+}<br>
<br>
Modified: cfe/trunk/test/SemaTemplate/instantiate-declref.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-declref.cpp?rev=154886&r1=154885&r2=154886&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-declref.cpp?rev=154886&r1=154885&r2=154886&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/SemaTemplate/instantiate-declref.cpp (original)<br>
+++ cfe/trunk/test/SemaTemplate/instantiate-declref.cpp Mon Apr 16 19:58:00 2012<br>
@@ -105,3 +105,13 @@<br>
   }<br>
   template void f(int const &); // expected-note {{requested here}}<br>
 }<br>
+<br>
+namespace test2 {<br>
+  template<typename T> void f() {<br>
+    T::error; // expected-error {{no member}}<br>
+  }<br>
+  void g() {<br>
+    // This counts as an odr-use, so should trigger the instantiation of f<int>.<br>
+    (void)&f<int>; // expected-note {{here}}<br>
+  }<br>
+}<br>
<br>
Added: cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp?rev=154886&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp?rev=154886&view=auto</a><br>

==============================================================================<br>
--- cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp (added)<br>
+++ cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp Mon Apr 16 19:58:00 2012<br>
@@ -0,0 +1,107 @@<br>
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 %s<br>
+<br>
+// DR1330: an exception specification for a function template is only<br>
+// instantiated when it is needed.<br>
+<br>
+template<typename T> void f1(T*) throw(T); // expected-error{{incomplete type 'Incomplete' is not allowed in exception specification}}<br>
+struct Incomplete; // expected-note{{forward}}<br>
+<br>
+void test_f1(Incomplete *incomplete_p, int *int_p) {<br>
+  f1(int_p);<br>
+  f1(incomplete_p); // expected-note{{instantiation of exception spec}}<br>
+}<br>
+<br>
+template<typename T> struct A {<br>
+  template<typename U> struct B {<br>
+    static void f() noexcept(A<U>().n);<br>
+  };<br>
+<br>
+  constexpr A() : n(true) {}<br>
+  bool n;<br>
+};<br>
+<br>
+static_assert(noexcept(A<int>::B<char>::f()), "");<br>
+<br>
+template<unsigned N> struct S {<br>
+  static void recurse() noexcept(noexcept(S<N+1>::recurse())); // \<br>
+  // expected-error {{no member named 'recurse'}} \<br>
+  // expected-note 9{{instantiation of exception spec}}<br>
+};<br>
+decltype(S<0>::recurse()) *pVoid1 = 0; // ok, exception spec not needed<br>
+decltype(&S<0>::recurse) pFn = 0; // ok, exception spec not needed<br>
+<br>
+template<> struct S<10> {};<br>
+void (*pFn2)() noexcept = &S<0>::recurse; // expected-note {{instantiation of exception spec}}<br>
+<br>
+<br>
+template<typename T> T go(T a) noexcept(noexcept(go(a))); // \<br>
+// expected-error 16{{call to function 'go' that is neither visible}} \<br>
+// expected-note 16{{'go' should be declared prior to the call site}} \<br>
+// expected-error {{recursive template instantiation exceeded maximum depth of 16}} \<br>
+// expected-error {{use of undeclared identifier 'go'}} \<br>
+<br>
+void f() {<br>
+  int k = go(0); // \<br>
+  // expected-note {{in instantiation of exception specification for 'go<int>' requested here}}<br>
+}<br>
+<br>
+<br>
+namespace dr1330_example {<br>
+  template <class T> struct A {<br>
+    void f(...) throw (typename T::X); // expected-error {{'int'}}<br>
+    void f(int);<br>
+  };<br>
+<br>
+  int main() {<br>
+    A<int>().f(42);<br>
+  }<br>
+<br>
+  int test2() {<br>
+    struct S {<br>
+      template<typename T><br>
+      static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; } // \<br>
+      // expected-note {{instantiation of exception spec}}<br>
+      typedef decltype(f<S>()) X;<br>
+    };<br>
+    S().f<S>(); // ok<br>
+    S().f<int>(); // expected-note {{instantiation of exception spec}}<br>
+  }<br>
+}<br>
+<br>
+namespace core_19754_example {<br>
+  template<typename T> T declval() noexcept;<br>
+<br>
+  template<typename T, typename = decltype(T(declval<T&&>()))><br>
+  struct is_movable { static const bool value = true; };<br>
+<br>
+  template<typename T><br>
+  struct wrap {<br>
+    T val;<br>
+    void irrelevant(wrap &p) noexcept(is_movable<T>::value);<br>
+  };<br>
+<br>
+  template<typename T><br>
+  struct base {<br>
+     base() {}<br>
+     base(const typename T::type1 &);<br>
+     base(const typename T::type2 &);<br>
+  };<br>
+<br>
+  template<typename T><br>
+  struct type1 {<br>
+     wrap<typename T::base> base;<br>
+  };<br>
+<br>
+  template<typename T><br>
+  struct type2 {<br>
+     wrap<typename T::base> base;<br>
+  };<br>
+<br>
+  struct types {<br>
+     typedef base<types> base;<br>
+     typedef type1<types> type1;<br>
+     typedef type2<types> type2;<br>
+  };<br>
+<br>
+  base<types> val = base<types>();<br>
+}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br>