r284337 - P0012R1: Make exception specifications be part of the type system. This

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 16 10:54:24 PDT 2016


Author: rsmith
Date: Sun Oct 16 12:54:23 2016
New Revision: 284337

URL: http://llvm.org/viewvc/llvm-project?rev=284337&view=rev
Log:
P0012R1: Make exception specifications be part of the type system. This
implements the bulk of the change (modifying the type system to include
exception specifications), but not all the details just yet.

Added:
    cfe/trunk/test/CXX/conv/conv.fctptr/
    cfe/trunk/test/CXX/conv/conv.fctptr/p1.cpp
    cfe/trunk/test/CXX/except/except.spec/p2-places-1z.cpp
    cfe/trunk/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.scs/p3.cpp
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p5.cpp
Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Overload.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
    cfe/trunk/test/CXX/drs/dr0xx.cpp
    cfe/trunk/test/CXX/drs/dr1xx.cpp
    cfe/trunk/test/CXX/drs/dr2xx.cpp
    cfe/trunk/test/CXX/except/except.spec/p2-places.cpp
    cfe/trunk/test/CXX/expr/expr.const/p3-0x.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp
    cfe/trunk/test/CXX/over/over.over/p1.cpp
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
    cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp
    cfe/trunk/test/SemaCXX/deprecated.cpp

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Sun Oct 16 12:54:23 2016
@@ -3364,9 +3364,15 @@ public:
     return reinterpret_cast<FunctionDecl *const *>(param_type_end())[1];
   }
   /// Determine whether this function type has a non-throwing exception
+  /// specification.
+  CanThrowResult canThrow(const ASTContext &Ctx) const;
+  /// Determine whether this function type has a non-throwing exception
   /// specification. If this depends on template arguments, returns
   /// \c ResultIfDependent.
-  bool isNothrow(const ASTContext &Ctx, bool ResultIfDependent = false) const;
+  bool isNothrow(const ASTContext &Ctx, bool ResultIfDependent = false) const {
+    return ResultIfDependent ? canThrow(Ctx) != CT_Can
+                             : canThrow(Ctx) == CT_Cannot;
+  }
 
   bool isVariadic() const { return Variadic; }
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Oct 16 12:54:23 2016
@@ -1644,7 +1644,8 @@ def err_init_conversion_failed : Error<
   "%select{none|const|restrict|const and restrict|volatile|const and volatile|"
   "volatile and restrict|const, volatile, and restrict}5 vs "
   "%select{none|const|restrict|const and restrict|volatile|const and volatile|"
-  "volatile and restrict|const, volatile, and restrict}6)}4">;
+  "volatile and restrict|const, volatile, and restrict}6)"
+  "|: different exception specifications}4">;
 
 def err_lvalue_to_rvalue_ref : Error<"rvalue reference %diff{to type $ cannot "
   "bind to lvalue of type $|cannot bind to incompatible lvalue}0,1">;
@@ -3278,7 +3279,8 @@ def note_ovl_candidate : Note<"candidate
     "%select{none|const|restrict|const and restrict|volatile|const and volatile"
     "|volatile and restrict|const, volatile, and restrict}3 but found "
     "%select{none|const|restrict|const and restrict|volatile|const and volatile"
-    "|volatile and restrict|const, volatile, and restrict}4)}2">;
+    "|volatile and restrict|const, volatile, and restrict}4)"
+    "| has different exception specification}2">;
 
 def note_ovl_candidate_inherited_constructor : Note<
     "constructor from base class %0 inherited here">;
@@ -6101,7 +6103,8 @@ def note_hidden_overloaded_virtual_decla
   "%select{none|const|restrict|const and restrict|volatile|const and volatile|"
   "volatile and restrict|const, volatile, and restrict}2 vs "
   "%select{none|const|restrict|const and restrict|volatile|const and volatile|"
-  "volatile and restrict|const, volatile, and restrict}3)}1">;
+  "volatile and restrict|const, volatile, and restrict}3)"
+  "|: different exception specifications}1">;
 def warn_using_directive_in_header : Warning<
   "using namespace directive in global context in header">,
   InGroup<HeaderHygiene>, DefaultIgnore;
@@ -6343,7 +6346,8 @@ def err_typecheck_convert_incompatible :
   "%select{none|const|restrict|const and restrict|volatile|const and volatile|"
   "volatile and restrict|const, volatile, and restrict}5 vs "
   "%select{none|const|restrict|const and restrict|volatile|const and volatile|"
-  "volatile and restrict|const, volatile, and restrict}6)}4">;
+  "volatile and restrict|const, volatile, and restrict}6)"
+  "|: different exception specifications}4">;
 def err_typecheck_missing_return_type_incompatible : Error<
   "%diff{return type $ must match previous return type $|"
   "return type must match previous return type}0,1 when %select{block "

Modified: cfe/trunk/include/clang/Sema/Overload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Overload.h (original)
+++ cfe/trunk/include/clang/Sema/Overload.h Sun Oct 16 12:54:23 2016
@@ -62,7 +62,7 @@ namespace clang {
     ICK_Lvalue_To_Rvalue,      ///< Lvalue-to-rvalue conversion (C++ 4.1)
     ICK_Array_To_Pointer,      ///< Array-to-pointer conversion (C++ 4.2)
     ICK_Function_To_Pointer,   ///< Function-to-pointer (C++ 4.3)
-    ICK_NoReturn_Adjustment,   ///< Removal of noreturn from a type (Clang)
+    ICK_Function_Conversion,   ///< Function pointer conversion (C++17 4.13)
     ICK_Qualification,         ///< Qualification conversions (C++ 4.4)
     ICK_Integral_Promotion,    ///< Integral promotions (C++ 4.5)
     ICK_Floating_Promotion,    ///< Floating point promotions (C++ 4.6)

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sun Oct 16 12:54:23 2016
@@ -2373,7 +2373,7 @@ public:
                                     bool IgnoreBaseAccess);
   bool IsQualificationConversion(QualType FromType, QualType ToType,
                                  bool CStyle, bool &ObjCLifetimeConversion);
