[cfe-commits] r127537 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/Analysis/ lib/CodeGen/ lib/Parse/ lib/Sema/ lib/Serialization/ test/CXX/except/except.spec/ test/SemaCXX/

Sebastian Redl sebastian.redl at getdesigned.at
Sat Mar 12 03:50:43 PST 2011


Author: cornedbee
Date: Sat Mar 12 05:50:43 2011
New Revision: 127537

URL: http://llvm.org/viewvc/llvm-project?rev=127537&view=rev
Log:
Propagate the new exception information to FunctionProtoType.
Change the interface to expose the new information and deal with the enormous fallout.
Introduce the new ExceptionSpecificationType value EST_DynamicNone to more easily deal with empty throw specifications.
Update the tests for noexcept and fix the various bugs uncovered, such as lack of tentative parsing support.

Added:
    cfe/trunk/test/CXX/except/except.spec/p2-dynamic-types.cpp
    cfe/trunk/test/CXX/except/except.spec/p2-places.cpp
    cfe/trunk/test/CXX/except/except.spec/p3.cpp
    cfe/trunk/test/CXX/except/except.spec/p5-pointers.cpp
    cfe/trunk/test/CXX/except/except.spec/p5-virtual.cpp
Removed:
    cfe/trunk/test/SemaCXX/exception-spec.cpp
Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/DeclPrinter.cpp
    cfe/trunk/lib/AST/DumpXML.cpp
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/AST/TypePrinter.cpp
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/lib/CodeGen/CGCall.cpp
    cfe/trunk/lib/CodeGen/CGException.cpp
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/ParseTentative.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/CXX/except/except.spec/p1.cpp

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Sat Mar 12 05:50:43 2011
@@ -2430,19 +2430,17 @@
   }
 
   FunctionProtoType(QualType result, const QualType *args, unsigned numArgs,
-                    QualType canonical, const ExtProtoInfo &epi);
+                    QualType canonical, const ExtProtoInfo &epi,
+                    const ASTContext *Context);
 
   /// NumArgs - The number of arguments this function has, not counting '...'.
   unsigned NumArgs : 20;
 
   /// NumExceptions - The number of types in the exception spec, if any.
-  unsigned NumExceptions : 10;
+  unsigned NumExceptions : 9;
 
-  /// HasExceptionSpec - Whether this function has an exception spec at all.
-  unsigned HasExceptionSpec : 1;
-
-  /// HasAnyExceptionSpec - Whether this function has a throw(...) spec.
-  unsigned HasAnyExceptionSpec : 1;
+  /// ExceptionSpecType - The type of exception specification this function has.
+  unsigned ExceptionSpecType : 3;
 
   /// ArgInfo - There is an variable size array after the class in memory that
   /// holds the argument types.
@@ -2450,6 +2448,19 @@
   /// Exceptions - There is another variable size array after ArgInfo that
   /// holds the exception types.
 
+  /// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
+  /// to the expression in the noexcept() specifier.
+
+  /// Context - If there is a NoexceptExpr, we need to store a pointer to the
+  /// ASTContext as well. We do it right after NoexceptExpr.
+
+  const ASTContext *getContext() const {
+    // Context sits after NoexceptExpr, one pointer past where the arguments end
+    if(getExceptionSpecType() == EST_ComputedNoexcept)
+      return *(reinterpret_cast<const ASTContext *const *>(arg_type_end()) + 1);
+    return 0;
+  }
+
   friend class ASTContext;  // ASTContext creates these.
 
 public:
@@ -2463,36 +2474,66 @@
     ExtProtoInfo EPI;
     EPI.ExtInfo = getExtInfo();
     EPI.Variadic = isVariadic();
-    EPI.ExceptionSpecType = hasExceptionSpec() ?
-        (hasAnyExceptionSpec() ? EST_DynamicAny : EST_Dynamic) : EST_None;
+    EPI.ExceptionSpecType = getExceptionSpecType();
     EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals());
     EPI.RefQualifier = getRefQualifier();
-    EPI.NumExceptions = NumExceptions;
-    EPI.Exceptions = exception_begin();
+    if (EPI.ExceptionSpecType == EST_Dynamic) {
+      EPI.NumExceptions = NumExceptions;
+      EPI.Exceptions = exception_begin();
+    } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
+      EPI.NoexceptExpr = getNoexceptExpr();
+    }
     return EPI;
   }
 
-  bool hasExceptionSpec() const { return HasExceptionSpec; }
-  bool hasAnyExceptionSpec() const { return HasAnyExceptionSpec; }
+  /// \brief Get the kind of exception specification on this function.
+  ExceptionSpecificationType getExceptionSpecType() const {
+    return static_cast<ExceptionSpecificationType>(ExceptionSpecType);
+  }
+  /// \brief Return whether this function has any kind of exception spec.
+  bool hasExceptionSpec() const {
+    return getExceptionSpecType() != EST_None;
+  }
+  /// \brief Return whether this function has a dynamic (throw) exception spec.
+  bool hasDynamicExceptionSpec() const {
+    return isDynamicExceptionSpec(getExceptionSpecType());
+  }
+  /// \brief Return whther this function has a noexcept exception spec.
+  bool hasNoexceptExceptionSpec() const {
+    return isNoexceptExceptionSpec(getExceptionSpecType());
+  }
+  /// \brief Result type of getNoexceptSpec().
+  enum NoexceptResult {
+    NR_NoNoexcept,  ///< There is no noexcept specifier.
+    NR_BadNoexcept, ///< The noexcept specifier has a bad expression.
+    NR_Dependent,   ///< The noexcept specifier is dependent.
+    NR_Throw,       ///< The noexcept specifier evaluates to false.
+    NR_Nothrow      ///< The noexcept specifier evaluates to true.
+  };
+  /// \brief Get the meaning of the noexcept spec on this function, if any.
+  NoexceptResult getNoexceptSpec() const;
   unsigned getNumExceptions() const { return NumExceptions; }
   QualType getExceptionType(unsigned i) const {
     assert(i < NumExceptions && "Invalid exception number!");
     return exception_begin()[i];
   }
-  bool hasEmptyExceptionSpec() const {
-    return hasExceptionSpec() && !hasAnyExceptionSpec() &&
-      getNumExceptions() == 0;
-  }
-
-  /// \brief Returns true if this function type has a non-throwing
-  /// exception-specification.
-  bool hasNonThrowingExceptionSpec() const {
-    // FIXME: this needs to be updated for C++0x.
-    return hasEmptyExceptionSpec();
+  Expr *getNoexceptExpr() const {
+    if (getExceptionSpecType() != EST_ComputedNoexcept)
+      return 0;
+    // NoexceptExpr sits where the arguments end.
+    return *reinterpret_cast<Expr *const *>(arg_type_end());
+  }
+  bool isNothrow() const {
+    ExceptionSpecificationType EST = getExceptionSpecType();
+    if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
+      return true;
+    if (EST != EST_ComputedNoexcept)
+      return false;
+    return getNoexceptSpec() == NR_Nothrow;
   }
 
   using FunctionType::isVariadic;
-  
+
   /// \brief Determines whether this function prototype contains a
   /// parameter pack at the end.
   ///
@@ -2521,6 +2562,8 @@
     return arg_type_end();
   }
   exception_iterator exception_end() const {
+    if (getExceptionSpecType() != EST_Dynamic)
+      return exception_begin();
     return exception_begin() + NumExceptions;
   }
 
@@ -2535,7 +2578,7 @@
   void Profile(llvm::FoldingSetNodeID &ID);
   static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
                       arg_type_iterator ArgTys, unsigned NumArgs,
-                      const ExtProtoInfo &EPI);
+                      const ExtProtoInfo &EPI, const ASTContext *Context);
 };
 
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Mar 12 05:50:43 2011
@@ -560,6 +560,8 @@
   "exception specifications of %select{return|argument}0 types differ">;
 def warn_missing_exception_specification : Warning<
   "%0 is missing exception specification '%1'">;
+def err_noexcept_needs_constant_expression : Error<
+  "argument to noexcept specifier must be a constant expression">;
 
 // C++ access checking
 def err_class_redeclared_with_different_access : Error<

Modified: cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h (original)
+++ cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h Sat Mar 12 05:50:43 2011
@@ -19,14 +19,15 @@
 /// \brief The various types of exception specifications that exist in C++0x.
 enum ExceptionSpecificationType {
   EST_None,            ///< no exception specification
-  EST_Dynamic,         ///< throw() or throw(T1, T2)
-  EST_DynamicAny,      ///< Microsoft throw(...) extension
+  EST_DynamicNone,     ///< throw()
+  EST_Dynamic,         ///< throw(T1, T2)
+  EST_MSAny,           ///< Microsoft throw(...) extension
   EST_BasicNoexcept,   ///< noexcept
   EST_ComputedNoexcept ///< noexcept(expression)
 };
 
 inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
-  return ESpecType == EST_Dynamic || ESpecType == EST_DynamicAny;
+  return ESpecType >= EST_DynamicNone && ESpecType <= EST_MSAny;
 }
 
 inline bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType) {

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat Mar 12 05:50:43 2011
@@ -757,7 +757,8 @@
       const FunctionProtoType *Old, SourceLocation OldLoc,
       const FunctionProtoType *New, SourceLocation NewLoc,
       bool *MissingExceptionSpecification = 0,
-      bool *MissingEmptyExceptionSpecification = 0);
+      bool *MissingEmptyExceptionSpecification = 0,
+      bool AllowNoexceptAllMatchWithNoSpec = false);
   bool CheckExceptionSpecSubset(
       const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
       const FunctionProtoType *Superset, SourceLocation SuperLoc,
@@ -1076,8 +1077,9 @@
   bool MergeFunctionDecl(FunctionDecl *New, Decl *Old);
   bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old);
   void mergeObjCMethodDecls(ObjCMethodDecl *New, const ObjCMethodDecl *Old);
-  void MergeVarDeclTypes(VarDecl *New, VarDecl *Old);
   void MergeVarDecl(VarDecl *New, LookupResult &OldDecls);
