r284800 - DR583, DR1512: Implement a rewrite to C++'s 'composite pointer type' rules.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 20 19:36:38 PDT 2016


Author: rsmith
Date: Thu Oct 20 21:36:37 2016
New Revision: 284800

URL: http://llvm.org/viewvc/llvm-project?rev=284800&view=rev
Log:
DR583, DR1512: Implement a rewrite to C++'s 'composite pointer type' rules.
This has two significant effects:

1) Direct relational comparisons between null pointer constants (0 and nullopt)
   and pointers are now ill-formed. This was always the case for C, and it
   appears that C++ only ever permitted by accident. For instance, cases like
     nullptr < &a
   are now rejected.

2) Comparisons and conditional operators between differently-cv-qualified
   pointer types now work, and produce a composite type that both source
   pointer types can convert to (when possible). For instance, comparison
   between 'int **' and 'const int **' is now valid, and uses an intermediate
   type of 'const int *const *'.

Clang previously supported #2 as an extension.

We do not accept the cases in #1 as an extension. I've tested a fair amount of
code to check that this doesn't break it, but if it turns out that someone is
relying on this, we can easily add it back as an extension.

Added:
    cfe/trunk/test/CXX/over/over.built/p15.cpp
    cfe/trunk/test/CXX/over/over.built/p16.cpp
    cfe/trunk/test/SemaCXX/libstdcxx_libcxx_less_hack.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/CXX/drs/dr15xx.cpp
    cfe/trunk/test/CXX/drs/dr5xx.cpp
    cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
    cfe/trunk/test/Misc/warning-flags.c
    cfe/trunk/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp
    cfe/trunk/test/OpenMP/distribute_simd_aligned_messages.cpp
    cfe/trunk/test/OpenMP/for_simd_aligned_messages.cpp
    cfe/trunk/test/OpenMP/parallel_for_simd_aligned_messages.cpp
    cfe/trunk/test/OpenMP/simd_aligned_messages.cpp
    cfe/trunk/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp
    cfe/trunk/test/OpenMP/target_simd_aligned_messages.cpp
    cfe/trunk/test/OpenMP/taskloop_simd_aligned_messages.cpp
    cfe/trunk/test/SemaCXX/compare.cpp
    cfe/trunk/test/SemaCXX/composite-pointer-type.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
    cfe/trunk/test/SemaCXX/null_in_arithmetic_ops.cpp
    cfe/trunk/test/SemaCXX/nullptr.cpp
    cfe/trunk/test/SemaCXX/nullptr_in_arithmetic_ops.cpp
    cfe/trunk/test/SemaCXX/warn-memsize-comparison.cpp
    cfe/trunk/test/SemaObjCXX/null_objc_pointer.mm
    cfe/trunk/www/cxx_dr_status.html

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Oct 20 21:36:37 2016
@@ -5536,6 +5536,8 @@ def ext_typecheck_ordered_comparison_of_
   "ordered comparison between pointer and integer (%0 and %1)">;
 def ext_typecheck_ordered_comparison_of_pointer_and_zero : Extension<
   "ordered comparison between pointer and zero (%0 and %1) is an extension">;
+def err_typecheck_ordered_comparison_of_pointer_and_zero : Error<
+  "ordered comparison between pointer and zero (%0 and %1)">;
 def ext_typecheck_ordered_comparison_of_function_pointers : ExtWarn<
   "ordered comparison of function pointers (%0 and %1)">;
 def ext_typecheck_comparison_of_fptr_to_void : Extension<
@@ -5556,9 +5558,6 @@ def err_cond_voidptr_arc : Error <
   "in ARC mode">;
 def err_typecheck_comparison_of_distinct_pointers : Error<
   "comparison of distinct pointer types%diff{ ($ and $)|}0,1">;
-def ext_typecheck_comparison_of_distinct_pointers_nonstandard : ExtWarn<
-  "comparison of distinct pointer types (%0 and %1) uses non-standard "
-  "composite pointer type %2">, InGroup<CompareDistinctPointerType>;
 def err_typecheck_op_on_nonoverlapping_address_space_pointers : Error<
   "%select{comparison between %diff{ ($ and $)|}0,1"
   "|arithmetic operation with operands of type %diff{ ($ and $)|}0,1"
@@ -6837,9 +6836,6 @@ def err_typecheck_expect_scalar_operand
   "operand of type %0 where arithmetic or pointer type is required">;
 def err_typecheck_cond_incompatible_operands : Error<
   "incompatible operand types%diff{ ($ and $)|}0,1">;
-def ext_typecheck_cond_incompatible_operands_nonstandard : ExtWarn<
-  "incompatible operand types%diff{ ($ and $)|}0,1 use non-standard composite "
-  "pointer type %2">;
 def err_cast_selector_expr : Error<
   "cannot type cast @selector expression">;
 def ext_typecheck_cond_incompatible_pointers : ExtWarn<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Oct 20 21:36:37 2016
@@ -8954,15 +8954,13 @@ public:
     ExprResult &cond, ExprResult &lhs, ExprResult &rhs,
     ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc);
   QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2,
-                                    bool *NonStandardCompositeType = nullptr,
                                     bool ConvertArgs = true);
   QualType FindCompositePointerType(SourceLocation Loc,
                                     ExprResult &E1, ExprResult &E2,
-                                    bool *NonStandardCompositeType = nullptr,
                                     bool ConvertArgs = true) {
     Expr *E1Tmp = E1.get(), *E2Tmp = E2.get();
-    QualType Composite = FindCompositePointerType(
-        Loc, E1Tmp, E2Tmp, NonStandardCompositeType, ConvertArgs);
+    QualType Composite =
+        FindCompositePointerType(Loc, E1Tmp, E2Tmp, ConvertArgs);
     E1 = E1Tmp;
     E2 = E2Tmp;
     return Composite;

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Oct 20 21:36:37 2016
@@ -8929,35 +8929,21 @@ static bool convertPointersToCompositeTy
   // C++ [expr.eq]p1 uses the same notion for (in)equality
   // comparisons of pointers.
 
-  // C++ [expr.eq]p2:
-  //   In addition, pointers to members can be compared, or a pointer to
-  //   member and a null pointer constant. Pointer to member conversions
-  //   (4.11) and qualification conversions (4.4) are performed to bring
-  //   them to a common type. If one operand is a null pointer constant,
-  //   the common type is the type of the other operand. Otherwise, the
-  //   common type is a pointer to member type similar (4.4) to the type
-  //   of one of the operands, with a cv-qualification signature (4.4)
-  //   that is the union of the cv-qualification signatures of the operand
-  //   types.
-
   QualType LHSType = LHS.get()->getType();
   QualType RHSType = RHS.get()->getType();
-  assert((LHSType->isPointerType() && RHSType->isPointerType()) ||
-         (LHSType->isMemberPointerType() && RHSType->isMemberPointerType()));
+  assert(LHSType->isPointerType() || RHSType->isPointerType() ||
+         LHSType->isMemberPointerType() || RHSType->isMemberPointerType());
 
-  bool NonStandardCompositeType = false;
-  bool *BoolPtr = S.isSFINAEContext() ? nullptr : &NonStandardCompositeType;
-  QualType T = S.FindCompositePointerType(Loc, LHS, RHS, BoolPtr);
+  QualType T = S.FindCompositePointerType(Loc, LHS, RHS);
   if (T.isNull()) {
-    diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true);
+    if ((LHSType->isPointerType() || LHSType->isMemberPointerType()) &&
+        (RHSType->isPointerType() || RHSType->isMemberPointerType()))
+      diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true);
+    else
+      S.InvalidOperands(Loc, LHS, RHS);
     return true;
   }
 
-  if (NonStandardCompositeType)
-    S.Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
-      << LHSType << RHSType << T << LHS.get()->getSourceRange()
-      << RHS.get()->getSourceRange();
-
   LHS = S.ImpCastExprToType(LHS.get(), T, CK_BitCast);
   RHS = S.ImpCastExprToType(RHS.get(), T, CK_BitCast);
   return false;
