Implement the core checking for compatible exception specifications in assignment and initialization.

The exception specification of the assignee must be the same or a subset of the target. In addition, exception specifications on arguments and return types must be equivalent, but this is not implemented yet.
This currently produces two diagnostics for every invalid assignment/initialization, due to the diagnostic produced outside PerformImplicitConversion, e.g. in CheckSingleInitializer. I don't know how to suppress this; in any case I think it is the wrong place for a diagnostic, since there are other diagnostics produced inside the function. So I'm leaving it as it is for the moment.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83710 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index d746237..eb0b6e1 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1197,7 +1197,11 @@
   // Perform the second implicit conversion
   switch (SCS.Second) {
   case ICK_Identity:
-    // Nothing to do.
+    // If both sides are functions (or pointers/references to them), there could
+    // be incompatible exception declarations.
+    if (CheckExceptionSpecCompatibility(From, ToType))
+      return true;
+    // Nothing else to do.
     break;
 
   case ICK_Integral_Promotion:
@@ -1235,6 +1239,8 @@
     CastExpr::CastKind Kind = CastExpr::CK_Unknown;
     if (CheckMemberPointerConversion(From, ToType, Kind))
       return true;
+    if (CheckExceptionSpecCompatibility(From, ToType))
+      return true;
     ImpCastExprToType(From, ToType, Kind);
     break;
   }
@@ -1269,6 +1275,38 @@
   return false;
 }
 
+bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
+{
+  // First we check for applicability.
+  // Target type must be a function, function pointer or function reference.
+  if (const PointerType *PtrTy = ToType->getAs<PointerType>())
+    ToType = PtrTy->getPointeeType();
+  else if (const ReferenceType *RefTy = ToType->getAs<ReferenceType>())
+    ToType = RefTy->getPointeeType();
+
+  const FunctionProtoType *ToFunc = ToType->getAs<FunctionProtoType>();
+  if (!ToFunc)
+    return false;
+
+  // SourceType must be a function or function pointer.
+  // References are treated as functions.
+  QualType FromType = From->getType();
+  if (const PointerType *PtrTy = FromType->getAs<PointerType>())
+    FromType = PtrTy->getPointeeType();
+
+  const FunctionProtoType *FromFunc = FromType->getAs<FunctionProtoType>();
+  if (!FromFunc)
+    return false;
+
+  // Now we've got the correct types on both sides, check their compatibility.
+  // This means that the source of the conversion can only throw a subset of
+  // the exceptions of the target, and any exception specs on arguments or
+  // return types must be equivalent.
+  return CheckExceptionSpecSubset(diag::err_incompatible_exception_specs,
+                                  0, ToFunc, From->getSourceRange().getBegin(),
+                                  FromFunc, SourceLocation());
+}
+
 Sema::OwningExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
                                                  SourceLocation KWLoc,
                                                  SourceLocation LParen,