+  void MergeVarDeclTypes(VarDecl *New, VarDecl *Old);
+  void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
   bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
 
   // AssignmentAction - This is used by all the assignment diagnostic functions

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Sat Mar 12 05:50:43 2011
@@ -1909,7 +1909,7 @@
   // Unique functions, to guarantee there is only one function of a particular
   // structure.
   llvm::FoldingSetNodeID ID;
-  FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI);
+  FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI, this);
 
   void *InsertPos = 0;
   if (FunctionProtoType *FTP =
@@ -1953,14 +1953,20 @@
 
   // FunctionProtoType objects are allocated with extra bytes after them
   // for two variable size arrays (for parameter and exception types) at the
-  // end of them.
+  // end of them. Instead of the exception types, there could be a noexcept
+  // expression and a context pointer.
   size_t Size = sizeof(FunctionProtoType) +
-                NumArgs * sizeof(QualType) +
-                EPI.NumExceptions * sizeof(QualType);
+                NumArgs * sizeof(QualType);
+  if (EPI.ExceptionSpecType == EST_Dynamic)
+    Size += EPI.NumExceptions * sizeof(QualType);
+  else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
+    Size += sizeof(Expr*) + sizeof(ASTContext*);
+  }
   FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
   FunctionProtoType::ExtProtoInfo newEPI = EPI;
   newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
-  new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI);
+  new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI,
+                              this);
   Types.push_back(FTP);
   FunctionProtoTypes.InsertNode(FTP, InsertPos);
   return QualType(FTP, 0);

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Sat Mar 12 05:50:43 2011
@@ -521,16 +521,21 @@
     }
     if (Proto1->isVariadic() != Proto2->isVariadic())
       return false;
-    if (Proto1->hasExceptionSpec() != Proto2->hasExceptionSpec())
+    if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType())
       return false;
-    if (Proto1->hasAnyExceptionSpec() != Proto2->hasAnyExceptionSpec())
-      return false;
-    if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
-      return false;
-    for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
+    if (Proto1->getExceptionSpecType() == EST_Dynamic) {
+      if (Proto1->getNumExceptions() != Proto2->getNumExceptions())
+        return false;
+      for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) {
+        if (!IsStructurallyEquivalent(Context,
+                                      Proto1->getExceptionType(I),
+                                      Proto2->getExceptionType(I)))
+          return false;
+      }
+    } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) {
       if (!IsStructurallyEquivalent(Context,
-                                    Proto1->getExceptionType(I),
-                                    Proto2->getExceptionType(I)))
+                                    Proto1->getNoexceptExpr(),
+                                    Proto2->getNoexceptExpr()))
         return false;
     }
     if (Proto1->getTypeQuals() != Proto2->getTypeQuals())

Modified: cfe/trunk/lib/AST/DeclPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclPrinter.cpp (original)
+++ cfe/trunk/lib/AST/DeclPrinter.cpp Sat Mar 12 05:50:43 2011
@@ -412,22 +412,32 @@
       if (TypeQuals & Qualifiers::Restrict)
         Proto += " restrict";
     }
-    
-    if (FT && FT->hasExceptionSpec()) {
+
+    if (FT && FT->hasDynamicExceptionSpec()) {
       Proto += " throw(";
-      if (FT->hasAnyExceptionSpec())
+      if (FT->getExceptionSpecType() == EST_MSAny)
         Proto += "...";
       else 
         for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) {
           if (I)
             Proto += ", ";
-          
-          
+
           std::string ExceptionType;
           FT->getExceptionType(I).getAsStringInternal(ExceptionType, SubPolicy);
           Proto += ExceptionType;
         }
       Proto += ")";
+    } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) {
+      Proto += " noexcept";
+      if (FT->getExceptionSpecType() == EST_ComputedNoexcept) {
+        Proto += "(";
+        llvm::raw_string_ostream EOut(Proto);
+        FT->getNoexceptExpr()->printPretty(EOut, Context, 0, SubPolicy,
+                                           Indentation);
+        EOut.flush();
+        Proto += EOut.str();
+        Proto += ")";
+      }
     }
 
     if (D->hasAttr<NoReturnAttr>())

Modified: cfe/trunk/lib/AST/DumpXML.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DumpXML.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DumpXML.cpp (original)
+++ cfe/trunk/lib/AST/DumpXML.cpp Sat Mar 12 05:50:43 2011
@@ -975,15 +975,16 @@
       dispatch(*I);
     pop();
 
-    if (T->hasExceptionSpec()) {
+    if (T->hasDynamicExceptionSpec()) {
       push("exception_specifiers");
-      setFlag("any", T->hasAnyExceptionSpec());
+      setFlag("any", T->getExceptionSpecType() == EST_MSAny);
       completeAttrs();
       for (FunctionProtoType::exception_iterator
              I = T->exception_begin(), E = T->exception_end(); I != E; ++I)
         dispatch(*I);
       pop();
     }
+    // FIXME: noexcept specifier
   }
 
   void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) {

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Sat Mar 12 05:50:43 2011
@@ -1659,7 +1659,7 @@
   if (!FT)
     return Expr::CT_Can;
 
-  return FT->hasEmptyExceptionSpec() ? Expr::CT_Cannot : Expr::CT_Can;
+  return FT->isNothrow() ? Expr::CT_Cannot : Expr::CT_Can;
 }
 
 static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) {

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Sat Mar 12 05:50:43 2011
@@ -102,7 +102,7 @@
 
 bool CXXNewExpr::shouldNullCheckAllocation() const {
   return getOperatorNew()->getType()->
-    castAs<FunctionProtoType>()->hasNonThrowingExceptionSpec();
+    castAs<FunctionProtoType>()->isNothrow();
 }
 
 // CXXDeleteExpr

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Sat Mar 12 05:50:43 2011
@@ -21,6 +21,7 @@
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/TypeVisitor.h"
 #include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
@@ -1165,7 +1166,8 @@
 
 FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
                                      unsigned numArgs, QualType canonical,
-                                     const ExtProtoInfo &epi)
+                                     const ExtProtoInfo &epi,
+                                     const ASTContext *context)
   : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals, 
                  epi.RefQualifier, canonical,
                  result->isDependentType(),
@@ -1173,8 +1175,7 @@
                  result->containsUnexpandedParameterPack(),
                  epi.ExtInfo),
     NumArgs(numArgs), NumExceptions(epi.NumExceptions),
-    HasExceptionSpec(isDynamicExceptionSpec(epi.ExceptionSpecType)),
-    HasAnyExceptionSpec(epi.ExceptionSpecType == EST_DynamicAny)
+    ExceptionSpecType(epi.ExceptionSpecType)
 {
   // Fill in the trailing argument array.
   QualType *argSlot = reinterpret_cast<QualType*>(this+1);
@@ -1187,20 +1188,54 @@
 
     argSlot[i] = args[i];
   }
-  
-  // Fill in the exception array.
-  QualType *exnSlot = argSlot + numArgs;
-  for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
-    if (epi.Exceptions[i]->isDependentType())
-      setDependent();
-
-    if (epi.Exceptions[i]->containsUnexpandedParameterPack())
-      setContainsUnexpandedParameterPack();
 
-    exnSlot[i] = epi.Exceptions[i];
+  if (getExceptionSpecType() == EST_Dynamic) {
+    // Fill in the exception array.
+    QualType *exnSlot = argSlot + numArgs;
+    for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
+      if (epi.Exceptions[i]->isDependentType())
+        setDependent();
+
+      if (epi.Exceptions[i]->containsUnexpandedParameterPack())
+        setContainsUnexpandedParameterPack();
+
+      exnSlot[i] = epi.Exceptions[i];
+    }
+  } else if (getExceptionSpecType() == EST_ComputedNoexcept) {
+    // Store the noexcept expression and context.
+    Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs);
+    *noexSlot = epi.NoexceptExpr;
+    const ASTContext **contextSlot = const_cast<const ASTContext**>(
+        reinterpret_cast<ASTContext**>(noexSlot + 1));
+    *contextSlot = context;
   }
 }
 
+FunctionProtoType::NoexceptResult
+FunctionProtoType::getNoexceptSpec() const {
+  ExceptionSpecificationType est = getExceptionSpecType();
+  if (est == EST_BasicNoexcept)
+    return NR_Nothrow;
+
+  if (est != EST_ComputedNoexcept)
+    return NR_NoNoexcept;
+
+  Expr *noexceptExpr = getNoexceptExpr();
+  if (!noexceptExpr)
+    return NR_BadNoexcept;
+  if (noexceptExpr->isValueDependent())
+    return NR_Dependent;
+
+  llvm::APSInt value;
+  ASTContext& ctx = const_cast<ASTContext&>(*getContext());
+  bool isICE = noexceptExpr->isIntegerConstantExpr(value, ctx, 0,
+                                                   /*evaluated*/false);
+  (void)isICE;
+  assert(isICE && "AST should not contain bad noexcept expressions.");
+
+  return value.getBoolValue() ? NR_Nothrow : NR_Throw;
+}
+
 bool FunctionProtoType::isTemplateVariadic() const {
   for (unsigned ArgIdx = getNumArgs(); ArgIdx; --ArgIdx)
     if (isa<PackExpansionType>(getArgType(ArgIdx - 1)))
@@ -1211,23 +1246,27 @@
 
 void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
                                 const QualType *ArgTys, unsigned NumArgs,
-                                const ExtProtoInfo &epi) {
+                                const ExtProtoInfo &epi,
+                                const ASTContext *Context) {
   ID.AddPointer(Result.getAsOpaquePtr());
   for (unsigned i = 0; i != NumArgs; ++i)
     ID.AddPointer(ArgTys[i].getAsOpaquePtr());
   ID.AddBoolean(epi.Variadic);
   ID.AddInteger(epi.TypeQuals);
   ID.AddInteger(epi.RefQualifier);
-  if (isDynamicExceptionSpec(epi.ExceptionSpecType)) {
-    ID.AddBoolean(epi.ExceptionSpecType == EST_DynamicAny);
+  ID.AddInteger(epi.ExceptionSpecType);
+  if (epi.ExceptionSpecType == EST_Dynamic) {
     for (unsigned i = 0; i != epi.NumExceptions; ++i)
       ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());
+  } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){
+    epi.NoexceptExpr->Profile(ID, *Context, true);
   }
   epi.ExtInfo.Profile(ID);
 }
 
 void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
