r284905 - [c++1z] P0012R1: Implement a few remaining pieces: downgrade diagnostic for

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 21 18:32:20 PDT 2016


Author: rsmith
Date: Fri Oct 21 20:32:19 2016
New Revision: 284905

URL: http://llvm.org/viewvc/llvm-project?rev=284905&view=rev
Log:
[c++1z] P0012R1: Implement a few remaining pieces: downgrade diagnostic for
mismatched dynamic exception specifications in expressions from an error to a
warning, since this is no longer ill-formed in C++1z.

Allow reference binding of a reference-to-non-noexcept function to a noexcept
function lvalue. As defect resolutions, also allow a conditional between
noexcept and non-noexcept function lvalues to produce a non-noexcept function
lvalue (rather than decaying to a function pointer), and allow function
template argument deduction to deduce a reference to non-noexcept function when
binding to a noexcept function type.

Added:
    cfe/trunk/test/CXX/expr/expr.post/expr.static.cast/p7.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/test/CXX/drs/dr0xx.cpp
    cfe/trunk/test/CXX/drs/dr13xx.cpp
    cfe/trunk/test/CXX/expr/p13.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/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p5.cpp
    cfe/trunk/www/cxx_dr_status.html
    cfe/trunk/www/make_cxx_dr_status

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Fri Oct 21 20:32:19 2016
@@ -621,6 +621,8 @@ def Format2 : DiagGroup<"format=2",
 
 def TypeSafety : DiagGroup<"type-safety">;
 
+def IncompatibleExceptionSpec : DiagGroup<"incompatible-exception-spec">;
+
 def IntToVoidPointerCast : DiagGroup<"int-to-void-pointer-cast">;
 def IntToPointerCast : DiagGroup<"int-to-pointer-cast",
                                  [IntToVoidPointerCast]>;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Oct 21 20:32:19 2016
@@ -1294,8 +1294,12 @@ def ext_override_exception_spec : ExtWar
   InGroup<MicrosoftExceptionSpec>;
 def err_incompatible_exception_specs : Error<
   "target exception specification is not superset of source">;
+def warn_incompatible_exception_specs : Warning<
+  err_incompatible_exception_specs.Text>, InGroup<IncompatibleExceptionSpec>;
 def err_deep_exception_specs_differ : Error<
   "exception specifications of %select{return|argument}0 types differ">;
+def warn_deep_exception_specs_differ : Warning<
+  err_deep_exception_specs_differ.Text>, InGroup<IncompatibleExceptionSpec>;
 def err_missing_exception_specification : Error<
   "%0 is missing exception specification '%1'">;
 def ext_missing_exception_specification : ExtWarn<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Oct 21 20:32:19 2016
@@ -1334,13 +1334,19 @@ public:
       bool *MissingEmptyExceptionSpecification = nullptr,
       bool AllowNoexceptAllMatchWithNoSpec = false,
       bool IsOperatorNew = false);