@@ -9314,41 +9300,53 @@ QualType Sema::CheckCompareOperands(Expr
                                    LHS.get()->getSourceRange());
   }
 
-  // All of the following pointer-related warnings are GCC extensions, except
-  // when handling null pointer constants. 
-  if (LHSType->isPointerType() && RHSType->isPointerType()) { // C99 6.5.8p2
-    QualType LCanPointeeTy =
-      LHSType->castAs<PointerType>()->getPointeeType().getCanonicalType();
-    QualType RCanPointeeTy =
-      RHSType->castAs<PointerType>()->getPointeeType().getCanonicalType();
-
-    if (getLangOpts().CPlusPlus) {
-      if (LCanPointeeTy == RCanPointeeTy)
-        return ResultTy;
-      if (!IsRelational &&
-          (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
-        // Valid unless comparison between non-null pointer and function pointer
-        // This is a gcc extension compatibility comparison.
-        // In a SFINAE context, we treat this as a hard error to maintain
-        // conformance with the C++ standard.
-        if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
-            && !LHSIsNull && !RHSIsNull) {
-          diagnoseFunctionPointerToVoidComparison(
-              *this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext());
-          
-          if (isSFINAEContext())
-            return QualType();
-          
-          RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast);
-          return ResultTy;
-        }
-      }
+  if ((LHSType->isIntegerType() && !LHSIsNull) ||
+      (RHSType->isIntegerType() && !RHSIsNull)) {
+    // Skip normal pointer conversion checks in this case; we have better
+    // diagnostics for this below.
+  } else if (getLangOpts().CPlusPlus) {
+    // Equality comparison of a function pointer to a void pointer is invalid,
+    // but we allow it as an extension.
+    // FIXME: If we really want to allow this, should it be part of composite
+    // pointer type computation so it works in conditionals too?
+    if (!IsRelational &&
+        ((LHSType->isFunctionPointerType() && RHSType->isVoidPointerType()) ||
+         (RHSType->isFunctionPointerType() && LHSType->isVoidPointerType()))) {
+      // This is a gcc extension compatibility comparison.
+      // In a SFINAE context, we treat this as a hard error to maintain
+      // conformance with the C++ standard.
+      diagnoseFunctionPointerToVoidComparison(
+          *this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext());
+      
+      if (isSFINAEContext())
+        return QualType();
+      
+      RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast);
+      return ResultTy;
+    }
 
+    // C++ [expr.eq]p2:
+    //   If at least one operand is a pointer [...] bring them to their
+    //   composite pointer type.
+    // C++ [expr.rel]p2:
+    //   If both operands are pointers, [...] bring them to their composite
+    //   pointer type.
+    if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >=
+        (IsRelational ? 2 : 1)) {
       if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
         return QualType();
       else
         return ResultTy;
     }