-  Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo());
+  Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo(),
+          getContext());
 }
 
 QualType TypedefType::desugar() const {

Modified: cfe/trunk/lib/AST/TypePrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypePrinter.cpp (original)
+++ cfe/trunk/lib/AST/TypePrinter.cpp Sat Mar 12 05:50:43 2011
@@ -421,12 +421,12 @@
     S += " &&";
     break;
   }
-  
-  if (T->hasExceptionSpec()) {
+
+  if (T->hasDynamicExceptionSpec()) {
     S += " throw(";
-    if (T->hasAnyExceptionSpec())
+    if (T->getExceptionSpecType() == EST_MSAny)
       S += "...";
-    else 
+    else
       for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) {
         if (I)
           S += ", ";
@@ -436,6 +436,16 @@
         S += ExceptionType;
       }
     S += ")";
+  } else if (isNoexceptExceptionSpec(T->getExceptionSpecType())) {
+    S += " noexcept";
+    if (T->getExceptionSpecType() == EST_ComputedNoexcept) {
+      S += "(";
+      llvm::raw_string_ostream EOut(S);
+      T->getNoexceptExpr()->printPretty(EOut, 0, Policy);
+      EOut.flush();
+      S += EOut.str();
+      S += ")";
+    }
   }
 
   print(T->getResultType(), S);

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Sat Mar 12 05:50:43 2011
@@ -1128,7 +1128,7 @@
   const FunctionType *FT = Ty->getAs<FunctionType>();
   if (FT) {
     if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
-      if (Proto->hasEmptyExceptionSpec())
+      if (Proto->isNothrow())
         return false;
   }
   return true;

Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Sat Mar 12 05:50:43 2011
@@ -709,7 +709,7 @@
       FuncAttrs |= llvm::Attribute::NoUnwind;
     else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
       const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
-      if (FPT && FPT->hasEmptyExceptionSpec())
+      if (FPT && FPT->isNothrow())
         FuncAttrs |= llvm::Attribute::NoUnwind;
     }
 

Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Sat Mar 12 05:50:43 2011
@@ -449,9 +449,8 @@
   if (Proto == 0)
     return;
 
-  assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack");
-
-  if (!Proto->hasExceptionSpec())
+  // FIXME: What about noexcept?
+  if (!Proto->hasDynamicExceptionSpec())
     return;
 
   unsigned NumExceptions = Proto->getNumExceptions();
@@ -477,7 +476,7 @@
   if (Proto == 0)
     return;
 
-  if (!Proto->hasExceptionSpec())
+  if (!Proto->hasDynamicExceptionSpec())
     return;
 
   EHStack.popFilter();

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Sat Mar 12 05:50:43 2011
@@ -982,7 +982,7 @@
   // exception spec; for this part, we inline
   // CXXNewExpr::shouldNullCheckAllocation()) and we have an
   // interesting initializer.
-  bool nullCheck = allocatorType->hasNonThrowingExceptionSpec() &&
+  bool nullCheck = allocatorType->isNothrow() &&
     !(allocType->isPODType() && !E->hasInitializer());
 
   llvm::BasicBlock *nullCheckBB = 0;

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Sat Mar 12 05:50:43 2011
@@ -2042,6 +2042,11 @@
     SourceLocation LParenLoc = ConsumeParen();
     NoexceptType = EST_ComputedNoexcept;
     NoexceptExpr = ParseConstantExpression();
+    // The argument must be contextually convertible to bool. We use
+    // ActOnBooleanCondition for this purpose.
+    if (!NoexceptExpr.isInvalid())
+      NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc,
+                                                   NoexceptExpr.get());
     SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
     NoexceptRange = SourceRange(KeywordLoc, RParenLoc);
   } else {
@@ -2090,7 +2095,7 @@
   if (!Tok.is(tok::l_paren)) {
     Diag(Tok, diag::err_expected_lparen_after) << "throw";
     SpecificationRange.setEnd(SpecificationRange.getBegin());
-    return EST_Dynamic;
+    return EST_DynamicNone;
   }
   SourceLocation LParenLoc = ConsumeParen();
 
@@ -2102,7 +2107,7 @@
       Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec);
     SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
     SpecificationRange.setEnd(RParenLoc);
-    return EST_DynamicAny;
+    return EST_MSAny;
   }
 
   // Parse the sequence of type-ids.
@@ -2132,7 +2137,7 @@
   }
 
   SpecificationRange.setEnd(MatchRHSPunctuation(tok::r_paren, LParenLoc));
-  return EST_Dynamic;
+  return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic;
 }
 
 /// ParseTrailingReturnType - Parse a trailing return type on a new-style

Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Sat Mar 12 05:50:43 2011
@@ -1238,6 +1238,16 @@
     if (!SkipUntil(tok::r_paren))
       return TPResult::Error();
   }
+  if (Tok.is(tok::kw_noexcept)) {
+    ConsumeToken();
+    // Possibly an expression as well.
+    if (Tok.is(tok::l_paren)) {
+      // Find the matching rparen.
+      ConsumeParen();
+      if (!SkipUntil(tok::r_paren))
+        return TPResult::Error();
+    }
+  }
 
   return TPResult::Ambiguous();
 }

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Mar 12 05:50:43 2011
@@ -1552,8 +1552,8 @@
     mergeParamDeclAttributes(*ni, *oi, Context);    
 }
 
-/// MergeVarDecl - We parsed a variable 'New' which has the same name and scope
-/// as a previous declaration 'Old'.  Figure out how to merge their types,
+/// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and
+/// scope as a previous declaration 'Old'.  Figure out how to merge their types,
 /// emitting diagnostics as appropriate.
 ///
 /// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back
@@ -1570,8 +1570,10 @@
     if (AT && !AT->isDeduced()) {
       // We don't know what the new type is until the initializer is attached.
       return;
-    } else if (Context.hasSameType(New->getType(), Old->getType()))
-      return;
+    } else if (Context.hasSameType(New->getType(), Old->getType())) {
+      // These could still be something that needs exception specs checked.
+      return MergeVarDeclExceptionSpecs(New, Old);
+    }
     // C++ [basic.link]p10:
     //   [...] the types specified by all declarations referring to a given
     //   object or function shall be identical, except that declarations for an

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Mar 12 05:50:43 2011
@@ -383,6 +383,48 @@
   return Invalid;
 }
 
+/// \brief Merge the exception specifications of two variable declarations.
+///
+/// This is called when there's a redeclaration of a VarDecl. The function
+/// checks if the redeclaration might have an exception specification and
+/// validates compatibility and merges the specs if necessary.
+void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) {
+  // Shortcut if exceptions are disabled.
+  if (!getLangOptions().CXXExceptions)
+    return;
+
+  assert(Context.hasSameType(New->getType(), Old->getType()) &&
+         "Should only be called if types are otherwise the same.");
+
+  QualType NewType = New->getType();
+  QualType OldType = Old->getType();
+
+  // We're only interested in pointers and references to functions, as well
+  // as pointers to member functions.
+  if (const ReferenceType *R = NewType->getAs<ReferenceType>()) {
+    NewType = R->getPointeeType();
+    OldType = OldType->getAs<ReferenceType>()->getPointeeType();
+  } else if (const PointerType *P = NewType->getAs<PointerType>()) {
+    NewType = P->getPointeeType();
+    OldType = OldType->getAs<PointerType>()->getPointeeType();
+  } else if (const MemberPointerType *M = NewType->getAs<MemberPointerType>()) {
+    NewType = M->getPointeeType();
+    OldType = OldType->getAs<MemberPointerType>()->getPointeeType();
+  }
+
+  if (!NewType->isFunctionProtoType())
+    return;
+
+  // There's lots of special cases for functions. For function pointers, system
+  // libraries are hopefully not as broken so that we don't need these
+  // workarounds.
+  if (CheckEquivalentExceptionSpec(
+        OldType->getAs<FunctionProtoType>(), Old->getLocation(),
+        NewType->getAs<FunctionProtoType>(), New->getLocation())) {
+    New->setInvalidDecl();
+  }
+}
+
 /// CheckCXXDefaultArguments - Verify that the default arguments for a
 /// function declaration are well-formed according to C++
 /// [dcl.fct.default].