-  bool IsNoReturnConversion(QualType FromType, QualType ToType,
+  bool IsFunctionConversion(QualType FromType, QualType ToType,
                             QualType &ResultTy);
   bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
   bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg);

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Sun Oct 16 12:54:23 2016
@@ -3193,6 +3193,34 @@ ASTContext::getCanonicalFunctionResultTy
   return CanResultType;
 }
 
+static bool isCanonicalExceptionSpecification(
+    const FunctionProtoType::ExceptionSpecInfo &ESI, bool NoexceptInType) {
+  if (ESI.Type == EST_None)
+    return true;
+  if (!NoexceptInType)
+    return false;
+
+  // C++17 onwards: exception specification is part of the type, as a simple
+  // boolean "can this function type throw".
+  if (ESI.Type == EST_BasicNoexcept)
+    return true;
+
+  // A dynamic exception specification is canonical if it only contains pack
+  // expansions (so we can't tell whether it's non-throwing).
+  if (ESI.Type == EST_Dynamic) {
+    for (QualType ET : ESI.Exceptions)
+      if (!ET->getAs<PackExpansionType>())
+        return false;
+    return true;
+  }
+
+  // A noexcept(expr) specification is canonical if expr is value-dependent.
+  if (ESI.Type == EST_ComputedNoexcept)
+    return ESI.NoexceptExpr && ESI.NoexceptExpr->isValueDependent();
+
+  return false;
+}
+
 QualType
 ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
                             const FunctionProtoType::ExtProtoInfo &EPI) const {
@@ -3209,10 +3237,14 @@ ASTContext::getFunctionType(QualType Res
         FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos))
     return QualType(FTP, 0);
 
+  bool NoexceptInType = getLangOpts().CPlusPlus1z;
+
+  bool IsCanonicalExceptionSpec =
+      isCanonicalExceptionSpecification(EPI.ExceptionSpec, NoexceptInType);
+
   // Determine whether the type being created is already canonical or not.
-  bool isCanonical =
-    EPI.ExceptionSpec.Type == EST_None && isCanonicalResultType(ResultTy) &&
-    !EPI.HasTrailingReturn;
+  bool isCanonical = IsCanonicalExceptionSpec &&
+                     isCanonicalResultType(ResultTy) && !EPI.HasTrailingReturn;
   for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
     if (!ArgArray[i].isCanonicalAsParam())
       isCanonical = false;