-  bool CheckExceptionSpecSubset(
-      const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
-      const FunctionProtoType *Superset, SourceLocation SuperLoc,
-      const FunctionProtoType *Subset, SourceLocation SubLoc);
-  bool CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
-      const FunctionProtoType *Target, SourceLocation TargetLoc,
-      const FunctionProtoType *Source, SourceLocation SourceLoc);
+  bool CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
+                                const PartialDiagnostic &NestedDiagID,
+                                const PartialDiagnostic &NoteID,
+                                const FunctionProtoType *Superset,
+                                SourceLocation SuperLoc,
+                                const FunctionProtoType *Subset,
+                                SourceLocation SubLoc);
+  bool CheckParamExceptionSpec(const PartialDiagnostic &NestedDiagID,
+                               const PartialDiagnostic &NoteID,
+                               const FunctionProtoType *Target,
+                               SourceLocation TargetLoc,
+                               const FunctionProtoType *Source,
+                               SourceLocation SourceLoc);
 
   TypeResult ActOnTypeName(Scope *S, Declarator &D);
 

Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Fri Oct 21 20:32:19 2016
@@ -414,7 +414,7 @@ bool Sema::CheckEquivalentExceptionSpec(
 /// a problem. If \c true is returned, either a diagnostic has already been
 /// produced or \c *MissingExceptionSpecification is set to \c true.
 bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
-                                        const PartialDiagnostic & NoteID,
+                                        const PartialDiagnostic &NoteID,
                                         const FunctionProtoType *Old,
                                         SourceLocation OldLoc,
                                         const FunctionProtoType *New,
@@ -605,10 +605,13 @@ bool Sema::CheckEquivalentExceptionSpec(
 /// CheckExceptionSpecSubset - Check whether the second function type's
 /// exception specification is a subset (or equivalent) of the first function
 /// type. This is used by override and pointer assignment checks.
-bool Sema::CheckExceptionSpecSubset(
-    const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
-    const FunctionProtoType *Superset, SourceLocation SuperLoc,
-    const FunctionProtoType *Subset, SourceLocation SubLoc) {
+bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
+                                    const PartialDiagnostic &NestedDiagID,
+                                    const PartialDiagnostic &NoteID,
+                                    const FunctionProtoType *Superset,
+                                    SourceLocation SuperLoc,
+                                    const FunctionProtoType *Subset,
+                                    SourceLocation SubLoc) {
 
   // Just auto-succeed under -fno-exceptions.
   if (!getLangOpts().CXXExceptions)
@@ -632,7 +635,8 @@ bool Sema::CheckExceptionSpecSubset(
 
   // If superset contains everything, we're done.
   if (SuperEST == EST_None || SuperEST == EST_MSAny)
-    return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+    return CheckParamExceptionSpec(NestedDiagID, 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
@@ -647,7 +651,8 @@ bool Sema::CheckExceptionSpecSubset(
 
   // Another case of the superset containing everything.
   if (SuperNR == FunctionProtoType::NR_Throw)
-    return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+    return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc,
+                                   Subset, SubLoc);
 
   ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
 
@@ -678,7 +683,8 @@ bool Sema::CheckExceptionSpecSubset(
 
   // If the subset contains nothing, we're done.
   if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow)
-    return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+    return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc,
+                                   Subset, SubLoc);
 
   // Otherwise, if the superset contains nothing, we've failed.
   if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) {
@@ -770,14 +776,15 @@ bool Sema::CheckExceptionSpecSubset(
     }
   }
   // We've run half the gauntlet.
-  return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
+  return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc,
+                                 Subset, SubLoc);
 }
 
-static bool CheckSpecForTypesEquivalent(Sema &S,
-    const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
-    QualType Target, SourceLocation TargetLoc,
-    QualType Source, SourceLocation SourceLoc)
-{
+static bool
+CheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID,
+                            const PartialDiagnostic &NoteID, QualType Target,
+                            SourceLocation TargetLoc, QualType Source,
+                            SourceLocation SourceLoc) {
   const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);
   if (!TFunc)
     return false;
@@ -794,13 +801,16 @@ static bool CheckSpecForTypesEquivalent(
 /// assignment and override compatibility check. We do not check the parameters
 /// of parameter function pointers recursively, as no sane programmer would
 /// even be able to write such a function type.
-bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID,
+bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &DiagID,
+                                   const PartialDiagnostic &NoteID,
                                    const FunctionProtoType *Target,
                                    SourceLocation TargetLoc,
                                    const FunctionProtoType *Source,
                                    SourceLocation SourceLoc) {
+  auto RetDiag = DiagID;
+  RetDiag << 0;
   if (CheckSpecForTypesEquivalent(
-          *this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(),
+          *this, RetDiag, PDiag(),
           Target->getReturnType(), TargetLoc, Source->getReturnType(),
           SourceLoc))
     return true;
@@ -810,8 +820,10 @@ bool Sema::CheckParamExceptionSpec(const
   assert(Target->getNumParams() == Source->getNumParams() &&
          "Functions have different argument counts.");
   for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) {
+    auto ParamDiag = DiagID;
+    ParamDiag << 1;
     if (CheckSpecForTypesEquivalent(
-            *this, PDiag(diag::err_deep_exception_specs_differ) << 1, PDiag(),
+            *this, ParamDiag, PDiag(),
             Target->getParamType(i), TargetLoc, Source->getParamType(i),
             SourceLoc))
       return true;
@@ -831,6 +843,16 @@ bool Sema::CheckExceptionSpecCompatibili
   if (!FromFunc || FromFunc->hasDependentExceptionSpec())
     return false;
 
+  unsigned DiagID = diag::err_incompatible_exception_specs;
+  unsigned NestedDiagID = diag::err_deep_exception_specs_differ;
+  // This is not an error in C++17 onwards, unless the noexceptness doesn't
+  // match, but in that case we have a full-on type mismatch, not just a
+  // type sugar mismatch.
+  if (getLangOpts().CPlusPlus1z) {
+    DiagID = diag::warn_incompatible_exception_specs;
+    NestedDiagID = diag::warn_deep_exception_specs_differ;
+  }
+
   // 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
@@ -843,10 +865,10 @@ bool Sema::CheckExceptionSpecCompatibili
   //     void (*q)(void (*) throw(int)) = p;
   //   }
   // ... because it might be instantiated with T=int.
-  return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs),
-                                  PDiag(), ToFunc, 
-                                  From->getSourceRange().getBegin(),
-                                  FromFunc, SourceLocation());
+  return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(NestedDiagID), PDiag(),
+                                  ToFunc, From->getSourceRange().getBegin(),
+                                  FromFunc, SourceLocation()) &&
+         !getLangOpts().CPlusPlus1z;
 }
 
 bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