@@ -2978,53 +3020,101 @@
   /// implicitly-declared special member functions.
   class ImplicitExceptionSpecification {
     ASTContext &Context;
-    bool AllowsAllExceptions;
+    // We order exception specifications thus:
+    // noexcept is the most restrictive, but is only used in C++0x.
+    // throw() comes next.
+    // Then a throw(collected exceptions)
+    // Finally no specification.
+    // throw(...) is used instead if any called function uses it.
+    ExceptionSpecificationType ComputedEST;
     llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
     llvm::SmallVector<QualType, 4> Exceptions;
-    
+
+    void ClearExceptions() {
+      ExceptionsSeen.clear();
+      Exceptions.clear();
+    }
+
   public:
     explicit ImplicitExceptionSpecification(ASTContext &Context) 
-      : Context(Context), AllowsAllExceptions(false) { }
-    
-    /// \brief Whether the special member function should have any
-    /// exception specification at all.
-    bool hasExceptionSpecification() const {
-      return !AllowsAllExceptions;
+      : Context(Context), ComputedEST(EST_BasicNoexcept) {
+      if (!Context.getLangOptions().CPlusPlus0x)
+        ComputedEST = EST_DynamicNone;
     }
-    
-    /// \brief Whether the special member function should have a
-    /// throw(...) exception specification (a Microsoft extension).
-    bool hasAnyExceptionSpecification() const {
-      return false;
+
+    /// \brief Get the computed exception specification type.
+    ExceptionSpecificationType getExceptionSpecType() const {
+      assert(ComputedEST != EST_ComputedNoexcept &&
+             "noexcept(expr) should not be a possible result");
+      return ComputedEST;
     }
-    
+
     /// \brief The number of exceptions in the exception specification.
     unsigned size() const { return Exceptions.size(); }
-    
+
     /// \brief The set of exceptions in the exception specification.
     const QualType *data() const { return Exceptions.data(); }
-    
-    /// \brief Note that 
+
+    /// \brief Integrate another called method into the collected data.
     void CalledDecl(CXXMethodDecl *Method) {
-      // If we already know that we allow all exceptions, do nothing.
-      if (AllowsAllExceptions || !Method)
+      // If we have an MSAny spec already, don't bother.
+      if (!Method || ComputedEST == EST_MSAny)
         return;
-      
+
       const FunctionProtoType *Proto
         = Method->getType()->getAs<FunctionProtoType>();
-      
+
+      ExceptionSpecificationType EST = Proto->getExceptionSpecType();
+
       // If this function can throw any exceptions, make a note of that.
-      if (!Proto->hasExceptionSpec() || Proto->hasAnyExceptionSpec()) {
-        AllowsAllExceptions = true;
-        ExceptionsSeen.clear();
-        Exceptions.clear();
+      if (EST == EST_MSAny || EST == EST_None) {
+        ClearExceptions();
+        ComputedEST = EST;
         return;
       }
-        
+
+      // If this function has a basic noexcept, it doesn't affect the outcome.
+      if (EST == EST_BasicNoexcept)
+        return;
+
+      // If we have a throw-all spec at this point, ignore the function.
+      if (ComputedEST == EST_None)
+        return;
+
+      // If we're still at noexcept(true) and there's a nothrow() callee,
+      // change to that specification.
+      if (EST == EST_DynamicNone) {
+        if (ComputedEST == EST_BasicNoexcept)
+          ComputedEST = EST_DynamicNone;
+        return;
+      }
+
+      // Check out noexcept specs.
+      if (EST == EST_ComputedNoexcept) {
+        FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec();
+        assert(NR != FunctionProtoType::NR_NoNoexcept &&
+               "Must have noexcept result for EST_ComputedNoexcept.");
+        assert(NR != FunctionProtoType::NR_Dependent &&
+               "Should not generate implicit declarations for dependent cases, "
+               "and don't know how to handle them anyway.");
+
+        // noexcept(false) -> no spec on the new function
+        if (NR == FunctionProtoType::NR_Throw) {
+          ClearExceptions();
+          ComputedEST = EST_None;
+        }
+        // noexcept(true) won't change anything either.
+        return;
+      }
+
+      assert(EST == EST_Dynamic && "EST case not considered earlier.");
+      assert(ComputedEST != EST_None &&
+             "Shouldn't collect exceptions when throw-all is guaranteed.");
+      ComputedEST = EST_Dynamic;
       // Record the exceptions in this function's exception specification.
       for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
                                               EEnd = Proto->exception_end();
-           E != EEnd; ++E) 
+           E != EEnd; ++E)
         if (ExceptionsSeen.insert(Context.getCanonicalType(*E)))
           Exceptions.push_back(*E);
     }
@@ -4672,7 +4762,7 @@
   //   exception-specification. [...]
   ImplicitExceptionSpecification ExceptSpec(Context);
 
-  // Direct base-class destructors.
+  // Direct base-class constructors.
   for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
                                        BEnd = ClassDecl->bases_end();
        B != BEnd; ++B) {
@@ -4688,8 +4778,8 @@
         ExceptSpec.CalledDecl(Constructor);
     }
   }
-  
-  // Virtual base-class destructors.
+
+  // Virtual base-class constructors.
   for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
                                        BEnd = ClassDecl->vbases_end();
        B != BEnd; ++B) {
@@ -4702,8 +4792,8 @@
         ExceptSpec.CalledDecl(Constructor);
     }
   }
-  
-  // Field destructors.
+
+  // Field constructors.
   for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
                                FEnd = ClassDecl->field_end();
        F != FEnd; ++F) {
@@ -4720,9 +4810,7 @@
   }
 
   FunctionProtoType::ExtProtoInfo EPI;
-  EPI.ExceptionSpecType = ExceptSpec.hasExceptionSpecification() ?
-    (ExceptSpec.hasAnyExceptionSpecification() ? EST_DynamicAny : EST_Dynamic) :
-    EST_None;
+  EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
   EPI.NumExceptions = ExceptSpec.size();
   EPI.Exceptions = ExceptSpec.data();
 
@@ -4997,16 +5085,14 @@
       ExceptSpec.CalledDecl(
                     LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
   }
-  
+
   // Create the actual destructor declaration.
   FunctionProtoType::ExtProtoInfo EPI;
-  EPI.ExceptionSpecType = ExceptSpec.hasExceptionSpecification() ?
-    (ExceptSpec.hasAnyExceptionSpecification() ? EST_DynamicAny : EST_Dynamic) :
-    EST_None;
+  EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
   EPI.NumExceptions = ExceptSpec.size();
   EPI.Exceptions = ExceptSpec.data();
   QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI);
-  
+
   CanQualType ClassType
     = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
   SourceLocation ClassLoc = ClassDecl->getLocation();
@@ -5014,9 +5100,9 @@
     = Context.DeclarationNames.getCXXDestructorName(ClassType);
   DeclarationNameInfo NameInfo(Name, ClassLoc);
   CXXDestructorDecl *Destructor
-    = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0,
-                                /*isInline=*/true,
-                                /*isImplicitlyDeclared=*/true);
+      = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0,
+                                  /*isInline=*/true,
+                                  /*isImplicitlyDeclared=*/true);
   Destructor->setAccess(AS_public);
   Destructor->setImplicit();
   Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
@@ -5396,13 +5482,11 @@
         ExceptSpec.CalledDecl(CopyAssign);      
     }      
   }
-  
+
   //   An implicitly-declared copy assignment operator is an inline public
   //   member of its class.
   FunctionProtoType::ExtProtoInfo EPI;
-  EPI.ExceptionSpecType = ExceptSpec.hasExceptionSpecification() ?
-    (ExceptSpec.hasAnyExceptionSpecification() ? EST_DynamicAny : EST_Dynamic) :
-    EST_None;
+  EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
   EPI.NumExceptions = ExceptSpec.size();
   EPI.Exceptions = ExceptSpec.data();
   DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
@@ -5860,13 +5944,11 @@
         ExceptSpec.CalledDecl(CopyConstructor);
     }
   }
-  
+
   //   An implicitly-declared copy constructor is an inline public
   //   member of its class.
   FunctionProtoType::ExtProtoInfo EPI;
-  EPI.ExceptionSpecType = ExceptSpec.hasExceptionSpecification() ?
-    (ExceptSpec.hasAnyExceptionSpecification() ? EST_DynamicAny : EST_Dynamic) :
-    EST_None;
+  EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
   EPI.NumExceptions = ExceptSpec.size();
   EPI.Exceptions = ExceptSpec.data();
   DeclarationName Name

Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Sat Mar 12 05:50:43 2011
@@ -105,7 +105,8 @@
                                     New->getType()->getAs<FunctionProtoType>(),
                                     New->getLocation(),
                                     &MissingExceptionSpecification,
-                                    &MissingEmptyExceptionSpecification))
+                                    &MissingEmptyExceptionSpecification,
+                                    /*AllowNoexceptAllMatchWithNoSpec=*/true))
     return false;
 
   // The failure was something other than an empty exception
@@ -129,8 +130,7 @@
        Context.getSourceManager().isInSystemHeader(Old->getLocation())) &&
       Old->isExternC()) {
     FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
-    EPI.ExceptionSpecType = EST_Dynamic;
-    EPI.NumExceptions = 0;
+    EPI.ExceptionSpecType = EST_DynamicNone;
     QualType NewType = Context.getFunctionType(NewProto->getResultType(),
                                                NewProto->arg_type_begin(),
                                                NewProto->getNumArgs(),
@@ -144,11 +144,14 @@
       = Old->getType()->getAs<FunctionProtoType>();
 
     FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
-    EPI.ExceptionSpecType = OldProto->hasExceptionSpec() ?
-      (OldProto->hasAnyExceptionSpec() ? EST_DynamicAny : EST_Dynamic) :
-      EST_None;
-    EPI.NumExceptions = OldProto->getNumExceptions();
-    EPI.Exceptions = OldProto->exception_begin();
+    EPI.ExceptionSpecType = OldProto->getExceptionSpecType();
+    if (EPI.ExceptionSpecType == EST_Dynamic) {
+      EPI.NumExceptions = OldProto->getNumExceptions();
+      EPI.Exceptions = OldProto->exception_begin();
+    } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
+      // FIXME: We can't just take the expression from the old prototype. It
+      // likely contains references to the old prototype's parameters.
+    }
 
     // Update the type of the function with the appropriate exception
     // specification.
@@ -178,20 +181,43 @@
     // Warn about the lack of exception specification.
     llvm::SmallString<128> ExceptionSpecString;
     llvm::raw_svector_ostream OS(ExceptionSpecString);
-    OS << "throw(";
-    bool OnFirstException = true;
-    for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(),
-                                            EEnd = OldProto->exception_end();
-         E != EEnd;
-         ++E) {
-      if (OnFirstException)
-        OnFirstException = false;
-      else
-        OS << ", ";
-      
-      OS << E->getAsString(Context.PrintingPolicy);
+    switch (OldProto->getExceptionSpecType()) {
+    case EST_DynamicNone:
+      OS << "throw()";
+      break;
+
+    case EST_Dynamic: {
+      OS << "throw(";
+      bool OnFirstException = true;
+      for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(),
+                                              EEnd = OldProto->exception_end();
+           E != EEnd;
+           ++E) {
+        if (OnFirstException)
+          OnFirstException = false;
+        else
+          OS << ", ";
+        
+        OS << E->getAsString(Context.PrintingPolicy);
+      }
+      OS << ")";
+      break;
+    }
+
+    case EST_BasicNoexcept:
+      OS << "noexcept";
+      break;
+
+    case EST_ComputedNoexcept:
+      OS << "noexcept(";
+      OldProto->getNoexceptExpr()->printPretty(OS, Context, 0,
+                                               Context.PrintingPolicy);
+      OS << ")";
+      break;
+
+    default:
+      assert(false && "This spec type is compatible with none.");
     }
-    OS << ")";
     OS.flush();
 
     SourceLocation FixItLoc;
@@ -236,18 +262,17 @@
                                       Old, OldLoc, New, NewLoc);
 }
 