@@ -3228,7 +3260,45 @@ ASTContext::getFunctionType(QualType Res
 
     FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI;
     CanonicalEPI.HasTrailingReturn = false;
-    CanonicalEPI.ExceptionSpec = FunctionProtoType::ExceptionSpecInfo();
+
+    if (IsCanonicalExceptionSpec) {
+      // Exception spec is already OK.
+    } else if (NoexceptInType) {
+      switch (EPI.ExceptionSpec.Type) {
+      case EST_Unparsed: case EST_Unevaluated: case EST_Uninstantiated:
+        // We don't know yet. It shouldn't matter what we pick here; no-one
+        // should ever look at this.
+        LLVM_FALLTHROUGH;
+      case EST_None: case EST_MSAny: case EST_Dynamic:
+        // If we get here for EST_Dynamic, there is at least one
+        // non-pack-expansion type, so this is not non-throwing.
+        CanonicalEPI.ExceptionSpec.Type = EST_None;
+        break;
+
+      case EST_DynamicNone: case EST_BasicNoexcept:
+        CanonicalEPI.ExceptionSpec.Type = EST_BasicNoexcept;
+        break;
+
+      case EST_ComputedNoexcept:
+        llvm::APSInt Value(1);
+        auto *E = CanonicalEPI.ExceptionSpec.NoexceptExpr;
+        if (!E || !E->isIntegerConstantExpr(Value, *this, nullptr,
+                                            /*IsEvaluated*/false)) {
+          // This noexcept specification is invalid.
+          // FIXME: Should this be able to happen?
+          CanonicalEPI.ExceptionSpec.Type = EST_None;
+          break;
+        }
+
+        CanonicalEPI.ExceptionSpec.Type =
+            Value.getBoolValue() ? EST_BasicNoexcept : EST_None;
+        break;
+      }
+      assert(isCanonicalExceptionSpecification(CanonicalEPI.ExceptionSpec,
+                                               NoexceptInType));
+    } else {
+      CanonicalEPI.ExceptionSpec = FunctionProtoType::ExceptionSpecInfo();
+    }
 
     // Adjust the canonical function result type.
     CanQualType CanResultTy = getCanonicalFunctionResultType(ResultTy);

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Sun Oct 16 12:54:23 2016
@@ -2717,8 +2717,9 @@ FunctionProtoType::FunctionProtoType(Qua
     QualType *exnSlot = argSlot + NumParams;
     unsigned I = 0;
     for (QualType ExceptionType : epi.ExceptionSpec.Exceptions) {
-      // Note that a dependent exception specification does *not* make
-      // a type dependent; it's not even part of the C++ type system.
+      // Note that, before C++17, a dependent exception specification does
+      // *not* make a type dependent; it's not even part of the C++ type
+      // system.
       if (ExceptionType->isInstantiationDependentType())
         setInstantiationDependent();
 
@@ -2757,6 +2758,19 @@ FunctionProtoType::FunctionProtoType(Qua
     slot[0] = epi.ExceptionSpec.SourceDecl;
   }
 
+  // If this is a canonical type, and its exception specification is dependent,
+  // then it's a dependent type. This only happens in C++17 onwards.
+  if (isCanonicalUnqualified()) {
+    if (getExceptionSpecType() == EST_Dynamic ||
+        getExceptionSpecType() == EST_ComputedNoexcept) {
+      assert(hasDependentExceptionSpec() && "type should not be canonical");
+      setDependent();
+    }
+  } else if (getCanonicalTypeInternal()->isDependentType()) {
+    // Ask our canonical type whether our exception specification was dependent.
+    setDependent();
+  }
+
   if (epi.ExtParameterInfos) {
     ExtParameterInfo *extParamInfos =
       const_cast<ExtParameterInfo *>(getExtParameterInfosBuffer());
@@ -2801,29 +2815,28 @@ FunctionProtoType::getNoexceptSpec(const
   return value.getBoolValue() ? NR_Nothrow : NR_Throw;
 }
 
-bool FunctionProtoType::isNothrow(const ASTContext &Ctx,
-                                  bool ResultIfDependent) const {
+CanThrowResult FunctionProtoType::canThrow(const ASTContext &Ctx) const {
   ExceptionSpecificationType EST = getExceptionSpecType();
   assert(EST != EST_Unevaluated && EST != EST_Uninstantiated);
   if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
-    return true;
+    return CT_Cannot;
 
-  if (EST == EST_Dynamic && ResultIfDependent) {
+  if (EST == EST_Dynamic) {
     // A dynamic exception specification is throwing unless every exception
     // type is an (unexpanded) pack expansion type.
     for (unsigned I = 0, N = NumExceptions; I != N; ++I)
       if (!getExceptionType(I)->getAs<PackExpansionType>())
-        return false;
-    return ResultIfDependent;
+        return CT_Can;
+    return CT_Dependent;
   }
 
   if (EST != EST_ComputedNoexcept)
-    return false;
+    return CT_Can;
 
   NoexceptResult NR = getNoexceptSpec(Ctx);
   if (NR == NR_Dependent)
-    return ResultIfDependent;
-  return NR == NR_Nothrow;
+    return CT_Dependent;
+  return NR == NR_Nothrow ? CT_Cannot : CT_Can;
 }
 
 bool FunctionProtoType::isTemplateVariadic() const {

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Oct 16 12:54:23 2016
@@ -2933,10 +2933,20 @@ bool Sema::MergeFunctionDecl(FunctionDec
   }
 
   if (getLangOpts().CPlusPlus) {
-    // (C++98 13.1p2):
+    // C++1z [over.load]p2
     //   Certain function declarations cannot be overloaded:
-    //     -- Function declarations that differ only in the return type
-    //        cannot be overloaded.
+    //     -- Function declarations that differ only in the return type,
+    //        the exception specification, or both cannot be overloaded.
+
+    // Check the exception specifications match. This may recompute the type of
+    // both Old and New if it resolved exception specifications, so grab the
+    // types again after this. Because this updates the type, we do this before
+    // any of the other checks below, which may update the "de facto" NewQType
+    // but do not necessarily update the type of New.
+    if (CheckEquivalentExceptionSpec(Old, New))
+      return true;
+    OldQType = Context.getCanonicalType(Old->getType());
+    NewQType = Context.getCanonicalType(New->getType());
 
     // Go back to the type source info to compare the declared return types,
     // per C++1y [dcl.type.auto]p13:
@@ -2951,10 +2961,10 @@ bool Sema::MergeFunctionDecl(FunctionDec
         (New->getTypeSourceInfo()
              ? New->getTypeSourceInfo()->getType()->castAs<FunctionType>()
              : NewType)->getReturnType();
-    QualType ResQT;
     if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) &&
         !((NewQType->isDependentType() || OldQType->isDependentType()) &&
           New->isLocalExternDecl())) {
+      QualType ResQT;
       if (NewDeclaredReturnType->isObjCObjectPointerType() &&
           OldDeclaredReturnType->isObjCObjectPointerType())
         ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType);
@@ -3092,7 +3102,7 @@ bool Sema::MergeFunctionDecl(FunctionDec
     // noreturn should now match unless the old type info didn't have it.
     QualType OldQTypeForComparison = OldQType;
     if (!OldTypeInfo.getNoReturn() && NewTypeInfo.getNoReturn()) {
-      assert(OldQType == QualType(OldType, 0));
+      auto *OldType = OldQType->castAs<FunctionProtoType>();
       const FunctionType *OldTypeForComparison
         = Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true));
       OldQTypeForComparison = QualType(OldTypeForComparison, 0);

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Oct 16 12:54:23 2016
@@ -659,9 +659,6 @@ bool Sema::MergeCXXFunctionDecl(Function
     Invalid = true;
   }
 
-  if (CheckEquivalentExceptionSpec(Old, New))
-    Invalid = true;
-
   return Invalid;
 }
 

Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Sun Oct 16 12:54:23 2016
@@ -130,6 +130,11 @@ bool Sema::CheckSpecifiedExceptionType(Q
 /// to member to a function with an exception specification. This means that
 /// it is invalid to add another level of indirection.
 bool Sema::CheckDistantExceptionSpec(QualType T) {
+  // C++17 removes this rule in favor of putting exception specifications into
+  // the type system.
+  if (getLangOpts().CPlusPlus1z)
+    return false;
+
   if (const PointerType *PT = T->getAs<PointerType>())
     T = PT->getPointeeType();
   else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sun Oct 16 12:54:23 2016
@@ -7288,7 +7288,7 @@ checkPointerTypesForAssignment(Sema &S,
     return Sema::IncompatiblePointer;
   }
   if (!S.getLangOpts().CPlusPlus &&
-      S.IsNoReturnConversion(ltrans, rtrans, ltrans))
+      S.IsFunctionConversion(ltrans, rtrans, ltrans))
     return Sema::IncompatiblePointer;
   return ConvTy;
 }

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sun Oct 16 12:54:23 2016
@@ -3610,7 +3610,7 @@ Sema::PerformImplicitConversion(Expr *Fr
     // Nothing else to do.
     break;
 
-  case ICK_NoReturn_Adjustment:
+  case ICK_Function_Conversion:
     // If both sides are functions (or pointers/references to them), there could
     // be incompatible exception declarations.
     if (CheckExceptionSpecCompatibility(From, ToType))

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sun Oct 16 12:54:23 2016
@@ -150,7 +150,7 @@ static const char* GetImplicitConversion
     "Lvalue-to-rvalue",
     "Array-to-pointer",
     "Function-to-pointer",
-    "Noreturn adjustment",
+    "Function pointer conversion",
     "Qualification",
     "Integral promotion",
     "Floating point promotion",
@@ -1390,13 +1390,15 @@ Sema::PerformImplicitConversion(Expr *Fr
 }
 
 /// \brief Determine whether the conversion from FromType to ToType is a valid
-/// conversion that strips "noreturn" off the nested function type.
-bool Sema::IsNoReturnConversion(QualType FromType, QualType ToType,
+/// conversion that strips "noexcept" or "noreturn" off the nested function
+/// type.
+bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
                                 QualType &ResultTy) {
   if (Context.hasSameUnqualifiedType(FromType, ToType))
     return false;
 
   // Permit the conversion F(t __attribute__((noreturn))) -> F(t)
+  //                    or F(t noexcept) -> F(t)
   // where F adds one of the following at most once:
   //   - a pointer
   //   - a member pointer
@@ -1425,11 +1427,37 @@ bool Sema::IsNoReturnConversion(QualType
       return false;
   }
 
-  const FunctionType *FromFn = cast<FunctionType>(CanFrom);
-  FunctionType::ExtInfo EInfo = FromFn->getExtInfo();
-  if (!EInfo.getNoReturn()) return false;
+  const auto *FromFn = cast<FunctionType>(CanFrom);
+  FunctionType::ExtInfo FromEInfo = FromFn->getExtInfo();
+
+  const auto *ToFn = dyn_cast<FunctionProtoType>(CanTo);
+  FunctionType::ExtInfo ToEInfo = ToFn->getExtInfo();
+
+  bool Changed = false;
+
+  // Drop 'noreturn' if not present in target type.
+  if (FromEInfo.getNoReturn() && !ToEInfo.getNoReturn()) {
+    FromFn = Context.adjustFunctionType(FromFn, FromEInfo.withNoReturn(false));
+    Changed = true;
+  }
+
+  // Drop 'noexcept' if not present in target type.
+  if (const auto *FromFPT = dyn_cast<FunctionProtoType>(FromFn)) {
+    const auto *ToFPT = dyn_cast<FunctionProtoType>(ToFn);
+    if (FromFPT->isNothrow(Context) && !ToFPT->isNothrow(Context)) {
+      FromFn = cast<FunctionType>(
+          Context.getFunctionType(FromFPT->getReturnType(),
+                                  FromFPT->getParamTypes(),
+                                  FromFPT->getExtProtoInfo().withExceptionSpec(
+                                      FunctionProtoType::ExceptionSpecInfo()))
+                 .getTypePtr());
+      Changed = true;
+    }
+  }
+
+  if (!Changed)
+    return false;
 
-  FromFn = Context.adjustFunctionType(FromFn, EInfo.withNoReturn(false));
   assert(QualType(FromFn, 0).isCanonical());
   if (QualType(FromFn, 0) != CanTo) return false;
 
@@ -1534,7 +1562,7 @@ static bool IsStandardConversion(Sema &S
                       S.ExtractUnqualifiedFunctionType(ToType), FromType)) {
         QualType resultTy;
         // if the function type matches except for [[noreturn]], it's ok
-        if (!S.IsNoReturnConversion(FromType,
+        if (!S.IsFunctionConversion(FromType,
               S.ExtractUnqualifiedFunctionType(ToType), resultTy))
           // otherwise, only a boolean conversion is standard   
           if (!ToType->isBooleanType()) 
@@ -1727,9 +1755,10 @@ static bool IsStandardConversion(Sema &S
     // Compatible conversions (Clang extension for C function overloading)
     SCS.Second = ICK_Compatible_Conversion;
     FromType = ToType.getUnqualifiedType();
-  } else if (S.IsNoReturnConversion(FromType, ToType, FromType)) {
-    // Treat a conversion that strips "noreturn" as an identity conversion.
-    SCS.Second = ICK_NoReturn_Adjustment;
+  } else if (S.IsFunctionConversion(FromType, ToType, FromType)) {
+    // Function pointer conversions (removing 'noexcept') including removal of
+    // 'noreturn' (Clang extension).
+    SCS.Second = ICK_Function_Conversion;
   } else if (IsTransparentUnionStandardConversion(S, From, ToType,
                                              InOverloadResolution,
                                              SCS, CStyle)) {
@@ -2615,7 +2644,8 @@ enum {
   ft_parameter_arity,
   ft_parameter_mismatch,
   ft_return_type,
-  ft_qualifer_mismatch
+  ft_qualifer_mismatch,
+  ft_noexcept
 };
 
 /// Attempts to get the FunctionProtoType from a Type. Handles
@@ -2715,6 +2745,16 @@ void Sema::HandleFunctionTypeMismatch(Pa
     return;
   }
 
+  // Handle exception specification differences on canonical type (in C++17
+  // onwards).
+  if (cast<FunctionProtoType>(FromFunction->getCanonicalTypeUnqualified())
+          ->isNothrow(Context) !=
+      cast<FunctionProtoType>(ToFunction->getCanonicalTypeUnqualified())
+          ->isNothrow(Context)) {
+    PDiag << ft_noexcept;
+    return;
+  }
+
   // Unable to find a difference, so add no extra info.
   PDiag << ft_default;
 }
@@ -5096,7 +5136,7 @@ static bool CheckConvertedConstantConver
   // conversions are fine.
   switch (SCS.Second) {
   case ICK_Identity:
-  case ICK_NoReturn_Adjustment:
+  case ICK_Function_Conversion:
   case ICK_Integral_Promotion:
   case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere.
     return true;
@@ -10428,7 +10468,7 @@ private:
   bool candidateHasExactlyCorrectType(const FunctionDecl *FD) {
     QualType Discard;
     return Context.hasSameUnqualifiedType(TargetFunctionType, FD->getType()) ||
-           S.IsNoReturnConversion(FD->getType(), TargetFunctionType, Discard);
+           S.IsFunctionConversion(FD->getType(), TargetFunctionType, Discard);
   }
 
   /// \return true if A is considered a better overload candidate for the

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Sun Oct 16 12:54:23 2016
@@ -956,9 +956,9 @@ bool Sema::isSameOrCompatibleFunctionTyp
   if (!ParamFunction || !ArgFunction)
     return Param == Arg;
 
-  // Noreturn adjustment.
+  // Noreturn and noexcept adjustment.
   QualType AdjustedParam;
-  if (IsNoReturnConversion(Param, Arg, AdjustedParam))
+  if (IsFunctionConversion(Param, Arg, AdjustedParam))
     return Arg == Context.getCanonicalType(AdjustedParam);
 
   // FIXME: Compatible calling conventions.
@@ -2757,18 +2757,17 @@ CheckOriginalCallArgDeduction(Sema &S, S
   }
 
   //    - The transformed A can be another pointer or pointer to member
-  //      type that can be converted to the deduced A via a qualification
-  //      conversion.
+  //      type that can be converted to the deduced A via a function pointer
+  //      conversion and/or a qualification conversion.
   //
   // Also allow conversions which merely strip [[noreturn]] from function types
   // (recursively) as an extension.
-  // FIXME: Currently, this doesn't play nicely with qualification conversions.
   bool ObjCLifetimeConversion = false;
   QualType ResultTy;
   if ((A->isAnyPointerType() || A->isMemberPointerType()) &&
       (S.IsQualificationConversion(A, DeducedA, false,
                                    ObjCLifetimeConversion) ||
-       S.IsNoReturnConversion(A, DeducedA, ResultTy)))
+       S.IsFunctionConversion(A, DeducedA, ResultTy)))
     return false;
 
 

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sun Oct 16 12:54:23 2016
@@ -4142,7 +4142,7 @@ static TypeSourceInfo *GetFullTypeForDec
 
       // Exception specs are not allowed in typedefs. Complain, but add it
       // anyway.
-      if (IsTypedefName && FTI.getExceptionSpecType())
+      if (IsTypedefName && FTI.getExceptionSpecType() && !LangOpts.CPlusPlus1z)
         S.Diag(FTI.getExceptionSpecLocBeg(),
                diag::err_exception_spec_in_typedef)
             << (D.getContext() == Declarator::AliasDeclContext ||

Added: cfe/trunk/test/CXX/conv/conv.fctptr/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/conv/conv.fctptr/p1.cpp?rev=284337&view=auto
==============================================================================
--- cfe/trunk/test/CXX/conv/conv.fctptr/p1.cpp (added)
+++ cfe/trunk/test/CXX/conv/conv.fctptr/p1.cpp Sun Oct 16 12:54:23 2016
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+struct S;
+
+typedef void Nothrow() noexcept;
+typedef void Throw();
+
+Nothrow *a;
+Throw *b;
+Nothrow S::*c;
+Throw S::*d;
+
+void test() {
+  a = b; // expected-error {{assigning to 'Nothrow *' (aka 'void (*)() noexcept') from incompatible type 'Throw *' (aka 'void (*)()'): different exception specifications}}
+  b = a;
+  c = d; // expected-error {{assigning to 'Nothrow S::*' from incompatible type 'Throw S::*': different exception specifications}}
+  d = c;
+
+  // Function pointer conversions do not combine properly with qualification conversions.
+  // FIXME: This seems like a defect.
+  Nothrow *const *pa = b; // expected-error {{cannot initialize}}
+  Throw *const *pb = a; // expected-error {{cannot initialize}}
+  Nothrow *const S::*pc = d; // expected-error {{cannot initialize}}
+  Throw *const S::*pd = c; // expected-error {{cannot initialize}}
+}
+
+// ... The result is a pointer to the function.
+void f() noexcept;
+constexpr void (*p)() = &f;
+static_assert(f == p);
+
+struct S { void f() noexcept; };
+constexpr void (S::*q)() = &S::f;
+static_assert(q == &S::f);
+
+
+namespace std_example {
+  void (*p)() throw(int);
+  void (**pp)() noexcept = &p; // expected-error {{cannot initialize a variable of type 'void (**)() noexcept' with an rvalue of type 'void (**)() throw(int)'}}
+
+  struct S { typedef void (*p)(); operator p(); }; // expected-note {{candidate}}
+  void (*q)() noexcept = S(); // expected-error {{no viable conversion from 'std_example::S' to 'void (*)() noexcept'}}
+}

Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp Sun Oct 16 12:54:23 2016
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s
 
 void f0() &; // expected-error {{non-member function cannot have '&' qualifier}}
 void f1() &&; // expected-error {{non-member function cannot have '&&' qualifier}}
@@ -58,3 +59,16 @@ template<typename T> struct pass {
 };
 pass<func_type_lvalue> pass0;
 pass<func_type_lvalue> pass1;
+
+template<typename T, typename U> struct is_same { static const bool value = false; };
+template<typename T> struct is_same<T, T> { static const bool value = true; };
+constexpr bool cxx1z = __cplusplus > 201402L;
+
+void noexcept_true() noexcept(true);
+void noexcept_false() noexcept(false);
+using func_type_noexcept_true = wrap<decltype(noexcept_true)>;
+using func_type_noexcept_false = wrap<decltype(noexcept_false)>;
+static_assert(is_same<func_type_noexcept_false, func_type_noexcept_true>::value == !cxx1z, "");
+static_assert(is_same<func_type_noexcept_false::val, func_type_noexcept_true::val>::value == !cxx1z, "");
+static_assert(is_same<func_type_noexcept_false::ptr, func_type_noexcept_true::ptr>::value == !cxx1z, "");
+static_assert(is_same<func_type_noexcept_false::ref, func_type_noexcept_true::ref>::value == !cxx1z, "");

Modified: cfe/trunk/test/CXX/drs/dr0xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr0xx.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr0xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr0xx.cpp Sun Oct 16 12:54:23 2016
@@ -279,16 +279,36 @@ namespace dr25 { // dr25: yes
     void f() throw(int);
   };
   void (A::*f)() throw (int);
-  void (A::*g)() throw () = f; // expected-error {{is not superset of source}}
+  void (A::*g)() throw () = f;
+#if __cplusplus <= 201402L
+  // expected-error at -2 {{is not superset of source}}
+#else
+  // expected-error at -4 {{different exception specifications}}
+#endif
   void (A::*g2)() throw () = 0;
   void (A::*h)() throw (int, char) = f;
-  void (A::*i)() throw () = &A::f; // expected-error {{is not superset of source}}
+  void (A::*i)() throw () = &A::f;
+#if __cplusplus <= 201402L
+  // expected-error at -2 {{is not superset of source}}
+#else
+  // expected-error at -4 {{different exception specifications}}
+#endif
   void (A::*i2)() throw () = 0;
   void (A::*j)() throw (int, char) = &A::f;
   void x() {
-    g2 = f; // expected-error {{is not superset}}
+    g2 = f;
+#if __cplusplus <= 201402L
+  // expected-error at -2 {{is not superset of source}}
+#else
+  // expected-error at -4 {{different exception specifications}}
+#endif
     h = f;
-    i2 = &A::f; // expected-error {{is not superset}}
+    i2 = &A::f;
+#if __cplusplus <= 201402L
+  // expected-error at -2 {{is not superset of source}}
+#else
+  // expected-error at -4 {{different exception specifications}}
+#endif
     j = &A::f;
   }
 }
@@ -997,20 +1017,31 @@ namespace dr92 { // FIXME: Issue is stil
   void f() throw(int, float);
   void (*p)() throw(int) = &f; // expected-error {{target exception specification is not superset of source}}
   void (*q)() throw(int);
-  void (**pp)() throw() = &q; // expected-error {{exception specifications are not allowed}}
+  void (**pp)() throw() = &q;
+#if __cplusplus <= 201402L
+  // expected-error at -2 {{exception specifications are not allowed}}
+#else
+  // expected-error at -4 {{cannot initialize}}
+#endif
 
-  void g(void() throw());
-  void h() {
-    g(f); // expected-error {{is not superset}}
-    g(q); // expected-error {{is not superset}}
+  void g(void() throw()); // expected-note 0-2 {{no known conversion}}
+  void h() throw() {
+    g(f); // expected-error-re {{{{is not superset|no matching function}}}}
+    g(q); // expected-error-re {{{{is not superset|no matching function}}}}
   }
 
   // Prior to C++17, this is OK because the exception specification is not
   // considered in this context. In C++17, we *do* perform an implicit
-  // conversion (which performs initialization), but we convert to the type of
-  // the template parameter, which does not include the exception specification.
+  // conversion (which performs initialization), and the exception specification
+  // is part of the type of the parameter, so this is invalid.
   template<void() throw()> struct X {};
-  X<&f> xp; // ok
+  X<&f> xp;
+#if __cplusplus > 201402L
+  // expected-error at -2 {{not implicitly convertible}}
+#endif
+
+  template<void() throw(int)> struct Y {};
+  Y<&h> yp; // ok
 }
 
 // dr93: na

Modified: cfe/trunk/test/CXX/drs/dr1xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr1xx.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr1xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr1xx.cpp Sun Oct 16 12:54:23 2016
@@ -235,9 +235,6 @@ namespace dr125 {
     friend dr125_A (::dr125_B::dr125_C)(); // ok
     friend dr125_A::dr125_B::dr125_C(); // expected-error {{did you mean the constructor name 'dr125_B'?}}
     // expected-error at -1 {{missing exception specification}}
-#if __cplusplus >= 201103L
-    // expected-error at -3 {{follows constexpr declaration}} expected-note at -10 {{here}}
-#endif
   };
 }
 

Modified: cfe/trunk/test/CXX/drs/dr2xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr2xx.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr2xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr2xx.cpp Sun Oct 16 12:54:23 2016
@@ -984,10 +984,19 @@ namespace dr289 { // dr289: yes
 namespace dr294 { // dr294: no
   void f() throw(int);
   int main() {
-    (void)static_cast<void (*)() throw()>(f); // FIXME: ill-formed
-    (void)static_cast<void (*)() throw(int)>(f); // FIXME: ill-formed
+    (void)static_cast<void (*)() throw()>(f); // FIXME: ill-formed in C++14 and before
+#if __cplusplus > 201402L
+    // FIXME: expected-error at -2 {{not allowed}}
+    //
+    // Irony: the above is valid in C++17 and beyond, but that's exactly when
+    // we reject it. In C++14 and before, this is ill-formed because an
+    // exception-specification is not permitted in a type-id. In C++17, this is
+    // valid because it's the inverse of a standard conversion sequence
+    // containing a function pointer conversion.
+#endif
+    (void)static_cast<void (*)() throw(int)>(f); // FIXME: ill-formed in C++14 and before
 
-    void (*p)() throw() = f; // expected-error {{not superset}}
+    void (*p)() throw() = f; // expected-error-re {{{{not superset|different exception specification}}}}
     void (*q)() throw(int) = f;
   }
 }

Added: cfe/trunk/test/CXX/except/except.spec/p2-places-1z.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p2-places-1z.cpp?rev=284337&view=auto
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p2-places-1z.cpp (added)
+++ cfe/trunk/test/CXX/except/except.spec/p2-places-1z.cpp Sun Oct 16 12:54:23 2016
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++1z -fexceptions -fcxx-exceptions -fsyntax-only -verify %s
+
+// In C++1z, we can put an exception-specification on any function declarator; the
+// corresponding paragraph from C++14 and before was deleted.
+// expected-no-diagnostics
+
+void f() noexcept;
+void (*fp)() noexcept;
+void (**fpp)() noexcept;
+void g(void (**pfa)() noexcept);
+void (**h())() noexcept;
+
+template<typename T> struct A {};
+template<void() noexcept> struct B {};
+A<void() noexcept> a;
+B<f> b;
+auto *p = new decltype(f)**;

Modified: 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=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p2-places.cpp (original)
+++ cfe/trunk/test/CXX/except/except.spec/p2-places.cpp Sun Oct 16 12:54:23 2016
@@ -37,6 +37,8 @@ namespace dyn {
   // Pointer to function returning pointer to pointer to function with spec
   void (**(*h())())() throw(int); // expected-error {{not allowed beyond a single}}
 
+  // FIXME: Missing a lot of negative tests, primarily type-ids in various places
+  // We fail to diagnose all of those.
 }
 
 namespace noex {

Modified: cfe/trunk/test/CXX/expr/expr.const/p3-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p3-0x.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p3-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.const/p3-0x.cpp Sun Oct 16 12:54:23 2016
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1z -verify %s
 
 // A converted constant expression of type T is a core constant expression,
 int nonconst = 8; // expected-note 3 {{here}}
@@ -40,10 +41,10 @@ const E e10 = E10;
 template<E> struct T {};
 T<e10> s10;
 
-//  integral promotions, and
+//  integral promotions,
 enum class EE { EE32 = ' ', EE65 = 'A', EE1 = (short)1, EE5 = E5 };
 
-//  integral conversions other than narrowing conversions
+//  integral conversions other than narrowing conversions,
 int b(unsigned n) {
   switch (n) {
     case E6:
@@ -74,12 +75,22 @@ using Int = A<-3>; // expected-error {{t
 
 // Note, conversions from integral or unscoped enumeration types to bool are
 // integral conversions as well as boolean conversions.
+// FIXME: Per core issue 1407, this is not correct.
 template<typename T, T v> struct Val { static constexpr T value = v; };
 static_assert(Val<bool, E1>::value == 1, ""); // ok
 static_assert(Val<bool, '\0'>::value == 0, ""); // ok
 static_assert(Val<bool, U'\1'>::value == 1, ""); // ok
 static_assert(Val<bool, E5>::value == 1, ""); // expected-error {{5, which cannot be narrowed to type 'bool'}}
 
+//  function pointer conversions [C++17]
+void noexcept_false() noexcept(false);
+void noexcept_true() noexcept(true);
+Val<decltype(&noexcept_false), &noexcept_true> remove_noexcept;
+Val<decltype(&noexcept_true), &noexcept_false> add_noexcept;
+#if __cplusplus > 201402L
+// expected-error at -2 {{value of type 'void (*)() noexcept(false)' is not implicitly convertible to 'void (*)() noexcept'}}
+#endif
+
 // (no other conversions are permitted)
 using Int = A<1.0>; // expected-error {{conversion from 'double' to 'unsigned char' is not allowed in a converted constant expression}}
 enum B : bool {

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p6.cpp Sun Oct 16 12:54:23 2016
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++1z %s -verify
 
 void test_conversion() {
   int (*fp1)(int) = [](int x) { return x + 1; };
@@ -9,6 +10,15 @@ void test_conversion() {
 
   volatile const auto lambda2 = [](int x) { }; // expected-note{{but method is not marked volatile}}
   void (*fp4)(int) = lambda2; // expected-error{{no viable conversion}}
+
+  void (*fp5)(int) noexcept = [](int x) { };
+#if __cplusplus > 201402L
+  // expected-error at -2 {{no viable}} expected-note at -2 {{candidate}}
+  void (*fp5a)(int) noexcept = [](auto x) { };
+  // expected-error at -1 {{no viable}} expected-note at -1 {{candidate}}
+  void (*fp5b)(int) noexcept = [](auto x) noexcept { };
+#endif
+  void (*fp6)(int) noexcept = [](int x) noexcept { };
 }
 
 void test_no_conversion() { 

Added: cfe/trunk/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.scs/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.scs/p3.cpp?rev=284337&view=auto
==============================================================================
--- cfe/trunk/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.scs/p3.cpp (added)
+++ cfe/trunk/test/CXX/over/over.match/over.match.best/over.best.ics/over.ics.scs/p3.cpp Sun Oct 16 12:54:23 2016
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+void f(void() noexcept); // expected-note {{no known conversion from 'void ()' to 'void (*)() noexcept'}}
+void f(void()) = delete; // expected-note {{explicitly deleted}}
+
+void g();
+void h() noexcept;
+
+void test() {
+  f(g); // expected-error {{call to deleted}}
+  f(h);
+}

Modified: cfe/trunk/test/CXX/over/over.over/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.over/p1.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/test/CXX/over/over.over/p1.cpp (original)
+++ cfe/trunk/test/CXX/over/over.over/p1.cpp Sun Oct 16 12:54:23 2016
@@ -1,7 +1,9 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -DNOEXCEPT= %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1z -DNOEXCEPT= %s
+// FIXME: %clang_cc1 -fsyntax-only -std=c++1z -DNOEXCEPT=noexcept %s
 
-template<typename T> T f0(T);
-int f0(int);
+template<typename T> T f0(T) NOEXCEPT;
+int f0(int) NOEXCEPT;
 
 // -- an object or reference being initialized 
 struct S {

Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp Sun Oct 16 12:54:23 2016
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
 
 namespace PR8598 {
   template<class T> struct identity { typedef T type; };
@@ -19,3 +19,28 @@ namespace PR12132 {
     fun(&A::x);
   }
 }
+
+#if __cplusplus > 201402L
+namespace noexcept_conversion {
+  template<typename R> void foo(R());
+  template<typename R> void bar(R()) = delete;
+  template<typename R> void bar(R() noexcept) {}
+  void f() throw() {
+    foo(&f);
+    bar(&f);
+  }
+  // There is no corresponding rule for references.
+  // FIXME: This seems like a defect.
+  template<typename R> void baz(R(&)()); // expected-note {{does not match adjusted type}}
+  void g() {
+    baz(f); // expected-error {{no match}}
+  }
+
+  void g1() noexcept;
+  void g2();
+  template <class T> int h(T *, T *); // expected-note {{deduced conflicting types for parameter 'T' ('void () noexcept' vs. 'void ()')}}
+  int x = h(g1, g2); // expected-error {{no matching function}}
+}
+#else
+// expected-no-diagnostics
+#endif

Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p5.cpp?rev=284337&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p5.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p5.cpp Sun Oct 16 12:54:23 2016
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+template<typename T, bool B> using Fn = T () noexcept(B);
+
+// - If the original A is a function pointer type, A can be "pointer to
+//   function" even if the deduced A is "pointer to noexcept function".
+struct A {
+  template<typename T> operator Fn<T, false>*(); // expected-note {{candidate}}
+};
+struct B {
+  template<typename T> operator Fn<T, true>*();
+};
+void (*p1)() = A();
+void (*p2)() = B();
+void (*p3)() noexcept = A(); // expected-error {{no viable conversion}}
+void (*p4)() noexcept = B();
+
+// - If the original A is a pointer to member function type, A can be "pointer
+//   to member of type function" even if the deduced A is "pointer to member of
+//   type noexcept function".
+struct C {
+  template<typename T> operator Fn<T, false> A::*(); // expected-note {{candidate}}
+};
+struct D {
+  template<typename T> operator Fn<T, true> A::*();
+};
+void (A::*q1)() = C();
+void (A::*q2)() = D();
+void (A::*q3)() noexcept = C(); // expected-error {{no viable conversion}}
+void (A::*q4)() noexcept = D();
+
+// There is no corresponding rule for references.
+// FIXME: This seems like a defect.
+struct E {
+  template<typename T> operator Fn<T, false>&(); // expected-note {{candidate}}
+};
+struct F {
+  template<typename T> operator Fn<T, true>&(); // expected-note {{candidate}}
+};
+void (&r1)() = E();
+void (&r2)() = F(); // expected-error {{no viable conversion}}
+void (&r3)() noexcept = E(); // expected-error {{no viable conversion}}
+void (&r4)() noexcept = F();

Modified: cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp Sun Oct 16 12:54:23 2016
@@ -142,11 +142,11 @@ namespace PR13527 {
     Y &operator=(Y&&) = default;
     ~Y() = default;
   };
-  Y::Y() = default; // expected-error {{definition of explicitly defaulted}}
-  Y::Y(const Y&) = default; // expected-error {{definition of explicitly defaulted}}
-  Y::Y(Y&&) = default; // expected-error {{definition of explicitly defaulted}}
-  Y &Y::operator=(const Y&) = default; // expected-error {{definition of explicitly defaulted}}
-  Y &Y::operator=(Y&&) = default; // expected-error {{definition of explicitly defaulted}}
+  Y::Y() noexcept = default; // expected-error {{definition of explicitly defaulted}}
+  Y::Y(const Y&) noexcept = default; // expected-error {{definition of explicitly defaulted}}
+  Y::Y(Y&&) noexcept = default; // expected-error {{definition of explicitly defaulted}}
+  Y &Y::operator=(const Y&) noexcept = default; // expected-error {{definition of explicitly defaulted}}
+  Y &Y::operator=(Y&&) noexcept = default; // expected-error {{definition of explicitly defaulted}}
   Y::~Y() = default; // expected-error {{definition of explicitly defaulted}}
 }
 

Modified: cfe/trunk/test/SemaCXX/deprecated.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/deprecated.cpp?rev=284337&r1=284336&r2=284337&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/deprecated.cpp (original)
+++ cfe/trunk/test/SemaCXX/deprecated.cpp Sun Oct 16 12:54:23 2016
@@ -7,9 +7,9 @@
 
 #include "Inputs/register.h"
 
-void f() throw();
-void g() throw(int);
-void h() throw(...);
+void g() throw();
+void h() throw(int);
+void i() throw(...);
 #if __cplusplus >= 201103L
 // expected-warning at -4 {{dynamic exception specifications are deprecated}} expected-note at -4 {{use 'noexcept' instead}}
 // expected-warning at -4 {{dynamic exception specifications are deprecated}} expected-note at -4 {{use 'noexcept(false)' instead}}




More information about the cfe-commits mailing list