@@ -880,6 +902,7 @@ bool Sema::CheckOverridingFunctionExcept
   if (getLangOpts().MicrosoftExt)
     DiagID = diag::ext_override_exception_spec;
   return CheckExceptionSpecSubset(PDiag(DiagID),
+                                  PDiag(diag::err_deep_exception_specs_differ),
                                   PDiag(diag::note_overridden_virtual_function),
                                   Old->getType()->getAs<FunctionProtoType>(),
                                   Old->getLocation(),
@@ -902,8 +925,13 @@ static CanThrowResult canCalleeThrow(Sem
 
   // See if we can get a function type from the decl somehow.
   const ValueDecl *VD = dyn_cast<ValueDecl>(D);
-  if (!VD) // If we have no clue what we're calling, assume the worst.
+  if (!VD) {
+    // In C++17, we may have a canonical exception specification. If so, use it.
+    if (auto *FT = E->getType().getCanonicalType()->getAs<FunctionProtoType>())
+      return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;
+    // If we have no clue what we're calling, assume the worst.
     return CT_Can;
+  }
 
   // As an extension, we assume that __attribute__((nothrow)) functions don't
   // throw.

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Oct 21 20:32:19 2016
@@ -5370,23 +5370,29 @@ QualType Sema::CXXCheckConditionalOperan
   //   if both are glvalues of the same value category and the same type except
   //   for cv-qualification, an attempt is made to convert each of those
   //   operands to the type of the other.
+  // FIXME:
+  //   Resolving a defect in P0012R1: we extend this to cover all cases where
+  //   one of the operands is reference-compatible with the other, in order
+  //   to support conditionals between functions differing in noexcept.
   ExprValueKind LVK = LHS.get()->getValueKind();
   ExprValueKind RVK = RHS.get()->getValueKind();
   if (!Context.hasSameType(LTy, RTy) &&
-      Context.hasSameUnqualifiedType(LTy, RTy) &&
       LVK == RVK && LVK != VK_RValue) {
-    // Since the unqualified types are reference-related and we require the
-    // result to be as if a reference bound directly, the only conversion
-    // we can perform is to add cv-qualifiers.
-    Qualifiers LCVR = Qualifiers::fromCVRMask(LTy.getCVRQualifiers());
-    Qualifiers RCVR = Qualifiers::fromCVRMask(RTy.getCVRQualifiers());
-    if (RCVR.isStrictSupersetOf(LCVR)) {
-      LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK);
-      LTy = LHS.get()->getType();
-    }
-    else if (LCVR.isStrictSupersetOf(RCVR)) {
+    // DerivedToBase was already handled by the class-specific case above.
+    // FIXME: Should we allow ObjC conversions here?
+    bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion;
+    if (CompareReferenceRelationship(
+            QuestionLoc, LTy, RTy, DerivedToBase,
+            ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
+        !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion) {
       RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
       RTy = RHS.get()->getType();
+    } else if (CompareReferenceRelationship(
+                   QuestionLoc, RTy, LTy, DerivedToBase,
+                   ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
+               !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion) {
+      LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK);
+      LTy = LHS.get()->getType();
     }
   }
 

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Oct 21 20:32:19 2016
@@ -4172,6 +4172,7 @@ Sema::CompareReferenceRelationship(Sourc
   DerivedToBase = false;
   ObjCConversion = false;
   ObjCLifetimeConversion = false;
+  QualType ConvertedT2;
   if (UnqualT1 == UnqualT2) {
     // Nothing to do.
   } else if (isCompleteType(Loc, OrigT2) &&
@@ -4182,6 +4183,15 @@ Sema::CompareReferenceRelationship(Sourc
            UnqualT2->isObjCObjectOrInterfaceType() &&
            Context.canBindObjCObjectType(UnqualT1, UnqualT2))
     ObjCConversion = true;
+  else if (UnqualT2->isFunctionType() &&
+           IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2))
+    // C++1z [dcl.init.ref]p4:
+    //   cv1 T1" is reference-compatible with "cv2 T2" if [...] T2 is "noexcept
+    //   function" and T1 is "function"
+    //
+    // We extend this to also apply to 'noreturn', so allow any function
+    // conversion between function types.
+    return Ref_Compatible;
   else
     return Ref_Incompatible;
 

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Fri Oct 21 20:32:19 2016
@@ -2729,6 +2729,13 @@ CheckOriginalCallArgDeduction(Sema &S, S
     // We don't want to keep the reference around any more.
     OriginalParamType = OriginalParamRef->getPointeeType();
 
+    // FIXME: Resolve core issue (no number yet): if the original P is a
+    // reference type and the transformed A is function type "noexcept F",
+    // the deduced A can be F.
+    QualType Tmp;
+    if (A->isFunctionType() && S.IsFunctionConversion(A, DeducedA, Tmp))
+      return false;
+
     Qualifiers AQuals = A.getQualifiers();
     Qualifiers DeducedAQuals = DeducedA.getQualifiers();
 
@@ -2760,8 +2767,8 @@ CheckOriginalCallArgDeduction(Sema &S, S
   //      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.
+  // Also allow conversions which merely strip __attribute__((noreturn)) from
+  // function types (recursively).
   bool ObjCLifetimeConversion = false;
   QualType ResultTy;
   if ((A->isAnyPointerType() || A->isMemberPointerType()) &&
@@ -2770,7 +2777,6 @@ CheckOriginalCallArgDeduction(Sema &S, S
        S.IsFunctionConversion(A, DeducedA, ResultTy)))
     return false;
 
-
   //    - If P is a class and P has the form simple-template-id, then the
   //      transformed A can be a derived class of the deduced A. [...]
   //     [...] Likewise, if P is a pointer to a class of the form

Modified: cfe/trunk/test/CXX/drs/dr0xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr0xx.cpp?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr0xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr0xx.cpp Fri Oct 21 20:32:19 2016
@@ -961,10 +961,11 @@ namespace dr85 { // dr85: yes
 // dr86: dup 446
 
 namespace dr87 { // dr87: no
+  // FIXME: Superseded by dr1975
   template<typename T> struct X {};
   // FIXME: This is invalid.
   X<void() throw()> x;
-  // ... but this is valid.
+  // This is valid under dr87 but not under dr1975.
   X<void(void() throw())> y;
 }
 
@@ -1013,9 +1014,14 @@ namespace dr91 { // dr91: yes
   int k = f(U());
 }
 
-namespace dr92 { // FIXME: Issue is still open.
+namespace dr92 { // dr92: 4.0 c++17
   void f() throw(int, float);
-  void (*p)() throw(int) = &f; // expected-error {{target exception specification is not superset of source}}
+  void (*p)() throw(int) = &f;
+#if __cplusplus <= 201402L
+  // expected-error at -2 {{target exception specification is not superset of source}}
+#else
+  // expected-warning at -4 {{target exception specification is not superset of source}}
+#endif
   void (*q)() throw(int);
   void (**pp)() throw() = &q;
 #if __cplusplus <= 201402L

Modified: cfe/trunk/test/CXX/drs/dr13xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr13xx.cpp?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr13xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr13xx.cpp Fri Oct 21 20:32:19 2016
@@ -54,8 +54,19 @@ namespace dr1330 { // dr1330: 4.0 c++11
   // the "T has not yet been instantiated" error here, rather than giving
   // confusing errors later on.
 #endif
-  void (B<P>::*bpf2)() throw(int) = &B<P>::f; // expected-error-re {{{{not superset|different exception spec}}}}
+  void (B<P>::*bpf2)() throw(int) = &B<P>::f;
+#if __cplusplus <= 201402L
+  // expected-error at -2 {{not superset}}
+#else
+  // expected-warning at -4 {{not superset}}
+#endif
   void (B<P>::*bpf3)() = &B<P>::f;
+  void (B<P>::*bpf4)() throw() = &B<P>::f;
+#if __cplusplus <= 201402L
+  // expected-error at -2 {{not superset}}
+#else
+  // expected-error at -4 {{different exception specifications}}
+#endif
 
 #if __cplusplus >= 201103L
   static_assert(noexcept(B<P>().g()), "");

Added: cfe/trunk/test/CXX/expr/expr.post/expr.static.cast/p7.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.post/expr.static.cast/p7.cpp?rev=284905&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.post/expr.static.cast/p7.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.post/expr.static.cast/p7.cpp Fri Oct 21 20:32:19 2016
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s -fcxx-exceptions
+
+void (*p)() noexcept;
+void (*q)();
+
+void f() {
+  // FIXME: This seems like a bad rule.
+  p = static_cast<decltype(p)>(q); // expected-error {{not allowed}}
+  q = static_cast<decltype(q)>(p);
+}

Modified: cfe/trunk/test/CXX/expr/p13.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/p13.cpp?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/p13.cpp (original)
+++ cfe/trunk/test/CXX/expr/p13.cpp Fri Oct 21 20:32:19 2016
@@ -40,12 +40,12 @@ namespace dynamic_exception_spec {
   using Y = void (*)() throw(float);
   using Z = void (*)() throw(int, float);
   void g(X x, Y y, Z z, bool k) {
-    x = k ? X() : Y(); // expected-error {{not superset}}
-    y = k ? X() : Y(); // expected-error {{not superset}}
+    x = k ? X() : Y(); // expected-warning {{not superset}}
+    y = k ? X() : Y(); // expected-warning {{not superset}}
     z = k ? X() : Y();
 
-    x = k ? x : y; // expected-error {{not superset}}
-    y = k ? x : y; // expected-error {{not superset}}
+    x = k ? x : y; // expected-warning {{not superset}}
+    y = k ? x : y; // expected-warning {{not superset}}
     z = k ? x : y;
   }
 }

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=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/test/CXX/over/over.over/p1.cpp (original)
+++ cfe/trunk/test/CXX/over/over.over/p1.cpp Fri Oct 21 20:32:19 2016
@@ -1,6 +1,6 @@
-// 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
+// RUN: %clang_cc1 -fsyntax-only -DNOEXCEPT= -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1z -DNOEXCEPT= -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++1z -DNOEXCEPT=noexcept -verify %s
 
 template<typename T> T f0(T) NOEXCEPT;
 int f0(int) NOEXCEPT;
@@ -94,3 +94,18 @@ Y1<f0> y1;
 Y1<&f0> y1a;
 Y2<f0> y2;
 Y3<f0> y3;
+
+#if __cplusplus > 201402L
+namespace MixedNoexcept {
+  inline namespace A {
+    void f() noexcept; // expected-note {{candidate}}
+  }
+  inline namespace B {
+    void f(); // expected-note {{candidate}}
+  }
+  void (*p)() noexcept = &f; // ok
+  void (*q)() = &f; // expected-error {{ambiguous}}
+}
+#else
+// expected-no-diagnostics
+#endif

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=284905&r1=284904&r2=284905&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 Fri Oct 21 20:32:19 2016
@@ -30,16 +30,26 @@ namespace noexcept_conversion {
     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}}
+  // We consider this to be a defect, and allow deduction to succeed in this
+  // case. FIXME: Check this should be accepted once the DR is resolved.
+  template<typename R> void baz(R(&)());
   void g() {
-    baz(f); // expected-error {{no match}}
+    baz(f);
   }
 
+  // But there is one for member pointers.
+  template<typename R, typename C, typename ...A> void quux(R (C::*)(A...));
+  struct Q { void f(int, char) noexcept { quux(&Q::f); } };
+
   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}}
+
+  // FIXME: It seems like a defect that B is not deducible here.
+  template<bool B> int i(void () noexcept(B)); // expected-note 2{{couldn't infer template argument 'B'}}
+  int i1 = i(g1); // expected-error {{no matching function}}
+  int i2 = i(g2); // expected-error {{no matching function}}
 }
 #else
 // expected-no-diagnostics

Modified: 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=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p5.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p5.cpp Fri Oct 21 20:32:19 2016
@@ -31,13 +31,31 @@ void (A::*q4)() noexcept = D();
 
 // There is no corresponding rule for references.
 // FIXME: This seems like a defect.
+// FIXME: We don't actually implement the final check for equal types at all!
+// Instead, we handle the matching via [over.ics.user]p3:
+//   "If the user-defined conversion is specified by a specialization of a
+//   conversion function template, the second standard conversion sequence
+//   shall have exact match rank."
+// Note that this *does* allow discarding noexcept, since that conversion has
+// Exact Match rank.
 struct E {
   template<typename T> operator Fn<T, false>&(); // expected-note {{candidate}}
 };
 struct F {
-  template<typename T> operator Fn<T, true>&(); // expected-note {{candidate}}
+  template<typename T> operator Fn<T, true>&();
 };
 void (&r1)() = E();
-void (&r2)() = F(); // expected-error {{no viable conversion}}
+void (&r2)() = F();
 void (&r3)() noexcept = E(); // expected-error {{no viable conversion}}
 void (&r4)() noexcept = F();
+
+// FIXME: We reject this for entirely the wrong reason. We incorrectly succeed
+// in deducing T = void, U = G::B, and only fail due to [over.ics.user]p3.
+struct G {
+  template<typename, typename> struct A {};
+  template<typename U> struct A<U, int> : A<U, void> {};
+  struct B { typedef int type; };
+
+  template<typename T, typename U = B> operator A<T, typename U::type> *(); // expected-note {{candidate function [with T = void, U = G::B]}}
+};
+G::A<void, void> *g = G(); // expected-error {{no viable conversion}}

Modified: cfe/trunk/www/cxx_dr_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/www/cxx_dr_status.html (original)
+++ cfe/trunk/www/cxx_dr_status.html Fri Oct 21 20:32:19 2016
@@ -591,7 +591,7 @@
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#92">92</a></td>
     <td>accepted</td>
     <td>Should <I>exception-specification</I>s be part of the type system?</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="svn" align="center">SVN (C++17 onwards)</td>
   </tr>
   <tr id="93">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#93">93</a></td>

Modified: cfe/trunk/www/make_cxx_dr_status
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/make_cxx_dr_status?rev=284905&r1=284904&r2=284905&view=diff
==============================================================================
--- cfe/trunk/www/make_cxx_dr_status (original)
+++ cfe/trunk/www/make_cxx_dr_status Fri Oct 21 20:32:19 2016
@@ -99,6 +99,12 @@ def availability(issue):
   if status.endswith(' c++11'):
     status = status[:-6]
     avail_suffix = ' (C++11 onwards)'
+  elif status.endswith(' c++14'):
+    status = status[:-6]
+    avail_suffix = ' (C++14 onwards)'
+  elif status.endswith(' c++17'):
+    status = status[:-6]
+    avail_suffix = ' (C++17 onwards)'
   if status == 'unknown':
     avail = 'Unknown'
     avail_style = ' class="none"'
@@ -161,7 +167,7 @@ for dr in drs:
     <td%s align="center">%s</td>
   </tr>''' % (row_style, dr.issue, dr.url, dr.issue, dr.status, dr.title, avail_style, avail)
 
-for status, num in count.items():
+for status, num in sorted(count.items()):
   print "%s: %s" % (status, num)
 
 print >> out_file, '''\




More information about the cfe-commits mailing list