-/// CheckEquivalentExceptionSpec - Check if the two types have equivalent
-/// exception specifications. Exception specifications are equivalent if
-/// they allow exactly the same set of exception types. It does not matter how
-/// that is achieved. See C++ [except.spec]p2.
-bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, 
+/// CheckEquivalentExceptionSpec - Check if the two types have compatible
+/// exception specifications. See C++ [except.spec]p3.
+bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
                                         const PartialDiagnostic & NoteID,
-                                        const FunctionProtoType *Old, 
+                                        const FunctionProtoType *Old,
                                         SourceLocation OldLoc,
-                                        const FunctionProtoType *New, 
+                                        const FunctionProtoType *New,
                                         SourceLocation NewLoc,
                                         bool *MissingExceptionSpecification,
-                                     bool *MissingEmptyExceptionSpecification)  {
+                                        bool*MissingEmptyExceptionSpecification,
+                                        bool AllowNoexceptAllMatchWithNoSpec) {
   // Just completely ignore this under -fno-exceptions.
   if (!getLangOptions().CXXExceptions)
     return false;
@@ -258,29 +283,109 @@
   if (MissingEmptyExceptionSpecification)
     *MissingEmptyExceptionSpecification = false;
 
-  bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
-  bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
+  // C++0x [except.spec]p3: Two exception-specifications are compatible if:
+  //   - both are non-throwing, regardless of their form,
+  //   - both have the form noexcept(constant-expression) and the constant-
+  //     expressions are equivalent,
+  //   - one exception-specification is a noexcept-specification allowing all
+  //     exceptions and the other is of the form throw(type-id-list), or
+  //   - both are dynamic-exception-specifications that have the same set of
+  //     adjusted types.
+  //
+  // C++0x [except.spec]p12: An exception-specifcation is non-throwing if it is
+  //   of the form throw(), noexcept, or noexcept(constant-expression) where the
+  //   constant-expression yields true.
+  //
+  // CWG 1073 Proposed resolution: Strike the third bullet above.
+  //
+  // C++0x [except.spec]p4: If any declaration of a function has an exception-
+  //   specifier that is not a noexcept-specification allowing all exceptions,
+  //   all declarations [...] of that function shall have a compatible
+  //   exception-specification.
+  //
+  // That last point basically means that noexcept(false) matches no spec.
+  // It's considered when AllowNoexceptAllMatchWithNoSpec is true.
+
+  ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
+  ExceptionSpecificationType NewEST = New->getExceptionSpecType();
+
+  // Shortcut the case where both have no spec.
+  if (OldEST == EST_None && NewEST == EST_None)
+    return false;
+
+  FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec();
+  FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec();
+  if (OldNR == FunctionProtoType::NR_BadNoexcept ||
+      NewNR == FunctionProtoType::NR_BadNoexcept)
+    return false;
+
+  // Dependent noexcept specifiers are compatible with each other, but nothing
+  // else.
+  // One noexcept is compatible with another if the argument is the same
+  if (OldNR == NewNR &&
+      OldNR != FunctionProtoType::NR_NoNoexcept &&
+      NewNR != FunctionProtoType::NR_NoNoexcept)
+    return false;
+  if (OldNR != NewNR &&
+      OldNR != FunctionProtoType::NR_NoNoexcept &&
+      NewNR != FunctionProtoType::NR_NoNoexcept) {
+    Diag(NewLoc, DiagID);
+    if (NoteID.getDiagID() != 0)
+      Diag(OldLoc, NoteID);
+    return true;
+  }
+
   if (getLangOptions().Microsoft) {
     // Treat throw(whatever) as throw(...) to be compatible with MS headers.
-    if (New->hasExceptionSpec() && New->getNumExceptions() > 0)
-      NewAny = true;
-    if (Old->hasExceptionSpec() && Old->getNumExceptions() > 0)
-      OldAny = true;
+    if (OldEST == EST_Dynamic)
+      OldEST = EST_MSAny;
+    if (NewEST == EST_Dynamic)
+      NewEST = EST_MSAny;
+  }
+
+  // The MS extension throw(...) is compatible with itself.
+  if (OldEST == EST_MSAny && NewEST == EST_MSAny)
+    return false;
+
+  // It's also compatible with no spec.
+  if ((OldEST == EST_None && NewEST == EST_MSAny) ||
+      (OldEST == EST_MSAny && NewEST == EST_None))
+    return false;
+
+  // It's also compatible with noexcept(false).
+  if (OldEST == EST_MSAny && NewNR == FunctionProtoType::NR_Throw)
+    return false;
+  if (NewEST == EST_MSAny && OldNR == FunctionProtoType::NR_Throw)
+    return false;
+
+  // As described above, noexcept(false) matches no spec only for functions.
+  if (AllowNoexceptAllMatchWithNoSpec) {
+    if (OldEST == EST_None && NewNR == FunctionProtoType::NR_Throw)
+      return false;
+    if (NewEST == EST_None && OldNR == FunctionProtoType::NR_Throw)
+      return false;
   }
 
-  if (OldAny && NewAny)
+  // Any non-throwing specifications are compatible.
+  bool OldNonThrowing = OldNR == FunctionProtoType::NR_Nothrow ||
+                        OldEST == EST_DynamicNone;
+  bool NewNonThrowing = NewNR == FunctionProtoType::NR_Nothrow ||
+                        NewEST == EST_DynamicNone;
+  if (OldNonThrowing && NewNonThrowing)
     return false;
-  if (OldAny || NewAny) {
+
+  // At this point, the only remaining valid case is two matching dynamic
+  // specifications. We return here unless both specifications are dynamic.
+  if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) {
     if (MissingExceptionSpecification && Old->hasExceptionSpec() &&
         !New->hasExceptionSpec()) {
       // The old type has an exception specification of some sort, but
       // the new type does not.
       *MissingExceptionSpecification = true;
 
-      if (MissingEmptyExceptionSpecification && 
-          !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0) {
-        // The old type has a throw() exception specification and the
-        // new type has no exception specification, and the caller asked
+      if (MissingEmptyExceptionSpecification && OldNonThrowing) {
+        // The old type has a throw() or noexcept(true) exception specification
+        // and the new type has no exception specification, and the caller asked
         // to handle this itself.
         *MissingEmptyExceptionSpecification = true;
       }
@@ -294,8 +399,11 @@
     return true;
   }
 
+  assert(OldEST == EST_Dynamic && NewEST == EST_Dynamic &&
+      "Exception compatibility logic error: non-dynamic spec slipped through.");
+
   bool Success = true;
-  // Both have a definite exception spec. Collect the first set, then compare
+  // Both have a dynamic exception spec. Collect the first set, then compare
   // to the second.
   llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
   for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
@@ -340,19 +448,66 @@
   if (!SubLoc.isValid())
     SubLoc = SuperLoc;
 
+  ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType();
+
   // If superset contains everything, we're done.
-  if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec())
+  if (SuperEST == EST_None || SuperEST == EST_MSAny)
+    return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+
+  // If there are dependent noexcept specs, assume everything is fine. Unlike
+  // with the equivalency check, this is safe in this case, because we don't
+  // want to merge declarations. Checks after instantiation will catch any
+  // omissions we make here.
+  // We also shortcut checking if a noexcept expression was bad.
+
+  FunctionProtoType::NoexceptResult SuperNR =Superset->getNoexceptSpec();
+  if (SuperNR == FunctionProtoType::NR_BadNoexcept ||
+      SuperNR == FunctionProtoType::NR_Dependent)
+    return false;
+
+  // Another case of the superset containing everything.
+  if (SuperNR == FunctionProtoType::NR_Throw)
     return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
 
+  ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
+
   // It does not. If the subset contains everything, we've failed.
-  if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) {
+  if (SubEST == EST_None || SubEST == EST_MSAny) {
     Diag(SubLoc, DiagID);
     if (NoteID.getDiagID() != 0)
       Diag(SuperLoc, NoteID);
     return true;
   }
 
-  // Neither contains everything. Do a proper comparison.
+  FunctionProtoType::NoexceptResult SubNR = Subset->getNoexceptSpec();
+  if (SubNR == FunctionProtoType::NR_BadNoexcept ||
+      SubNR == FunctionProtoType::NR_Dependent)
+    return false;
+
+  // Another case of the subset containing everything.
+  if (SubNR == FunctionProtoType::NR_Throw) {
+    Diag(SubLoc, DiagID);
+    if (NoteID.getDiagID() != 0)
+      Diag(SuperLoc, NoteID);
+    return true;
+  }
+
+  // If the subset contains nothing, we're done.
+  if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow)
+    return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+
+  // Otherwise, if the superset contains nothing, we've failed.
+  if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) {
+    Diag(SubLoc, DiagID);
+    if (NoteID.getDiagID() != 0)
+      Diag(SuperLoc, NoteID);
+    return true;
+  }
+
+  assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic &&
+         "Exception spec subset: non-dynamic case slipped through.");
+
+  // Neither contains everything or nothing. Do a proper comparison.
   for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
        SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
     // Take one type from the subset.

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sat Mar 12 05:50:43 2011
@@ -1501,10 +1501,12 @@
   }
 
   FunctionProtoType::ExtProtoInfo EPI;
-  EPI.ExceptionSpecType = EST_Dynamic;
   if (HasBadAllocExceptionSpec) {
+    EPI.ExceptionSpecType = EST_Dynamic;
     EPI.NumExceptions = 1;
     EPI.Exceptions = &BadAllocType;
+  } else {
+    EPI.ExceptionSpecType = EST_DynamicNone;
   }
 
   QualType FnType = Context.getFunctionType(Return, &Argument, 1, EPI);
@@ -2421,7 +2423,7 @@
             FoundAssign = true;
             const FunctionProtoType *CPT
                 = Operator->getType()->getAs<FunctionProtoType>();