+  } else if (LHSType->isPointerType() &&
+             RHSType->isPointerType()) { // C99 6.5.8p2
+    // All of the following pointer-related warnings are GCC extensions, except
+    // when handling null pointer constants.
+    QualType LCanPointeeTy =
+      LHSType->castAs<PointerType>()->getPointeeType().getCanonicalType();
+    QualType RCanPointeeTy =
+      RHSType->castAs<PointerType>()->getPointeeType().getCanonicalType();
+
     // C99 6.5.9p2 and C99 6.5.8p2
     if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
                                    RCanPointeeTy.getUnqualifiedType())) {
@@ -9393,36 +9391,63 @@ QualType Sema::CheckCompareOperands(Expr
   }
 
   if (getLangOpts().CPlusPlus) {
-    // Comparison of nullptr_t with itself.
-    if (LHSType->isNullPtrType() && RHSType->isNullPtrType())
-      return ResultTy;
-    
-    // Comparison of pointers with null pointer constants and equality
-    // comparisons of member pointers to null pointer constants.
-    if (RHSIsNull &&
-        ((LHSType->isAnyPointerType() || LHSType->isNullPtrType()) ||
-         (!IsRelational && 
-          (LHSType->isMemberPointerType() || LHSType->isBlockPointerType())))) {
-      RHS = ImpCastExprToType(RHS.get(), LHSType, 
-                        LHSType->isMemberPointerType()
-                          ? CK_NullToMemberPointer
-                          : CK_NullToPointer);
+    // C++ [expr.eq]p4:
+    //   Two operands of type std::nullptr_t or one operand of type
+    //   std::nullptr_t and the other a null pointer constant compare equal.
+    if (!IsRelational && LHSIsNull && RHSIsNull) {
+      if (LHSType->isNullPtrType()) {
+        RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
+        return ResultTy;
+      }
+      if (RHSType->isNullPtrType()) {
+        LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
+        return ResultTy;
+      }
+    }
+
+    // Comparison of Objective-C pointers and block pointers against nullptr_t.
+    // These aren't covered by the composite pointer type rules.
+    if (!IsRelational && RHSType->isNullPtrType() &&
+        (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) {
+      RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
       return ResultTy;
     }
-    if (LHSIsNull &&
-        ((RHSType->isAnyPointerType() || RHSType->isNullPtrType()) ||
-         (!IsRelational && 
-          (RHSType->isMemberPointerType() || RHSType->isBlockPointerType())))) {
-      LHS = ImpCastExprToType(LHS.get(), RHSType, 
-                        RHSType->isMemberPointerType()
-                          ? CK_NullToMemberPointer
-                          : CK_NullToPointer);
+    if (!IsRelational && LHSType->isNullPtrType() &&
+        (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) {
+      LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
       return ResultTy;
     }
 
-    // Comparison of member pointers.
+    if (IsRelational &&
+        ((LHSType->isNullPtrType() && RHSType->isPointerType()) ||
+         (RHSType->isNullPtrType() && LHSType->isPointerType()))) {
+      // HACK: Relational comparison of nullptr_t against a pointer type is
+      // invalid per DR583, but we allow it within std::less<> and friends,
+      // since otherwise common uses of it break.
+      // FIXME: Consider removing this hack once LWG fixes std::less<> and
+      // friends to have std::nullptr_t overload candidates.
+      DeclContext *DC = CurContext;
+      if (isa<FunctionDecl>(DC))
+        DC = DC->getParent();
+      if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
+        if (CTSD->isInStdNamespace() &&
+            llvm::StringSwitch<bool>(CTSD->getName())
+                .Cases("less", "less_equal", "greater", "greater_equal", true)
+                .Default(false)) {
+          if (RHSType->isNullPtrType())
+            RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
+          else
+            LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
+          return ResultTy;
+        }
+      }
+    }
+
+    // C++ [expr.eq]p2:
+    //   If at least one operand is a pointer to member, [...] bring them to
+    //   their composite pointer type.
     if (!IsRelational &&
-        LHSType->isMemberPointerType() && RHSType->isMemberPointerType()) {
+        (LHSType->isMemberPointerType() || RHSType->isMemberPointerType())) {
       if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
         return QualType();
       else
@@ -9531,15 +9556,19 @@ QualType Sema::CheckCompareOperands(Expr
       // Under a debugger, allow the comparison of pointers to integers,
       // since users tend to want to compare addresses.
     } else if ((LHSIsNull && LHSType->isIntegerType()) ||
-        (RHSIsNull && RHSType->isIntegerType())) {
-      if (IsRelational && !getLangOpts().CPlusPlus)
-        DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
-    } else if (IsRelational && !getLangOpts().CPlusPlus)
-      DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
-    else if (getLangOpts().CPlusPlus) {
+               (RHSIsNull && RHSType->isIntegerType())) {
+      if (IsRelational) {
+        isError = getLangOpts().CPlusPlus;
+        DiagID =
+          isError ? diag::err_typecheck_ordered_comparison_of_pointer_and_zero
+                  : diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
+      }
+    } else if (getLangOpts().CPlusPlus) {
       DiagID = diag::err_typecheck_comparison_of_pointer_integer;
       isError = true;
-    } else
+    } else if (IsRelational)
+      DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
+    else
       DiagID = diag::ext_typecheck_comparison_of_pointer_integer;
 
     if (DiagID) {

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Oct 20 21:36:37 2016
@@ -5399,7 +5399,7 @@ QualType Sema::CXXCheckConditionalOperan
     // exception specifications, if any.
     if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) {
       Qualifiers Qs = LTy.getQualifiers();
-      LTy = FindCompositePointerType(QuestionLoc, LHS, RHS, nullptr,
+      LTy = FindCompositePointerType(QuestionLoc, LHS, RHS,
                                      /*ConvertArgs*/false);
       LTy = Context.getQualifiedType(LTy, Qs);
 
@@ -5511,19 +5511,9 @@ QualType Sema::CXXCheckConditionalOperan
   //      performed to bring them to a common type, whose cv-qualification
   //      shall match the cv-qualification of either the second or the third
   //      operand. The result is of the common type.
-  bool NonStandardCompositeType = false;
-  QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS,
-                                 isSFINAEContext() ? nullptr
-                                                   : &NonStandardCompositeType);
-  if (!Composite.isNull()) {
-    if (NonStandardCompositeType)
-      Diag(QuestionLoc,
-           diag::ext_typecheck_cond_incompatible_operands_nonstandard)
-        << LTy << RTy << Composite
-        << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
-
+  QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS);
+  if (!Composite.isNull())
     return Composite;
-  }
 
   // Similarly, attempt to find composite type of two objective-c pointers.
   Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc);
@@ -5622,19 +5612,10 @@ mergeExceptionSpecs(Sema &S, FunctionPro
 /// \param Loc The location of the operator requiring these two expressions to
 /// be converted to the composite pointer type.
 ///
-/// If \p NonStandardCompositeType is non-NULL, then we are permitted to find
-/// a non-standard (but still sane) composite type to which both expressions
-/// can be converted. When such a type is chosen, \c *NonStandardCompositeType
-/// will be set true.
-///
 /// \param ConvertArgs If \c false, do not convert E1 and E2 to the target type.
 QualType Sema::FindCompositePointerType(SourceLocation Loc,
                                         Expr *&E1, Expr *&E2,
-                                        bool *NonStandardCompositeType,
                                         bool ConvertArgs) {
-  if (NonStandardCompositeType)
-    *NonStandardCompositeType = false;
-
   assert(getLangOpts().CPlusPlus && "This function assumes C++");
 
   // C++1z [expr]p14:
@@ -5727,8 +5708,7 @@ QualType Sema::FindCompositePointerType(
 
       // If we're allowed to create a non-standard composite type, keep track
       // of where we need to fill in additional 'const' qualifiers.
-      if (NonStandardCompositeType &&
-          Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
+      if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
         NeedConstBefore = QualifierUnion.size();
 
       QualifierUnion.push_back(
@@ -5745,8 +5725,7 @@ QualType Sema::FindCompositePointerType(
 
       // If we're allowed to create a non-standard composite type, keep track
       // of where we need to fill in additional 'const' qualifiers.
-      if (NonStandardCompositeType &&
-          Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
+      if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
         NeedConstBefore = QualifierUnion.size();
 
       QualifierUnion.push_back(
@@ -5797,16 +5776,13 @@ QualType Sema::FindCompositePointerType(
     }
   }
 
-  if (NeedConstBefore && NonStandardCompositeType) {
+  if (NeedConstBefore) {
     // Extension: Add 'const' to qualifiers that come before the first qualifier
     // mismatch, so that our (non-standard!) composite type meets the
     // requirements of C++ [conv.qual]p4 bullet 3.
-    for (unsigned I = 0; I != NeedConstBefore; ++I) {
-      if ((QualifierUnion[I] & Qualifiers::Const) == 0) {
+    for (unsigned I = 0; I != NeedConstBefore; ++I)
+      if ((QualifierUnion[I] & Qualifiers::Const) == 0)
         QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const;
-        *NonStandardCompositeType = true;
-      }
-    }
   }
 
   // Rewrap the composites as pointers or member pointers with the union CVRs.

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Oct 20 21:36:37 2016
@@ -7624,12 +7624,12 @@ public:
   }
 
   // C++ [over.match.oper]p16:
-  //   For every pointer to member type T, there exist candidate operator
-  //   functions of the form
+  //   For every pointer to member type T or type std::nullptr_t, there
+  //   exist candidate operator functions of the form
   //
   //        bool operator==(T,T);
   //        bool operator!=(T,T);
-  void addEqualEqualOrNotEqualMemberPointerOverloads() {
+  void addEqualEqualOrNotEqualMemberPointerOrNullptrOverloads() {
     /// Set of (canonical) types that we've already handled.
     llvm::SmallPtrSet<QualType, 8> AddedTypes;
 
@@ -7646,13 +7646,22 @@ public:
         QualType ParamTypes[2] = { *MemPtr, *MemPtr };
         S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet);
       }
+
+      if (CandidateTypes[ArgIdx].hasNullPtrType()) {
+        CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy);
+        if (AddedTypes.insert(NullPtrTy).second) {
+          QualType ParamTypes[2] = { NullPtrTy, NullPtrTy };
+          S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args,
+                                CandidateSet);
+        }
+      }
     }
   }
 
   // C++ [over.built]p15:
   //
-  //   For every T, where T is an enumeration type, a pointer type, or 
-  //   std::nullptr_t, there exist candidate operator functions of the form
+  //   For every T, where T is an enumeration type or a pointer type,
+  //   there exist candidate operator functions of the form
   //
   //        bool       operator<(T, T);
   //        bool       operator>(T, T);
@@ -7737,17 +7746,6 @@ public:
         QualType ParamTypes[2] = { *Enum, *Enum };
         S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet);
       }
-      
-      if (CandidateTypes[ArgIdx].hasNullPtrType()) {
-        CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy);
-        if (AddedTypes.insert(NullPtrTy).second &&
-            !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy,
-                                                             NullPtrTy))) {
-          QualType ParamTypes[2] = { NullPtrTy, NullPtrTy };
-          S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args,
-                                CandidateSet);
-        }
-      }
     }
   }
 