-            if (!CPT->hasEmptyExceptionSpec()) {
+            if (!CPT->isNothrow()) {
               AllNoThrow = false;
               break;
             }
@@ -2461,9 +2463,9 @@
           FoundConstructor = true;
           const FunctionProtoType *CPT
               = Constructor->getType()->getAs<FunctionProtoType>();
-          // TODO: check whether evaluating default arguments can throw.
+          // FIXME: check whether evaluating default arguments can throw.
           // For now, we'll be conservative and assume that they can throw.
-          if (!CPT->hasEmptyExceptionSpec() || CPT->getNumArgs() > 1) {
+          if (!CPT->isNothrow() || CPT->getNumArgs() > 1) {
             AllNoThrow = false;
             break;
           }
@@ -2498,7 +2500,7 @@
               = Constructor->getType()->getAs<FunctionProtoType>();
           // TODO: check whether evaluating default arguments can throw.
           // For now, we'll be conservative and assume that they can throw.
-          return CPT->hasEmptyExceptionSpec() && CPT->getNumArgs() == 0;
+          return CPT->isNothrow() && CPT->getNumArgs() == 0;
         }
       }
     }

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sat Mar 12 05:50:43 2011
@@ -2085,8 +2085,7 @@
   const FunctionProtoType *Proto = Tmpl->getType()->getAs<FunctionProtoType>();
   assert(Proto && "Function template without prototype?");
 
-  if (Proto->hasExceptionSpec() || Proto->hasAnyExceptionSpec() ||
-      Proto->getNoReturnAttr()) {
+  if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) {
     // The function has an exception specification or a "noreturn"
     // attribute. Substitute into each of the exception types.
     llvm::SmallVector<QualType, 4> Exceptions;
@@ -2100,7 +2099,7 @@
                                                 Unexpanded);
         assert(!Unexpanded.empty() && 
                "Pack expansion without parameter packs?");
-        
+
         bool Expand = false;
         bool RetainExpansion = false;
         llvm::Optional<unsigned> NumExpansions
@@ -2114,7 +2113,7 @@
                                                     RetainExpansion,
                                                     NumExpansions))
           break;
-                      
+
         if (!Expand) {
           // We can't expand this pack expansion into separate arguments yet;
           // just substitute into the pattern and create a new pack expansion 
@@ -2130,7 +2129,7 @@
           Exceptions.push_back(T);
           continue;
         }
-        
+
         // Substitute into the pack expansion pattern for each template
         bool Invalid = false;
         for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
@@ -2143,13 +2142,13 @@
             Invalid = true;
             break;
           }
-          
+
           Exceptions.push_back(T);
         }
-        
+
         if (Invalid)
           break;
-        
+
         continue;
       }
       
@@ -2166,9 +2165,8 @@
     // Rebuild the function type 
 
     FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
-    EPI.ExceptionSpecType = Proto->hasExceptionSpec() ?
-      (Proto->hasAnyExceptionSpec() ? EST_DynamicAny : EST_Dynamic) :
-      EST_None;
+    // FIXME: Handle noexcept
+    EPI.ExceptionSpecType = Proto->getExceptionSpecType();
     EPI.NumExceptions = Exceptions.size();
     EPI.Exceptions = Exceptions.data();
     EPI.ExtInfo = Proto->getExtInfo();

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sat Mar 12 05:50:43 2011
@@ -1901,7 +1901,22 @@
           EPI.NumExceptions = Exceptions.size();
           EPI.Exceptions = Exceptions.data();
         } else if (FTI.getExceptionSpecType() == EST_ComputedNoexcept) {
-          EPI.NoexceptExpr = FTI.NoexceptExpr;
+          // If an error occurred, there's no expression here.
+          if (Expr *NoexceptExpr = FTI.NoexceptExpr) {
+            assert((NoexceptExpr->isTypeDependent() ||
+                    NoexceptExpr->getType()->getCanonicalTypeUnqualified() ==
+                        Context.BoolTy) &&
+                 "Parser should have made sure that the expression is boolean");
+            SourceLocation ErrLoc;
+            llvm::APSInt Dummy;
+            if (!NoexceptExpr->isValueDependent() &&
+                !NoexceptExpr->isIntegerConstantExpr(Dummy, Context, &ErrLoc,
+                                                     /*evaluated*/false))
+              Diag(ErrLoc, diag::err_noexcept_needs_constant_expression)
+                  << NoexceptExpr->getSourceRange();
+            else
+              EPI.NoexceptExpr = NoexceptExpr;
+          }
         }
 
         T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI);

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Sat Mar 12 05:50:43 2011
@@ -3117,15 +3117,18 @@
     EPI.Variadic = Record[Idx++];
     EPI.TypeQuals = Record[Idx++];
     EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
-    bool HasExceptionSpec = Record[Idx++];
-    bool HasAnyExceptionSpec = Record[Idx++];
-    EPI.ExceptionSpecType = HasExceptionSpec ?
-        (HasAnyExceptionSpec ? EST_DynamicAny : EST_Dynamic) : EST_None;
-    EPI.NumExceptions = Record[Idx++];
-    llvm::SmallVector<QualType, 2> Exceptions;
-    for (unsigned I = 0; I != EPI.NumExceptions; ++I)
-      Exceptions.push_back(GetType(Record[Idx++]));
-    EPI.Exceptions = Exceptions.data();
+    ExceptionSpecificationType EST =
+        static_cast<ExceptionSpecificationType>(Record[Idx++]);
+    EPI.ExceptionSpecType = EST;
+    if (EST == EST_Dynamic) {
+      EPI.NumExceptions = Record[Idx++];
+      llvm::SmallVector<QualType, 2> Exceptions;
+      for (unsigned I = 0; I != EPI.NumExceptions; ++I)
+        Exceptions.push_back(GetType(Record[Idx++]));
+      EPI.Exceptions = Exceptions.data();
+    } else if (EST == EST_ComputedNoexcept) {
+      EPI.NoexceptExpr = ReadExpr(*Loc.F);
+    }
     return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams,
                                     EPI);
   }

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Sat Mar 12 05:50:43 2011
@@ -178,11 +178,14 @@
   Record.push_back(T->isVariadic());
   Record.push_back(T->getTypeQuals());
   Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
-  Record.push_back(T->hasExceptionSpec());
-  Record.push_back(T->hasAnyExceptionSpec());
-  Record.push_back(T->getNumExceptions());
-  for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
-    Writer.AddTypeRef(T->getExceptionType(I), Record);
+  Record.push_back(T->getExceptionSpecType());
+  if (T->getExceptionSpecType() == EST_Dynamic) {
+    Record.push_back(T->getNumExceptions());
+    for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I)
+      Writer.AddTypeRef(T->getExceptionType(I), Record);
+  } else if (T->getExceptionSpecType() == EST_ComputedNoexcept) {
+    Writer.AddStmt(T->getNoexceptExpr());
+  }
   Code = TYPE_FUNCTION_PROTO;
 }
 

Modified: cfe/trunk/test/CXX/except/except.spec/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p1.cpp?rev=127537&r1=127536&r2=127537&view=diff
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p1.cpp (original)
+++ cfe/trunk/test/CXX/except/except.spec/p1.cpp Sat Mar 12 05:50:43 2011
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
 
 // Simple parser tests, dynamic specification.
 
@@ -26,24 +26,35 @@
 
 namespace noex {
 
-  void f() noexcept { }
-  void g() noexcept (true) { }
-  void h() noexcept (false) { }
-  void i() noexcept (1 < 2) { }
+  void f1() noexcept { }
+  void f2() noexcept (true) { }
+  void f3() noexcept (false) { }
+  void f4() noexcept (1 < 2) { }
 
-  class Class {
+  class CA1 {
     void foo() noexcept { }
     void bar() noexcept (true) { }
   };
 
-  void (*fptr)() noexcept;
-  void (*gptr)() noexcept (true);
+  void (*fptr1)() noexcept;
+  void (*fptr2)() noexcept (true);
 
 }
 
-namespace bad {
+namespace mix {
 
   void f() throw(int) noexcept { } // expected-error {{cannot have both}}
   void g() noexcept throw(int) { } // expected-error {{cannot have both}}
 
 }
+
+// Sema tests, noexcept specification
+
+namespace noex {
+
+  struct A {};
+
+  void g1() noexcept(A()); // expected-error {{not contextually convertible}}
+  void g2(bool b) noexcept(b); // expected-error {{argument to noexcept specifier must be a constant expression}}
+
+}

Added: cfe/trunk/test/CXX/except/except.spec/p2-dynamic-types.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p2-dynamic-types.cpp?rev=127537&view=auto
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p2-dynamic-types.cpp (added)
+++ cfe/trunk/test/CXX/except/except.spec/p2-dynamic-types.cpp Sat Mar 12 05:50:43 2011
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Dynamic specifications: valid types.
+
+struct Incomplete; // expected-note 3 {{forward declaration}}
+
+// Exception spec must not have incomplete types, or pointers to them, except
+// void.
+void ic1() throw(void); // expected-error {{incomplete type 'void' is not allowed in exception specification}}
+void ic2() throw(Incomplete); // expected-error {{incomplete type 'Incomplete' is not allowed in exception specification}}
+void ic3() throw(void*);
+void ic4() throw(Incomplete*); // expected-error {{pointer to incomplete type 'Incomplete' is not allowed in exception specification}}
+void ic5() throw(Incomplete&); // expected-error {{reference to incomplete type 'Incomplete' is not allowed in exception specification}}
+
+// Don't suppress errors in template instantiation.
+template <typename T> struct TEx; // expected-note {{template is declared here}}
+
+void tf() throw(TEx<int>); // expected-error {{implicit instantiation of undefined template}}
+
+// DR 437, class throws itself.
+struct DR437 {
+   void f() throw(DR437);
+   void g() throw(DR437*);
+   void h() throw(DR437&);
+};
+
+// DR 437 within a nested class
+struct DR437_out {
+   struct DR437_in {
+      void f() throw(DR437_out);
+      void g() throw(DR437_out*);
+      void h() throw(DR437_out&);
+   }; 
+};

Added: cfe/trunk/test/CXX/except/except.spec/p2-places.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p2-places.cpp?rev=127537&view=auto
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p2-places.cpp (added)
+++ cfe/trunk/test/CXX/except/except.spec/p2-places.cpp Sat Mar 12 05:50:43 2011
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Tests where specs are allowed and where they aren't.
+
+namespace dyn {
+
+  // Straight from the standard:
+
+  // Plain function with spec
+  void f() throw(int);
+
+  // Pointer to function with spec
+  void (*fp)() throw (int);
+
+  // Function taking reference to function with spec
+  void g(void pfa() throw(int));
+
+  // Typedef for pointer to function with spec
+  typedef int (*pf)() throw(int); // expected-error {{specifications are not allowed in typedefs}}
+
+  // Some more:
+
+  // Function returning function with spec
+  void (*h())() throw(int);
+
+  // Ultimate parser thrill: function with spec returning function with spec and
+  // taking pointer to function with spec.
+  // The actual function throws int, the return type double, the argument float.
+  void (*i() throw(int))(void (*)() throw(float)) throw(double);
+
+  // Pointer to pointer to function taking function with spec
+  void (**k)(void pfa() throw(int)); // no-error
+
+  // Pointer to pointer to function with spec
+  void (**j)() throw(int); // expected-error {{not allowed beyond a single}}
+
+  // Pointer to function returning pointer to pointer to function with spec
+  void (**(*h())())() throw(int); // expected-error {{not allowed beyond a single}}
+
+}
+
+namespace noex {
+
+  // These parallel those from above.
+
+  void f() noexcept(false);
+
+  void (*fp)() noexcept(false);
+
+  void g(void pfa() noexcept(false));
+
+  typedef int (*pf)() noexcept(false); // expected-error {{specifications are not allowed in typedefs}}
+
+  void (*h())() noexcept(false);
+
+  void (*i() noexcept(false))(void (*)() noexcept(true)) noexcept(false);
+
+  void (**k)(void pfa() noexcept(false)); // no-error
+
+  void (**j)() noexcept(false); // expected-error {{not allowed beyond a single}}
+
+  void (**(*h())())() noexcept(false); // expected-error {{not allowed beyond a single}}
+}

Added: cfe/trunk/test/CXX/except/except.spec/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p3.cpp?rev=127537&view=auto
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p3.cpp (added)
+++ cfe/trunk/test/CXX/except/except.spec/p3.cpp Sat Mar 12 05:50:43 2011
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Exception specification compatibility.
+// We test function pointers, because functions have an extra rule in p4.
+
+// Same type is compatible
+extern void (*r1)() throw(int);
+extern void (*r1)() throw(int);
+
+// Typedefs don't matter.
+typedef int INT;
+extern void (*r2)() throw(int);
+extern void (*r2)() throw(INT);
+
+// Order doesn't matter.
+extern void (*r3)() throw(int, float);
+extern void (*r3)() throw(float, int);
+
+// MS throw-any spec and no spec at all are compatible
+extern void (*r4)();
+extern void (*r4)() throw(...);
+
+// throw(X) and no spec are not compatible
+extern void (*r5)() throw(int); // expected-note {{previous declaration}}
+extern void (*r5)(); // expected-error {{exception specification in declaration does not match}}
+
+// For functions, we accept this with a warning.
+extern void f5() throw(int); // expected-note {{previous declaration}}
+extern void f5(); // expected-warning {{missing exception specification}}
+
+// Different types are not compatible.
+extern void (*r7)() throw(int); // expected-note {{previous declaration}}
+extern void (*r7)() throw(float); // expected-error {{exception specification in declaration does not match}}
+
+// Top-level const doesn't matter.
+extern void (*r8)() throw(int);
+extern void (*r8)() throw(const int);
+
+// Multiple appearances don't matter.
+extern void (*r9)() throw(int, int);
+extern void (*r9)() throw(int, int);
+
+
+// noexcept is compatible with itself
+extern void (*r10)() noexcept;
+extern void (*r10)() noexcept;
+
+// noexcept(true) is compatible with noexcept
+extern void (*r11)() noexcept;
+extern void (*r11)() noexcept(true);
+
+// noexcept(false) isn't
+extern void (*r12)() noexcept; // expected-note {{previous declaration}}
+extern void (*r12)() noexcept(false); // expected-error {{does not match}}
+
+// The form of the boolean expression doesn't matter.
+extern void (*r13)() noexcept(1 < 2);
+extern void (*r13)() noexcept(2 > 1);
+
+// noexcept(false) is incompatible with noexcept(true)
+extern void (*r14)() noexcept(true); // expected-note {{previous declaration}}
+extern void (*r14)() noexcept(false); // expected-error {{does not match}}
+
+// noexcept(false) is compatible with itself
+extern void (*r15)() noexcept(false);
+extern void (*r15)() noexcept(false);
+
+// noexcept(false) is compatible with MS throw(...)
+extern void (*r16)() noexcept(false);
+extern void (*r16)() throw(...);
+
+// noexcept(false) is *not* compatible with no spec
+extern void (*r17)(); // expected-note {{previous declaration}}
+extern void (*r17)() noexcept(false); // expected-error {{does not match}}
+
+// except for functions
+void f17();
+void f17() noexcept(false);
+
+// noexcept(false) is compatible with dynamic specs that throw unless
+// CWG 1073 resolution is accepted. Clang implements it.
+//extern void (*r18)() throw(int);
+//extern void (*r18)() noexcept(false);
+
+// noexcept(true) is compatible with dynamic specs that don't throw
+extern void (*r19)() throw();
+extern void (*r19)() noexcept(true);
+
+// The other way round doesn't work.
+extern void (*r20)() throw(); // expected-note {{previous declaration}}
+extern void (*r20)() noexcept(false); // expected-error {{does not match}}
+
+extern void (*r21)() throw(int); // expected-note {{previous declaration}}
+extern void (*r21)() noexcept(true); // expected-error {{does not match}}

Added: cfe/trunk/test/CXX/except/except.spec/p5-pointers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p5-pointers.cpp?rev=127537&view=auto
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p5-pointers.cpp (added)
+++ cfe/trunk/test/CXX/except/except.spec/p5-pointers.cpp Sat Mar 12 05:50:43 2011
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Assignment of function pointers.
+
+struct A
+{
+};
+
+struct B1 : A
+{
+};
+
+struct B2 : A
+{
+};
+
+struct D : B1, B2
+{
+};
+
+struct P : private A
+{
+};
+
+// Some functions to play with below.
+void s1() throw();
+void s2() throw(int);
+void s3() throw(A);
+void s4() throw(B1);
+void s5() throw(D);
+void s6();
+void s7() throw(int, float);
+void (*s8())() throw(B1); // s8 returns a pointer to function with spec
+void s9(void (*)() throw(B1)); // s9 takes pointer to function with spec
+
+void s10() noexcept;
+void s11() noexcept(true);
+void s12() noexcept(false);
+
+void fnptrs()
+{
+  // Assignment and initialization of function pointers.
+  void (*t1)() throw() = &s1;    // valid
+  t1 = &s2;                      // expected-error {{not superset}} expected-error {{incompatible type}}
+  t1 = &s3;                      // expected-error {{not superset}} expected-error {{incompatible type}}
+  void (&t2)() throw() = s2;     // expected-error {{not superset}}
+  void (*t3)() throw(int) = &s2; // valid
+  void (*t4)() throw(A) = &s1;   // valid
+  t4 = &s3;                      // valid
+  t4 = &s4;                      // valid
+  t4 = &s5;                      // expected-error {{not superset}} expected-error {{incompatible type}}
+  void (*t5)() = &s1;            // valid
+  t5 = &s2;                      // valid
+  t5 = &s6;                      // valid
+  t5 = &s7;                      // valid
+  t1 = t3;                       // expected-error {{not superset}} expected-error {{incompatible type}}
+  t3 = t1;                       // valid
+  void (*t6)() throw(B1);
+  t6 = t4;                       // expected-error {{not superset}} expected-error {{incompatible type}}
+  t4 = t6;                       // valid
+  t5 = t1;                       // valid
+  t1 = t5;                       // expected-error {{not superset}} expected-error {{incompatible type}}
+
+  // return types and arguments must match exactly, no inheritance allowed
+  void (*(*t7)())() throw(B1) = &s8;       // valid
+  void (*(*t8)())() throw(A) = &s8;        // expected-error {{return types differ}}
+  void (*(*t9)())() throw(D) = &s8;        // expected-error {{return types differ}}
+  void (*t10)(void (*)() throw(B1)) = &s9; // valid   expected-warning{{disambiguated}}
+  void (*t11)(void (*)() throw(A)) = &s9;  // expected-error {{argument types differ}} expected-warning{{disambiguated}}
+  void (*t12)(void (*)() throw(D)) = &s9;  // expected-error {{argument types differ}} expected-warning{{disambiguated}}
+}
+
+// Member function stuff
+
+struct Str1 { void f() throw(int); }; // expected-note {{previous declaration}}
+void Str1::f() // expected-warning {{missing exception specification}}
+{
+}
+
+void mfnptr()
+{
+  void (Str1::*pfn1)() throw(int) = &Str1::f; // valid
+  void (Str1::*pfn2)() = &Str1::f; // valid
+  void (Str1::*pfn3)() throw() = &Str1::f; // expected-error {{not superset}}
+}

Added: cfe/trunk/test/CXX/except/except.spec/p5-virtual.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p5-virtual.cpp?rev=127537&view=auto
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p5-virtual.cpp (added)
+++ cfe/trunk/test/CXX/except/except.spec/p5-virtual.cpp Sat Mar 12 05:50:43 2011
@@ -0,0 +1,96 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// Compatibility of virtual functions.
+
+struct A
+{
+};
+
+struct B1 : A
+{
+};
+
+struct B2 : A
+{
+};
+
+struct D : B1, B2
+{
+};
+
+struct P : private A
+{
+};
+
+struct Base
+{
+  virtual void f1() throw();
+  virtual void f2() throw(int, float);
+
+  virtual void f3() throw(int, float);
+  virtual void f4() throw(A);
+  virtual void f5() throw(A, int, float);
+  virtual void f6();
+
+  virtual void f7() noexcept;
+  virtual void f8() noexcept;
+  virtual void f9() noexcept(false);
+  virtual void f10() noexcept(false);
+
+  virtual void f11() throw();
+  virtual void f12() noexcept;
+  virtual void f13() noexcept(false);
+  virtual void f14() throw(int);
+
+  virtual void f15();
+  virtual void f16();
+
+  virtual void g1() throw(); // expected-note {{overridden virtual function is here}}
+  virtual void g2() throw(int); // expected-note {{overridden virtual function is here}}
+  virtual void g3() throw(A); // expected-note {{overridden virtual function is here}}
+  virtual void g4() throw(B1); // expected-note {{overridden virtual function is here}}
+  virtual void g5() throw(A); // expected-note {{overridden virtual function is here}}
+
+  virtual void g6() noexcept; // expected-note {{overridden virtual function is here}}
+  virtual void g7() noexcept; // expected-note {{overridden virtual function is here}}
+
+  virtual void g8() noexcept; // expected-note {{overridden virtual function is here}}
+  virtual void g9() throw(); // expected-note {{overridden virtual function is here}}
+  virtual void g10() throw(int); // expected-note {{overridden virtual function is here}}
+};
+struct Derived : Base
+{
+  virtual void f1() throw();
+  virtual void f2() throw(float, int);
+
+  virtual void f3() throw(float);
+  virtual void f4() throw(B1);
+  virtual void f5() throw(B1, B2, int);
+  virtual void f6() throw(B2, B2, int, float, char, double, bool);
+
+  virtual void f7() noexcept;
+  virtual void f8() noexcept(true);
+  virtual void f9() noexcept(true);
+  virtual void f10() noexcept(false);
+
+  virtual void f11() noexcept;
+  virtual void f12() throw();
+  virtual void f13() throw(int);
+  virtual void f14() noexcept(true);
+
+  virtual void f15() noexcept;
+  virtual void f16() throw();
+
+  virtual void g1() throw(int); // expected-error {{exception specification of overriding function is more lax}}
+  virtual void g2(); // expected-error {{exception specification of overriding function is more lax}}
+  virtual void g3() throw(D); // expected-error {{exception specification of overriding function is more lax}}
+  virtual void g4() throw(A); // expected-error {{exception specification of overriding function is more lax}}
+  virtual void g5() throw(P); // expected-error {{exception specification of overriding function is more lax}}
+
+  virtual void g6() noexcept(false); // expected-error {{exception specification of overriding function is more lax}}
+  virtual void g7(); // expected-error {{exception specification of overriding function is more lax}}
+
+  virtual void g8() throw(int); // expected-error {{exception specification of overriding function is more lax}}
+  virtual void g9() noexcept(false); // expected-error {{exception specification of overriding function is more lax}}
+  virtual void g10() noexcept(false); // expected-error {{exception specification of overriding function is more lax}}
+};

Removed: cfe/trunk/test/SemaCXX/exception-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/exception-spec.cpp?rev=127536&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/exception-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/exception-spec.cpp (removed)
@@ -1,193 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -fexceptions -fcxx-exceptions %s
-
-// Straight from the standard:
-// Plain function with spec
-void f() throw(int);
-// Pointer to function with spec
-void (*fp)() throw (int);
-// Function taking reference to function with spec
-void g(void pfa() throw(int));
-// Typedef for pointer to function with spec
-typedef int (*pf)() throw(int); // expected-error {{specifications are not allowed in typedefs}}
-
-// Some more:
-// Function returning function with spec
-void (*h())() throw(int);
-// Ultimate parser thrill: function with spec returning function with spec and
-// taking pointer to function with spec.
-// The actual function throws int, the return type double, the argument float.
-void (*i() throw(int))(void (*)() throw(float)) throw(double);
-// Pointer to pointer to function taking function with spec
-void (**k)(void pfa() throw(int)); // no-error
-// Pointer to pointer to function with spec
-void (**j)() throw(int); // expected-error {{not allowed beyond a single}}
-// Pointer to function returning pointer to pointer to function with spec
-void (**(*h())())() throw(int); // expected-error {{not allowed beyond a single}}
-
-struct Incomplete; // expected-note 3 {{forward declaration}}
-
-// Exception spec must not have incomplete types, or pointers to them, except
-// void.
-void ic1() throw(void); // expected-error {{incomplete type 'void' is not allowed in exception specification}}
-void ic2() throw(Incomplete); // expected-error {{incomplete type 'Incomplete' is not allowed in exception specification}}
-void ic3() throw(void*);
-void ic4() throw(Incomplete*); // expected-error {{pointer to incomplete type 'Incomplete' is not allowed in exception specification}}
-void ic5() throw(Incomplete&); // expected-error {{reference to incomplete type 'Incomplete' is not allowed in exception specification}}
-
-// Redeclarations
-typedef int INT;
-void r1() throw(int);
-void r1() throw(int);
-
-void r2() throw(int);
-void r2() throw(INT);
-
-// throw-any spec and no spec at all are semantically equivalent
-void r4() throw(int, float);
-void r4() throw(float, int);
-
-void r5() throw(int); // expected-note {{previous declaration}}
-void r5(); // expected-warning {{missing exception specification}}
-
-void r7() throw(int); // expected-note {{previous declaration}}
-void r7() throw(float); // expected-error {{exception specification in declaration does not match}}
-
-// Top-level const doesn't matter.
-void r8() throw(int);
-void r8() throw(const int);
-
-// Multiple appearances don't matter.
-void r9() throw(int, int);
-void r9() throw(int, int);
-
-struct A
-{
-};
-
-struct B1 : A
-{
-};
-
-struct B2 : A
-{
-};
-
-struct D : B1, B2
-{
-};
-
-struct P : private A
-{
-};
-
-struct Base
-{
-  virtual void f1() throw();
-  virtual void f4() throw(int, float);
-
-  virtual void f5() throw(int, float);
-  virtual void f6() throw(A);
-  virtual void f7() throw(A, int, float);
-  virtual void f8();
-
-  virtual void g1() throw(); // expected-note {{overridden virtual function is here}}
-  virtual void g2() throw(int); // expected-note {{overridden virtual function is here}}
-  virtual void g3() throw(A); // expected-note {{overridden virtual function is here}}
-  virtual void g4() throw(B1); // expected-note {{overridden virtual function is here}}
-  virtual void g5() throw(A); // expected-note {{overridden virtual function is here}}
-};
-struct Derived : Base
-{
-  virtual void f1() throw();
-  virtual void f4() throw(float, int);
-
-  virtual void f5() throw(float);
-  virtual void f6() throw(B1);
-  virtual void f7() throw(B1, B2, int);
-  virtual void f8() throw(B2, B2, int, float, char, double, bool);
-
-  virtual void g1() throw(int); // expected-error {{exception specification of overriding function is more lax}}
-  virtual void g2(); // expected-error {{exception specification of overriding function is more lax}}
-  virtual void g3() throw(D); // expected-error {{exception specification of overriding function is more lax}}
-  virtual void g4() throw(A); // expected-error {{exception specification of overriding function is more lax}}
-  virtual void g5() throw(P); // expected-error {{exception specification of overriding function is more lax}}
-};
-
-// Some functions to play with below.
-void s1() throw();
-void s2() throw(int);
-void s3() throw(A);
-void s4() throw(B1);
-void s5() throw(D);
-void s6();
-void s7() throw(int, float);
-void (*s8())() throw(B1); // s8 returns a pointer to function with spec
-void s9(void (*)() throw(B1)); // s9 takes pointer to function with spec
-
-void fnptrs()
-{
-  // Assignment and initialization of function pointers.
-  void (*t1)() throw() = &s1;    // valid
-  t1 = &s2;                      // expected-error {{not superset}} expected-error {{incompatible type}}
-  t1 = &s3;                      // expected-error {{not superset}} expected-error {{incompatible type}}
-  void (&t2)() throw() = s2;     // expected-error {{not superset}}
-  void (*t3)() throw(int) = &s2; // valid
-  void (*t4)() throw(A) = &s1;   // valid
-  t4 = &s3;                      // valid
-  t4 = &s4;                      // valid
-  t4 = &s5;                      // expected-error {{not superset}} expected-error {{incompatible type}}
-  void (*t5)() = &s1;            // valid
-  t5 = &s2;                      // valid
-  t5 = &s6;                      // valid
-  t5 = &s7;                      // valid
-  t1 = t3;                       // expected-error {{not superset}} expected-error {{incompatible type}}
-  t3 = t1;                       // valid
-  void (*t6)() throw(B1);
-  t6 = t4;                       // expected-error {{not superset}} expected-error {{incompatible type}}
-  t4 = t6;                       // valid
-  t5 = t1;                       // valid
-  t1 = t5;                       // expected-error {{not superset}} expected-error {{incompatible type}}
-
-  // return types and arguments must match exactly, no inheritance allowed
-  void (*(*t7)())() throw(B1) = &s8;       // valid
-  void (*(*t8)())() throw(A) = &s8;        // expected-error {{return types differ}}
-  void (*(*t9)())() throw(D) = &s8;        // expected-error {{return types differ}}
-  void (*t10)(void (*)() throw(B1)) = &s9; // valid   expected-warning{{disambiguated}}
-  void (*t11)(void (*)() throw(A)) = &s9;  // expected-error {{argument types differ}} expected-warning{{disambiguated}}
-  void (*t12)(void (*)() throw(D)) = &s9;  // expected-error {{argument types differ}} expected-warning{{disambiguated}}
-}
-
-// Member function stuff
-
-struct Str1 { void f() throw(int); }; // expected-note {{previous declaration}}
-void Str1::f() // expected-warning {{missing exception specification}}
-{
-}
-
-void mfnptr()
-{
-  void (Str1::*pfn1)() throw(int) = &Str1::f; // valid
-  void (Str1::*pfn2)() = &Str1::f; // valid
-  void (Str1::*pfn3)() throw() = &Str1::f; // expected-error {{not superset}}
-}
-
-// Don't suppress errors in template instantiation.
-template <typename T> struct TEx; // expected-note {{template is declared here}}
-
-void tf() throw(TEx<int>); // expected-error {{implicit instantiation of undefined template}}
-
-// DR 437, class throws itself.
-struct DR437 {
-   void f() throw(DR437);
-   void g() throw(DR437*);
-   void h() throw(DR437&);
-};
-
-// DR 437 within a nested class
-struct DR437_out {
-   struct DR437_in {
-      void f() throw(DR437_out);
-      void g() throw(DR437_out*);
-      void h() throw(DR437_out&);
-   }; 
-};





More information about the cfe-commits mailing list