@@ -8443,7 +8441,7 @@ void Sema::AddBuiltinOperatorCandidates(
 
   case OO_EqualEqual:
   case OO_ExclaimEqual:
-    OpBuilder.addEqualEqualOrNotEqualMemberPointerOverloads();
+    OpBuilder.addEqualEqualOrNotEqualMemberPointerOrNullptrOverloads();
     // Fall through.
 
   case OO_Less:

Modified: cfe/trunk/test/CXX/drs/dr15xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr15xx.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr15xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr15xx.cpp Thu Oct 20 21:36:37 2016
@@ -3,9 +3,137 @@
 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 
-#if __cplusplus < 201103L
-// expected-no-diagnostics
+namespace dr1512 { // dr1512: 4.0
+  void f(char *p) {
+    if (p > 0) {} // expected-error {{ordered comparison between pointer and zero}}
+#if __cplusplus >= 201103L
+    if (p > nullptr) {} // expected-error {{invalid operands}}
 #endif
+  }
+  bool g(int **x, const int **y) {
+    return x < y;
+  }
+
+  template<typename T> T val();
+
+  template<typename A, typename B, typename C> void composite_pointer_type_is_base() {
+    typedef __typeof(true ? val<A>() : val<B>()) type;
+    typedef C type;
+
+    typedef __typeof(val<A>() == val<B>()) cmp;
+    typedef __typeof(val<A>() != val<B>()) cmp;
+    typedef bool cmp;
+  }
+
+  template<typename A, typename B, typename C> void composite_pointer_type_is_ord() {
+    composite_pointer_type_is_base<A, B, C>();
+
+    typedef __typeof(val<A>() < val<B>()) cmp;
+    typedef __typeof(val<A>() <= val<B>()) cmp;
+    typedef __typeof(val<A>() > val<B>()) cmp;
+    typedef __typeof(val<A>() >= val<B>()) cmp;
+    typedef bool cmp;
+  }
+
+  template <typename A, typename B, typename C>
+  void composite_pointer_type_is_unord(int = 0) {
+    composite_pointer_type_is_base<A, B, C>();
+  }
+  template <typename A, typename B, typename C>
+  void composite_pointer_type_is_unord(__typeof(val<A>() < val<B>()) * = 0);
+  template <typename A, typename B, typename C>
+  void composite_pointer_type_is_unord(__typeof(val<A>() <= val<B>()) * = 0);
+  template <typename A, typename B, typename C>
+  void composite_pointer_type_is_unord(__typeof(val<A>() > val<B>()) * = 0);
+  template <typename A, typename B, typename C>
+  void composite_pointer_type_is_unord(__typeof(val<A>() >= val<B>()) * = 0);
+
+  // A call to this is ambiguous if a composite pointer type exists.
+  template<typename A, typename B>
+  void no_composite_pointer_type(__typeof((true ? val<A>() : val<B>()), void()) * = 0);
+  template<typename A, typename B> void no_composite_pointer_type(int = 0);
+
+  struct A {};
+  struct B : A {};
+  struct C {};
+
+  void test() {
+#if __cplusplus >= 201103L
+    using nullptr_t = decltype(nullptr);
+    composite_pointer_type_is_unord<nullptr_t, nullptr_t, nullptr_t>();
+    no_composite_pointer_type<nullptr_t, int>();
+
+    composite_pointer_type_is_unord<nullptr_t, const char**, const char**>();
+    composite_pointer_type_is_unord<const char**, nullptr_t, const char**>();
+#endif
+
+    composite_pointer_type_is_ord<const int *, volatile void *, const volatile void*>();
+    composite_pointer_type_is_ord<const void *, volatile int *, const volatile void*>();
+
+    composite_pointer_type_is_ord<const A*, volatile B*, const volatile A*>();
+    composite_pointer_type_is_ord<const B*, volatile A*, const volatile A*>();
+
+    composite_pointer_type_is_unord<const int *A::*, volatile int *B::*, const volatile int *const B::*>();
+    composite_pointer_type_is_unord<const int *B::*, volatile int *A::*, const volatile int *const B::*>();
+    no_composite_pointer_type<int (A::*)(), int (C::*)()>();
+    no_composite_pointer_type<const int (A::*)(), volatile int (C::*)()>();
+
+#if __cplusplus > 201402
+    composite_pointer_type_is_ord<int (*)() noexcept, int (*)(), int (*)()>();
+    composite_pointer_type_is_ord<int (*)(), int (*)() noexcept, int (*)()>();
+    composite_pointer_type_is_unord<int (A::*)() noexcept, int (A::*)(), int (A::*)()>();
+    composite_pointer_type_is_unord<int (A::*)(), int (A::*)() noexcept, int (A::*)()>();
+    // FIXME: This looks like a standard defect; these should probably all have type 'int (B::*)()'.
+    composite_pointer_type_is_unord<int (B::*)(), int (A::*)() noexcept, int (B::*)()>();
+    composite_pointer_type_is_unord<int (A::*)() noexcept, int (B::*)(), int (B::*)()>();
+    composite_pointer_type_is_unord<int (B::*)() noexcept, int (A::*)(), int (B::*)()>();
+    composite_pointer_type_is_unord<int (A::*)(), int (B::*)() noexcept, int (B::*)()>();
+
+    // FIXME: It would be reasonable to permit these, with a common type of 'int (*const *)()'.
+    no_composite_pointer_type<int (**)() noexcept, int (**)()>();
+    no_composite_pointer_type<int (**)(), int (**)() noexcept>();
+
+    // FIXME: It would be reasonable to permit these, with a common type of 'int (A::*)()'.
+    no_composite_pointer_type<int (A::*)() const, int (A::*)()>();
+    no_composite_pointer_type<int (A::*)(), int (A::*)() const>();
+
+    // FIXME: It would be reasonable to permit these, with a common type of
+    // 'int (A::*)() &' and 'int (A::*)() &&', respectively.
+    no_composite_pointer_type<int (A::*)() &, int (A::*)()>();
+    no_composite_pointer_type<int (A::*)(), int (A::*)() &>();
+    no_composite_pointer_type<int (A::*)() &&, int (A::*)()>();
+    no_composite_pointer_type<int (A::*)(), int (A::*)() &&>();
+
+    no_composite_pointer_type<int (A::*)() &&, int (A::*)() &>();
+    no_composite_pointer_type<int (A::*)() &, int (A::*)() &&>();
+
+    no_composite_pointer_type<int (C::*)(), int (A::*)() noexcept>();
+    no_composite_pointer_type<int (A::*)() noexcept, int (C::*)()>();
+#endif
+  }
+
+  template<typename T> struct Wrap { operator T(); };
+  void test_overload() {
+#if __cplusplus >= 201103L
+    using nullptr_t = decltype(nullptr);
+    void(Wrap<nullptr_t>() == Wrap<nullptr_t>());
+    void(Wrap<nullptr_t>() != Wrap<nullptr_t>());
+    void(Wrap<nullptr_t>() < Wrap<nullptr_t>()); // expected-error {{invalid operands}}
+    void(Wrap<nullptr_t>() > Wrap<nullptr_t>()); // expected-error {{invalid operands}}
+    void(Wrap<nullptr_t>() <= Wrap<nullptr_t>()); // expected-error {{invalid operands}}
+    void(Wrap<nullptr_t>() >= Wrap<nullptr_t>()); // expected-error {{invalid operands}}
+
+    // The wording change fails to actually disallow this. This is valid
+    // via the builtin operator<(int*, int*) etc.
+    void(Wrap<nullptr_t>() == Wrap<int*>());
+    void(Wrap<nullptr_t>() != Wrap<int*>());
+    void(Wrap<nullptr_t>() < Wrap<int*>());
+    void(Wrap<nullptr_t>() > Wrap<int*>());
+    void(Wrap<nullptr_t>() <= Wrap<int*>());
+    void(Wrap<nullptr_t>() >= Wrap<int*>());
+#endif
+  }
+}
 
 namespace dr1550 { // dr1550: yes
   int f(bool b, int n) {

Modified: cfe/trunk/test/CXX/drs/dr5xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr5xx.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr5xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr5xx.cpp Thu Oct 20 21:36:37 2016
@@ -863,14 +863,13 @@ namespace dr580 { // dr580: partial
 
 // dr582: na
 
-namespace dr583 { // dr583: no
+namespace dr583 { // dr583: 4.0
   // see n3624
   int *p;
-  // FIXME: These are all ill-formed.
-  bool b1 = p < 0;
-  bool b2 = p > 0;
-  bool b3 = p <= 0;
-  bool b4 = p >= 0;
+  bool b1 = p < 0; // expected-error {{ordered comparison between pointer and zero}}
+  bool b2 = p > 0; // expected-error {{ordered comparison between pointer and zero}}
+  bool b3 = p <= 0; // expected-error {{ordered comparison between pointer and zero}}
+  bool b4 = p >= 0; // expected-error {{ordered comparison between pointer and zero}}
 }
 
 // dr584: na

Modified: cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp Thu Oct 20 21:36:37 2016
@@ -461,14 +461,14 @@ namespace UnspecifiedRelations {
   constexpr bool u2 = p > q; // expected-error {{constant expression}}
   constexpr bool u3 = p <= q; // expected-error {{constant expression}}
   constexpr bool u4 = p >= q; // expected-error {{constant expression}}
-  constexpr bool u5 = p < 0; // expected-error {{constant expression}}
-  constexpr bool u6 = p <= 0; // expected-error {{constant expression}}
-  constexpr bool u7 = p > 0; // expected-error {{constant expression}}
-  constexpr bool u8 = p >= 0; // expected-error {{constant expression}}
-  constexpr bool u9 = 0 < q; // expected-error {{constant expression}}
-  constexpr bool u10 = 0 <= q; // expected-error {{constant expression}}
-  constexpr bool u11 = 0 > q; // expected-error {{constant expression}}
-  constexpr bool u12 = 0 >= q; // expected-error {{constant expression}}
+  constexpr bool u5 = p < (int*)0; // expected-error {{constant expression}}
+  constexpr bool u6 = p <= (int*)0; // expected-error {{constant expression}}
+  constexpr bool u7 = p > (int*)0; // expected-error {{constant expression}}
+  constexpr bool u8 = p >= (int*)0; // expected-error {{constant expression}}
+  constexpr bool u9 = (int*)0 < q; // expected-error {{constant expression}}
+  constexpr bool u10 = (int*)0 <= q; // expected-error {{constant expression}}
+  constexpr bool u11 = (int*)0 > q; // expected-error {{constant expression}}
+  constexpr bool u12 = (int*)0 >= q; // expected-error {{constant expression}}
   void f(), g();
 
   constexpr void (*pf)() = &f, (*pg)() = &g;
@@ -522,7 +522,7 @@ namespace UnspecifiedRelations {
   constexpr void *null = 0;
   constexpr void *pv = (void*)&s.a;
   constexpr void *qv = (void*)&s.b;
-  constexpr bool v1 = null < 0;
+  constexpr bool v1 = null < (int*)0;
   constexpr bool v2 = null < pv; // expected-error {{constant expression}}
   constexpr bool v3 = null == pv; // ok
   constexpr bool v4 = qv == pv; // ok

Added: cfe/trunk/test/CXX/over/over.built/p15.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.built/p15.cpp?rev=284800&view=auto
==============================================================================
--- cfe/trunk/test/CXX/over/over.built/p15.cpp (added)
+++ cfe/trunk/test/CXX/over/over.built/p15.cpp Thu Oct 20 21:36:37 2016
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare
+
+struct A { operator decltype(nullptr)(); };
+struct B { operator const int *(); };
+void f(A a, B b, volatile int *pi) {
+  (void)(a == a);
+  (void)(a != a);
+  (void)(a < a); // expected-error {{invalid operands}}
+  (void)(a > a); // expected-error {{invalid operands}}
+  (void)(a <= a); // expected-error {{invalid operands}}
+  (void)(a >= a); // expected-error {{invalid operands}}
+
+  (void)(a == b);
+  (void)(a != b);
+  // FIXME: These cases were intended to be made ill-formed by N3624, but it
+  // fails to actually achieve this goal.
+  (void)(a < b);
+  (void)(a > b);
+  (void)(a <= b);
+  (void)(a >= b);
+
+  (void)(b == a);
+  (void)(b != a);
+  // FIXME: These cases were intended to be made ill-formed by N3624, but it
+  // fails to actually achieve this goal.
+  (void)(b < a);
+  (void)(b > a);
+  (void)(b <= a);
+  (void)(b >= a);
+
+  (void)(a == pi);
+  (void)(a != pi);
+  // FIXME: These cases were intended to be made ill-formed by N3624, but it
+  // fails to actually achieve this goal.
+  (void)(a < pi);
+  (void)(a > pi);
+  (void)(a <= pi);
+  (void)(a >= pi);
+
+  (void)(pi == a);
+  (void)(pi != a);
+  // FIXME: These cases were intended to be made ill-formed by N3624, but it
+  // fails to actually achieve this goal.
+  (void)(pi < a);
+  (void)(pi > a);
+  (void)(pi <= a);
+  (void)(pi >= a);
+
+  (void)(b == pi);
+  (void)(b != pi);
+  (void)(b < pi);
+  (void)(b > pi);
+  (void)(b <= pi);
+  (void)(b >= pi);
+
+  (void)(pi == b);
+  (void)(pi != b);
+  (void)(pi < b);
+  (void)(pi > b);
+  (void)(pi <= b);
+  (void)(pi >= b);
+
+  (void)(b == b);
+  (void)(b != b);
+  (void)(b < b);
+  (void)(b > b);
+  (void)(b <= b);
+  (void)(b >= b);
+
+  (void)(pi == pi);
+  (void)(pi != pi);
+  (void)(pi < pi);
+  (void)(pi > pi);
+  (void)(pi <= pi);
+  (void)(pi >= pi);
+}
+
+// FIXME: This is wrong: the type T = 'const volatile int * const * const *'
+// would work here, and there exists a builtin candidate for that type.
+struct C { operator const int ***(); };
+void g(C c, volatile int ***p) {
+  (void)(c < p); // expected-error {{invalid operands}}
+}

Added: cfe/trunk/test/CXX/over/over.built/p16.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.built/p16.cpp?rev=284800&view=auto
==============================================================================
--- cfe/trunk/test/CXX/over/over.built/p16.cpp (added)
+++ cfe/trunk/test/CXX/over/over.built/p16.cpp Thu Oct 20 21:36:37 2016
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-tautological-compare
+
+struct A { operator decltype(nullptr)(); };
+struct B { operator int A::*(); };
+void f(A a, B b, int A::*pi) {
+  (void)(a == a);
+  (void)(a != a);
+  (void)(a < a); // expected-error {{invalid operands}}
+  (void)(a > a); // expected-error {{invalid operands}}
+  (void)(a <= a); // expected-error {{invalid operands}}
+  (void)(a >= a); // expected-error {{invalid operands}}
+
+  (void)(a == b);
+  (void)(a != b);
+  (void)(a < b); // expected-error {{invalid operands}}
+  (void)(a > b); // expected-error {{invalid operands}}
+  (void)(a <= b); // expected-error {{invalid operands}}
+  (void)(a >= b); // expected-error {{invalid operands}}
+
+  (void)(b == a);
+  (void)(b != a);
+  (void)(b < a); // expected-error {{invalid operands}}
+  (void)(b > a); // expected-error {{invalid operands}}
+  (void)(b <= a); // expected-error {{invalid operands}}
+  (void)(b >= a); // expected-error {{invalid operands}}
+
+  (void)(a == pi);
+  (void)(a != pi);
+  (void)(a < pi); // expected-error {{invalid operands}}
+  (void)(a > pi); // expected-error {{invalid operands}}
+  (void)(a <= pi); // expected-error {{invalid operands}}
+  (void)(a >= pi); // expected-error {{invalid operands}}
+
+  (void)(pi == a);
+  (void)(pi != a);
+  (void)(pi < a); // expected-error {{invalid operands}}
+  (void)(pi > a); // expected-error {{invalid operands}}
+  (void)(pi <= a); // expected-error {{invalid operands}}
+  (void)(pi >= a); // expected-error {{invalid operands}}
+
+  (void)(b == pi);
+  (void)(b != pi);
+  (void)(b < pi); // expected-error {{invalid operands}}
+  (void)(b > pi); // expected-error {{invalid operands}}
+  (void)(b <= pi); // expected-error {{invalid operands}}
+  (void)(b >= pi); // expected-error {{invalid operands}}
+
+  (void)(pi == b);
+  (void)(pi != b);
+  (void)(pi < b); // expected-error {{invalid operands}}
+  (void)(pi > b); // expected-error {{invalid operands}}
+  (void)(pi <= b); // expected-error {{invalid operands}}
+  (void)(pi >= b); // expected-error {{invalid operands}}
+
+  (void)(b == b);
+  (void)(b != b);
+  (void)(b < b); // expected-error {{invalid operands}}
+  (void)(b > b); // expected-error {{invalid operands}}
+  (void)(b <= b); // expected-error {{invalid operands}}
+  (void)(b >= b); // expected-error {{invalid operands}}
+
+  (void)(pi == pi);
+  (void)(pi != pi);
+  (void)(pi < pi); // expected-error {{invalid operands}}
+  (void)(pi > pi); // expected-error {{invalid operands}}
+  (void)(pi <= pi); // expected-error {{invalid operands}}
+  (void)(pi >= pi); // expected-error {{invalid operands}}
+}
+
+// FIXME: This is wrong: type T = 'const volatile int * const A::* const B::*'
+// would work here, and there exists a builtin candidate for that type.
+struct C { operator const int *A::*B::*(); };
+void g(C c, volatile int *A::*B::*p) {
+  (void)(c == p); // expected-error {{invalid operands}}
+}

Modified: cfe/trunk/test/Misc/warning-flags.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/warning-flags.c?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/Misc/warning-flags.c (original)
+++ cfe/trunk/test/Misc/warning-flags.c Thu Oct 20 21:36:37 2016
@@ -18,7 +18,7 @@ This test serves two purposes:
 
 The list of warnings below should NEVER grow.  It should gradually shrink to 0.
 
-CHECK: Warnings without flags (84):
+CHECK: Warnings without flags (83):
 CHECK-NEXT:   ext_excess_initializers
 CHECK-NEXT:   ext_excess_initializers_in_char_array_initializer
 CHECK-NEXT:   ext_expected_semi_decl_list
@@ -31,7 +31,6 @@ CHECK-NEXT:   ext_plain_complex
 CHECK-NEXT:   ext_template_arg_extra_parens
 CHECK-NEXT:   ext_typecheck_comparison_of_pointer_integer
 CHECK-NEXT:   ext_typecheck_cond_incompatible_operands
-CHECK-NEXT:   ext_typecheck_cond_incompatible_operands_nonstandard
 CHECK-NEXT:   ext_typecheck_ordered_comparison_of_function_pointers
 CHECK-NEXT:   ext_typecheck_ordered_comparison_of_pointer_integer
 CHECK-NEXT:   ext_using_undefined_std

Modified: cfe/trunk/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/distribute_parallel_for_simd_aligned_messages.cpp Thu Oct 20 21:36:37 2016
@@ -166,7 +166,8 @@ template<class I, class C> int foomain(I
 
 #pragma omp target
 #pragma omp teams
-#pragma omp distribute parallel for simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+// FIXME: Should argc really be a pointer?
+#pragma omp distribute parallel for simd aligned (*argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
   for (I k = 0; k < argc; ++k) ++k;
 
 #pragma omp target

Modified: cfe/trunk/test/OpenMP/distribute_simd_aligned_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/distribute_simd_aligned_messages.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/distribute_simd_aligned_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/distribute_simd_aligned_messages.cpp Thu Oct 20 21:36:37 2016
@@ -166,7 +166,8 @@ template<class I, class C> int foomain(I
 
 #pragma omp target
 #pragma omp teams
-#pragma omp distribute simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+// FIXME: Should argc really be a pointer?
+#pragma omp distribute simd aligned (*argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
   for (I k = 0; k < argc; ++k) ++k;
 
 #pragma omp target

Modified: cfe/trunk/test/OpenMP/for_simd_aligned_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/for_simd_aligned_messages.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/for_simd_aligned_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/for_simd_aligned_messages.cpp Thu Oct 20 21:36:37 2016
@@ -121,7 +121,8 @@ template<class I, class C> int foomain(I
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp for simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
   for (I k = 0; k < argc; ++k) ++k;
-  #pragma omp for simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+// FIXME: Should argc really be a pointer?
+  #pragma omp for simd aligned (*argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp for simd aligned (argc : 5) // expected-warning {{aligned clause will be ignored because the requested alignment is not a power of 2}}
   for (I k = 0; k < argc; ++k) ++k;

Modified: cfe/trunk/test/OpenMP/parallel_for_simd_aligned_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_for_simd_aligned_messages.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/parallel_for_simd_aligned_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/parallel_for_simd_aligned_messages.cpp Thu Oct 20 21:36:37 2016
@@ -121,7 +121,8 @@ template<class I, class C> int foomain(I
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp parallel for simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
   for (I k = 0; k < argc; ++k) ++k;
-  #pragma omp parallel for simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+// FIXME: Should argc really be a pointer?
+  #pragma omp parallel for simd aligned (*argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp parallel for simd aligned (argc : 5) // expected-warning {{aligned clause will be ignored because the requested alignment is not a power of 2}}
   for (I k = 0; k < argc; ++k) ++k;

Modified: cfe/trunk/test/OpenMP/simd_aligned_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/simd_aligned_messages.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/simd_aligned_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/simd_aligned_messages.cpp Thu Oct 20 21:36:37 2016
@@ -121,7 +121,8 @@ template<class I, class C> int foomain(I
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
   for (I k = 0; k < argc; ++k) ++k;
-  #pragma omp simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+// FIXME: Should argc really be a pointer?
+  #pragma omp simd aligned (*argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp simd aligned (argc : 5) // expected-warning {{aligned clause will be ignored because the requested alignment is not a power of 2}}
   for (I k = 0; k < argc; ++k) ++k;

Modified: cfe/trunk/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/target_parallel_for_simd_aligned_messages.cpp Thu Oct 20 21:36:37 2016
@@ -121,7 +121,8 @@ template<class I, class C> int foomain(I
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp target parallel for simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
   for (I k = 0; k < argc; ++k) ++k;
-  #pragma omp target parallel for simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+// FIXME: Should argc really be a pointer?
+  #pragma omp target parallel for simd aligned (*argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp target parallel for simd aligned (argc : 5) // expected-warning {{aligned clause will be ignored because the requested alignment is not a power of 2}}
   for (I k = 0; k < argc; ++k) ++k;

Modified: cfe/trunk/test/OpenMP/target_simd_aligned_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/target_simd_aligned_messages.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/target_simd_aligned_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/target_simd_aligned_messages.cpp Thu Oct 20 21:36:37 2016
@@ -121,7 +121,8 @@ template<class I, class C> int foomain(I
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp target simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
   for (I k = 0; k < argc; ++k) ++k;
-  #pragma omp target simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+// FIXME: Should argc really be a pointer?
+  #pragma omp target simd aligned (*argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp target simd aligned (argc : 5) // expected-warning {{aligned clause will be ignored because the requested alignment is not a power of 2}}
   for (I k = 0; k < argc; ++k) ++k;

Modified: cfe/trunk/test/OpenMP/taskloop_simd_aligned_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/taskloop_simd_aligned_messages.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/taskloop_simd_aligned_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/taskloop_simd_aligned_messages.cpp Thu Oct 20 21:36:37 2016
@@ -121,7 +121,8 @@ template<class I, class C> int foomain(I
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp taskloop simd aligned (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
   for (I k = 0; k < argc; ++k) ++k;
-  #pragma omp taskloop simd aligned (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+// FIXME: Should argc really be a pointer?
+  #pragma omp taskloop simd aligned (*argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
   for (I k = 0; k < argc; ++k) ++k;
   #pragma omp taskloop simd aligned (argc : 5) // expected-warning {{aligned clause will be ignored because the requested alignment is not a power of 2}}
   for (I k = 0; k < argc; ++k) ++k;

Modified: cfe/trunk/test/SemaCXX/compare.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/compare.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/compare.cpp (original)
+++ cfe/trunk/test/SemaCXX/compare.cpp Thu Oct 20 21:36:37 2016
@@ -201,9 +201,10 @@ int test1(int i) {
 
 enum E { e };
 void test2(int i, void *vp) {
+  if (&i == vp) { } // ok
   if (test1 == vp) { } // expected-warning{{equality comparison between function pointer and void pointer}}
   if (test1 == e) { } // expected-error{{comparison between pointer and integer}}
-  if (vp < 0) { }
+  if (vp < 0) { } // expected-error {{comparison between pointer and zero}}
   if (test1 < e) { } // expected-error{{comparison between pointer and integer}}
 }
 

Modified: cfe/trunk/test/SemaCXX/composite-pointer-type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/composite-pointer-type.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/composite-pointer-type.cpp (original)
+++ cfe/trunk/test/SemaCXX/composite-pointer-type.cpp Thu Oct 20 21:36:37 2016
@@ -53,8 +53,8 @@ bool f(Matrix4 m1, const Matrix4 m2) {
 
 // PR6346
 bool f1(bool b, void **p, const void **q) {
-  if (p == q) // expected-warning{{comparison of distinct pointer types ('void **' and 'const void **') uses non-standard composite pointer type 'const void *const *'}}
+  if (p == q)
     return false;
 
-  return b? p : q; // expected-warning{{incompatible operand types ('void **' and 'const void **') use non-standard composite pointer type 'const void *const *'}}
+  return b? p : q;
 }

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Thu Oct 20 21:36:37 2016
@@ -279,17 +279,17 @@ static_assert(&s.x > &s.y, "false"); //
 
 static_assert(0 == &y, "false"); // expected-error {{false}}
 static_assert(0 != &y, "");
-constexpr bool n3 = 0 <= &y; // expected-error {{must be initialized by a constant expression}}
-constexpr bool n4 = 0 >= &y; // expected-error {{must be initialized by a constant expression}}
-constexpr bool n5 = 0 < &y; // expected-error {{must be initialized by a constant expression}}
-constexpr bool n6 = 0 > &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n3 = (int*)0 <= &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n4 = (int*)0 >= &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n5 = (int*)0 < &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n6 = (int*)0 > &y; // expected-error {{must be initialized by a constant expression}}
 
 static_assert(&x == 0, "false"); // expected-error {{false}}
 static_assert(&x != 0, "");
-constexpr bool n9 = &x <= 0; // expected-error {{must be initialized by a constant expression}}
-constexpr bool n10 = &x >= 0; // expected-error {{must be initialized by a constant expression}}
-constexpr bool n11 = &x < 0; // expected-error {{must be initialized by a constant expression}}
-constexpr bool n12 = &x > 0; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n9 = &x <= (int*)0; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n10 = &x >= (int*)0; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n11 = &x < (int*)0; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n12 = &x > (int*)0; // expected-error {{must be initialized by a constant expression}}
 
 static_assert(&x == &x, "");
 static_assert(&x != &x, "false"); // expected-error {{false}}

Added: cfe/trunk/test/SemaCXX/libstdcxx_libcxx_less_hack.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/libstdcxx_libcxx_less_hack.cpp?rev=284800&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/libstdcxx_libcxx_less_hack.cpp (added)
+++ cfe/trunk/test/SemaCXX/libstdcxx_libcxx_less_hack.cpp Thu Oct 20 21:36:37 2016
@@ -0,0 +1,67 @@
+// This is a test for a hack in Clang that works around a problem introduced by
+// DR583: it's no longer possible to compare a pointer against nullptr_t, but
+// we still want to permit those comparisons within less<> and friends.
+
+// RUN: %clang_cc1 -verify %s -std=c++14
+
+namespace std {
+  template<typename T = void> struct less {};
+  template<typename T = void> struct less_equal {};
+  template<typename T = void> struct greater {};
+  template<typename T = void> struct greater_equal {};
+
+  template<> struct less<> {
+    template <class T1, class T2>
+    auto operator()(T1 &&t, T2 &&u) const noexcept(noexcept(t < u))
+        -> decltype(t < u) {
+      return t < u;
+    }
+  };
+
+  template<> struct less_equal<> {
+    template <class T1, class T2>
+    auto operator()(T1 &&t, T2 &&u) const noexcept(noexcept(t <= u))
+        -> decltype(t <= u) {
+      return t <= u;
+    }
+  };
+
+  template<> struct greater<> {
+    template <class T1, class T2>
+    auto operator()(T1 &&t, T2 &&u) const noexcept(noexcept(t > u))
+        -> decltype(t > u) {
+      return t > u;
+    }
+  };
+
+  template<> struct greater_equal<> {
+    template <class T1, class T2>
+    auto operator()(T1 &&t, T2 &&u) const noexcept(noexcept(t >= u))
+        -> decltype(t >= u) {
+      return t >= u;
+    }
+  };
+
+  template<typename = void> struct unrelated;
+  template<> struct unrelated<> {
+    template <class T1, class T2>
+    auto operator()(T1 &&t, T2 &&u) const noexcept(noexcept(t < u)) // expected-note {{substitution failure}}
+        -> decltype(t < u) {
+      return t < u;
+    }
+  };
+};
+
+void test(int *p) {
+  using namespace std;
+  less<>()(p, nullptr);
+  less<>()(nullptr, p);
+  less_equal<>()(p, nullptr);
+  less_equal<>()(nullptr, p);
+  greater<>()(p, nullptr);
+  greater<>()(nullptr, p);
+  greater_equal<>()(p, nullptr);
+  greater_equal<>()(nullptr, p);
+
+  unrelated<>()(p, nullptr); // expected-error {{no matching function}}
+}

Modified: cfe/trunk/test/SemaCXX/null_in_arithmetic_ops.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/null_in_arithmetic_ops.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/null_in_arithmetic_ops.cpp (original)
+++ cfe/trunk/test/SemaCXX/null_in_arithmetic_ops.cpp Thu Oct 20 21:36:37 2016
@@ -71,8 +71,8 @@ void f() {
   b = a == NULL || a != NULL; // expected-warning 2{{comparison between NULL and non-pointer ('int' and NULL)}}
   b = NULL == a || NULL != a; // expected-warning 2{{comparison between NULL and non-pointer (NULL and 'int')}}
 
-  b = &a < NULL || NULL < &a || &a > NULL || NULL > &a;
-  b = &a <= NULL || NULL <= &a || &a >= NULL || NULL >= &a;
+  b = &a < NULL || NULL < &a || &a > NULL || NULL > &a; // expected-error 4{{ordered comparison between pointer and zero}}
+  b = &a <= NULL || NULL <= &a || &a >= NULL || NULL >= &a; // expected-error 4{{ordered comparison between pointer and zero}}
   b = &a == NULL || NULL == &a || &a != NULL || NULL != &a;
 
   b = 0 == a;

Modified: cfe/trunk/test/SemaCXX/nullptr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nullptr.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/nullptr.cpp (original)
+++ cfe/trunk/test/SemaCXX/nullptr.cpp Thu Oct 20 21:36:37 2016
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -ffreestanding -Wno-null-conversion %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -ffreestanding -Wno-null-conversion -Wno-tautological-compare %s
 #include <stdint.h>
 
 typedef decltype(nullptr) nullptr_t;
@@ -32,17 +32,17 @@ nullptr_t f(nullptr_t null)
 
   // Operators
   (void)(null == nullptr);
-  (void)(null <= nullptr);
+  (void)(null <= nullptr); // expected-error {{invalid operands to binary expression}}
   (void)(null == 0);
   (void)(null == (void*)0);
   (void)((void*)0 == nullptr);
-  (void)(null <= 0);
-  (void)(null <= (void*)0);
-  (void)((void*)0 <= nullptr);
+  (void)(null <= 0); // expected-error {{invalid operands to binary expression}}
+  (void)(null <= (void*)0); // expected-error {{invalid operands to binary expression}}
+  (void)((void*)0 <= nullptr); // expected-error {{invalid operands to binary expression}}
   (void)(0 == nullptr);
   (void)(nullptr == 0);
-  (void)(nullptr <= 0);
-  (void)(0 <= nullptr);
+  (void)(nullptr <= 0); // expected-error {{invalid operands to binary expression}}
+  (void)(0 <= nullptr); // expected-error {{invalid operands to binary expression}}
   (void)(1 > nullptr); // expected-error {{invalid operands to binary expression}}
   (void)(1 != nullptr); // expected-error {{invalid operands to binary expression}}
   (void)(1 + nullptr); // expected-error {{invalid operands to binary expression}}
@@ -118,24 +118,24 @@ static_assert(__is_scalar(nullptr_t), ""
 static_assert(__is_pod(nullptr_t), "");
 static_assert(sizeof(nullptr_t) == sizeof(void*), "");
 
-static_assert(!(nullptr < nullptr), "");
-static_assert(!(nullptr > nullptr), "");
-static_assert(  nullptr <= nullptr, "");
-static_assert(  nullptr >= nullptr, "");
+static_assert(!(nullptr < nullptr), ""); // expected-error {{invalid operands to binary expression}}
+static_assert(!(nullptr > nullptr), ""); // expected-error {{invalid operands to binary expression}}
+static_assert(  nullptr <= nullptr, ""); // expected-error {{invalid operands to binary expression}}
+static_assert(  nullptr >= nullptr, ""); // expected-error {{invalid operands to binary expression}}
 static_assert(  nullptr == nullptr, "");
 static_assert(!(nullptr != nullptr), "");
 
-static_assert(!(0 < nullptr), "");
-static_assert(!(0 > nullptr), "");
-static_assert(  0 <= nullptr, "");
-static_assert(  0 >= nullptr, "");
+static_assert(!(0 < nullptr), ""); // expected-error {{invalid operands to binary expression}}
+static_assert(!(0 > nullptr), ""); // expected-error {{invalid operands to binary expression}}
+static_assert(  0 <= nullptr, ""); // expected-error {{invalid operands to binary expression}}
+static_assert(  0 >= nullptr, ""); // expected-error {{invalid operands to binary expression}}
 static_assert(  0 == nullptr, "");
 static_assert(!(0 != nullptr), "");
 
-static_assert(!(nullptr < 0), "");
-static_assert(!(nullptr > 0), "");
-static_assert(  nullptr <= 0, "");
-static_assert(  nullptr >= 0, "");
+static_assert(!(nullptr < 0), ""); // expected-error {{invalid operands to binary expression}}
+static_assert(!(nullptr > 0), ""); // expected-error {{invalid operands to binary expression}}
+static_assert(  nullptr <= 0, ""); // expected-error {{invalid operands to binary expression}}
+static_assert(  nullptr >= 0, ""); // expected-error {{invalid operands to binary expression}}
 static_assert(  nullptr == 0, "");
 static_assert(!(nullptr != 0), "");
 
@@ -154,10 +154,10 @@ namespace overloading {
   void test_conversion(ConvertsToNullPtr ctn) {
     (void)(ctn == ctn);
     (void)(ctn != ctn);
-    (void)(ctn <= ctn);
-    (void)(ctn >= ctn);
-    (void)(ctn < ctn);
-    (void)(ctn > ctn);
+    (void)(ctn <= ctn); // expected-error {{invalid operands to binary expression}}
+    (void)(ctn >= ctn); // expected-error {{invalid operands to binary expression}}
+    (void)(ctn < ctn); // expected-error {{invalid operands to binary expression}}
+    (void)(ctn > ctn); // expected-error {{invalid operands to binary expression}}
   }
 }
 

Modified: cfe/trunk/test/SemaCXX/nullptr_in_arithmetic_ops.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nullptr_in_arithmetic_ops.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/nullptr_in_arithmetic_ops.cpp (original)
+++ cfe/trunk/test/SemaCXX/nullptr_in_arithmetic_ops.cpp Thu Oct 20 21:36:37 2016
@@ -45,12 +45,12 @@ void foo() {
   b = a == nullptr || nullptr == a; // expected-error 2{{invalid operands to binary expression}}
   b = a != nullptr || nullptr != a; // expected-error 2{{invalid operands to binary expression}}
 
-  b = &a < nullptr || nullptr < &a || &a > nullptr || nullptr > &a;
-  b = &a <= nullptr || nullptr <= &a || &a >= nullptr || nullptr >= &a;
+  b = &a < nullptr || nullptr < &a || &a > nullptr || nullptr > &a; // expected-error 4{{invalid operands}}
+  b = &a <= nullptr || nullptr <= &a || &a >= nullptr || nullptr >= &a; // expected-error 4{{invalid operands}}
   b = &a == nullptr || nullptr == &a || &a != nullptr || nullptr != &a;
 
-  b = nullptr < nullptr || nullptr > nullptr;
-  b = nullptr <= nullptr || nullptr >= nullptr;
+  b = nullptr < nullptr || nullptr > nullptr; // expected-error 2{{invalid operands to binary expression}}
+  b = nullptr <= nullptr || nullptr >= nullptr; // expected-error 2{{invalid operands to binary expression}}
   b = nullptr == nullptr || nullptr != nullptr;
 
   b = ((nullptr)) != a;  // expected-error{{invalid operands to binary expression}}

Modified: cfe/trunk/test/SemaCXX/warn-memsize-comparison.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-memsize-comparison.cpp?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-memsize-comparison.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-memsize-comparison.cpp Thu Oct 20 21:36:37 2016
@@ -5,7 +5,7 @@ typedef __SIZE_TYPE__ size_t;
 extern "C" void *memset(void *, int, size_t);
 extern "C" void *memmove(void *s1, const void *s2, size_t n);
 extern "C" void *memcpy(void *s1, const void *s2, size_t n);
-extern "C" void *memcmp(void *s1, const void *s2, size_t n);
+extern "C" int memcmp(void *s1, const void *s2, size_t n);
 extern "C" int strncmp(const char *s1, const char *s2, size_t n);
 extern "C" int strncasecmp(const char *s1, const char *s2, size_t n);
 extern "C" char *strncpy(char *dst, const char *src, size_t n);
@@ -28,11 +28,12 @@ void f() {
     expected-note {{explicitly cast the argument}}
   if (memmove(b1, b2, sizeof(b1)) == 0) {}
 
+  // FIXME: This fixit is bogus.
   if (memcpy(b1, b2, sizeof(b1) < 0)) {} // \
     expected-warning{{size argument in 'memcpy' call is a comparison}} \
     expected-note {{did you mean to compare}} \
     expected-note {{explicitly cast the argument}}
-  if (memcpy(b1, b2, sizeof(b1)) < 0) {}
+  if (memcpy(b1, b2, sizeof(b1)) < 0) {} // expected-error {{ordered comparison between pointer and zero}}
 
   if (memcmp(b1, b2, sizeof(b1) <= 0)) {} // \
     expected-warning{{size argument in 'memcmp' call is a comparison}} \
@@ -58,11 +59,12 @@ void f() {
     expected-note {{explicitly cast the argument}}
   if (strncpy(b1, b2, sizeof(b1)) == 0 || true) {}
 
+  // FIXME: This fixit is bogus.
   if (strncat(b1, b2, sizeof(b1) - 1 >= 0 && true)) {} // \
     expected-warning{{size argument in 'strncat' call is a comparison}} \
     expected-note {{did you mean to compare}} \
     expected-note {{explicitly cast the argument}}
-  if (strncat(b1, b2, sizeof(b1) - 1) >= 0 && true) {}
+  if (strncat(b1, b2, sizeof(b1) - 1) >= 0 && true) {} // expected-error {{ordered comparison between pointer and zero}}
 
   if (strndup(b1, sizeof(b1) != 0)) {} // \
     expected-warning{{size argument in 'strndup' call is a comparison}} \

Modified: cfe/trunk/test/SemaObjCXX/null_objc_pointer.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/null_objc_pointer.mm?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/null_objc_pointer.mm (original)
+++ cfe/trunk/test/SemaObjCXX/null_objc_pointer.mm Thu Oct 20 21:36:37 2016
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -Wnull-arithmetic %s
-// expected-no-diagnostics
 #define NULL __null
 
 @interface X
@@ -8,7 +7,7 @@
 void f() {
   bool b;
   X *d;
-  b = d < NULL || NULL < d || d > NULL || NULL > d;
-  b = d <= NULL || NULL <= d || d >= NULL || NULL >= d;
+  b = d < NULL || NULL < d || d > NULL || NULL > d; // expected-error 4{{ordered comparison between pointer and zero}}
+  b = d <= NULL || NULL <= d || d >= NULL || NULL >= d; // expected-error 4{{ordered comparison between pointer and zero}}
   b = d == NULL || NULL == d || d != NULL || NULL != d;
 }

Modified: cfe/trunk/www/cxx_dr_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=284800&r1=284799&r2=284800&view=diff
==============================================================================
--- cfe/trunk/www/cxx_dr_status.html (original)
+++ cfe/trunk/www/cxx_dr_status.html Thu Oct 20 21:36:37 2016
@@ -3541,7 +3541,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#583">583</a></td>
     <td>CD3</td>
     <td>Relational pointer comparisons against the null pointer constant</td>
-    <td class="none" align="center">No</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr id="584">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#584">584</a></td>
@@ -8887,7 +8887,7 @@ and <I>POD class</I></td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1512">1512</a></td>
     <td>CD3</td>
     <td>Pointer comparison vs qualification conversions</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr class="open" id="1513">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1513">1513</a></td>




More information about the cfe-commits mailing list