[clang] 4b00299 - [c++20] Add deprecation warnings for the expression forms deprecated by P1120R0.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 16 17:49:55 PST 2019


Author: Richard Smith
Date: 2019-12-16T17:49:45-08:00
New Revision: 4b0029995853fe37d1dc95ef96f46697c743fcad

URL: https://github.com/llvm/llvm-project/commit/4b0029995853fe37d1dc95ef96f46697c743fcad
DIFF: https://github.com/llvm/llvm-project/commit/4b0029995853fe37d1dc95ef96f46697c743fcad.diff

LOG: [c++20] Add deprecation warnings for the expression forms deprecated by P1120R0.

This covers:
 * usual arithmetic conversions (comparisons, arithmetic, conditionals)
   between different enumeration types
 * usual arithmetic conversions between enums and floating-point types
 * comparisons between two operands of array type

The deprecation warnings are on-by-default (in C++20 compilations); it
seems likely that these forms will become ill-formed in C++23, so
warning on them now by default seems wise.

For the first two bullets, off-by-default warnings were also added for
all the cases where we didn't already have warnings (covering language
modes prior to C++20). These warnings are in subgroups of the existing
-Wenum-conversion (except that the first case is not warned on if either
enumeration type is anonymous, consistent with our existing
-Wenum-conversion warnings).

Added: 
    clang/test/CXX/expr/expr.arith.conv/p2.cpp

Modified: 
    clang/include/clang/AST/Type.h
    clang/include/clang/Basic/DiagnosticGroups.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/Type.cpp
    clang/lib/Sema/SemaChecking.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/lib/Sema/SemaExprCXX.cpp
    clang/test/Sema/switch.c
    clang/test/Sema/warn-conditional-emum-types-mismatch.c
    clang/test/SemaCXX/deprecated.cpp
    clang/test/SemaCXX/self-comparison.cpp
    clang/test/SemaCXX/warn-enum-compare.cpp
    clang/www/cxx_status.html

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 882b5947c9f4..25ab44c4bcbe 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1973,6 +1973,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
 
   /// Determine whether this type is an integral or unscoped enumeration type.
   bool isIntegralOrUnscopedEnumerationType() const;
+  bool isUnscopedEnumerationType() const;
 
   /// Floating point categories.
   bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double)

diff  --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 6cb1a4e0700d..8aa93d4138a2 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -60,7 +60,27 @@ def UndefinedBoolConversion : DiagGroup<"undefined-bool-conversion">;
 def BoolConversion : DiagGroup<"bool-conversion", [PointerBoolConversion,
                                                    UndefinedBoolConversion]>;
 def IntConversion : DiagGroup<"int-conversion">;
-def EnumConversion : DiagGroup<"enum-conversion">;
+def DeprecatedEnumCompareConditional :
+  DiagGroup<"deprecated-enum-compare-conditional">;
+def EnumCompareConditional : DiagGroup<"enum-compare-conditional",
+                                       [DeprecatedEnumCompareConditional]>;
+def EnumCompareSwitch : DiagGroup<"enum-compare-switch">;
+def DeprecatedEnumCompare : DiagGroup<"deprecated-enum-compare">;
+def EnumCompare : DiagGroup<"enum-compare", [EnumCompareSwitch,
+                                             DeprecatedEnumCompare]>;
+def DeprecatedAnonEnumEnumConversion : DiagGroup<"deprecated-anon-enum-enum-conversion">;
+def DeprecatedEnumEnumConversion : DiagGroup<"deprecated-enum-enum-conversion">;
+def DeprecatedEnumFloatConversion : DiagGroup<"deprecated-enum-float-conversion">;
+def AnonEnumEnumConversion : DiagGroup<"anon-enum-enum-conversion",
+                                   [DeprecatedAnonEnumEnumConversion]>;
+def EnumEnumConversion : DiagGroup<"enum-enum-conversion",
+                                   [DeprecatedEnumEnumConversion]>;
+def EnumFloatConversion : DiagGroup<"enum-float-conversion",
+                                    [DeprecatedEnumFloatConversion]>;
+def EnumConversion : DiagGroup<"enum-conversion",
+                               [EnumEnumConversion,
+                                EnumFloatConversion,
+                                EnumCompareConditional]>;
 def ObjCSignedCharBoolImplicitIntConversion :
   DiagGroup<"objc-signed-char-bool-implicit-int-conversion">;
 def ImplicitIntConversion : DiagGroup<"implicit-int-conversion",
@@ -126,6 +146,7 @@ def FinalDtorNonFinalClass : DiagGroup<"final-dtor-non-final-class">;
 def CXX11CompatDeprecatedWritableStr :
   DiagGroup<"c++11-compat-deprecated-writable-strings">;
 
+def DeprecatedArrayCompare : DiagGroup<"deprecated-array-compare">;
 def DeprecatedAttributes : DiagGroup<"deprecated-attributes">;
 def DeprecatedCommaSubscript : DiagGroup<"deprecated-comma-subscript">;
 def DeprecatedCopy : DiagGroup<"deprecated-copy">;
@@ -147,12 +168,18 @@ def DeprecatedVolatile : DiagGroup<"deprecated-volatile">;
 def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
                                       [CXX11CompatDeprecatedWritableStr]>;
 // FIXME: Why is DeprecatedImplementations not in this group?
-def Deprecated : DiagGroup<"deprecated", [DeprecatedAttributes,
+def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
+                                          DeprecatedArrayCompare,
+                                          DeprecatedAttributes,
                                           DeprecatedCommaSubscript,
                                           DeprecatedCopy,
                                           DeprecatedCopyDtor,
                                           DeprecatedDeclarations,
                                           DeprecatedDynamicExceptionSpec,
+                                          DeprecatedEnumCompare,
+                                          DeprecatedEnumCompareConditional,
+                                          DeprecatedEnumEnumConversion,
+                                          DeprecatedEnumFloatConversion,
                                           DeprecatedIncrementBool,
                                           DeprecatedRegister,
                                           DeprecatedThisCapture,
@@ -573,9 +600,6 @@ def CoveredSwitchDefault : DiagGroup<"covered-switch-default">;
 def SwitchBool     : DiagGroup<"switch-bool">;
 def SwitchEnum     : DiagGroup<"switch-enum">;
 def Switch         : DiagGroup<"switch">;
-def EnumCompareConditional : DiagGroup<"enum-compare-conditional">;
-def EnumCompareSwitch : DiagGroup<"enum-compare-switch">;
-def EnumCompare       : DiagGroup<"enum-compare", [EnumCompareSwitch]>;
 def ImplicitFallthroughPerFunction :
   DiagGroup<"implicit-fallthrough-per-function">;
 def ImplicitFallthrough  : DiagGroup<"implicit-fallthrough",

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d657c29adafd..8f303f2f1496 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6219,6 +6219,52 @@ def err_typecheck_op_on_nonoverlapping_address_space_pointers : Error<
   "%
diff { ($ and $)|}0,1}2"
   " which are pointers to non-overlapping address spaces">;
 
+def select_arith_conv_kind : TextSubstitution<
+  "%select{arithmetic between|bitwise operation between|comparison of|"
+  "conditional expression between|compound assignment of}0">;
+def warn_arith_conv_enum_float : Warning<
+  "%sub{select_arith_conv_kind}0 "
+  "%select{floating-point|enumeration}1 type %2 "
+  "%plural{2:with|4:from|:and}0 "
+  "%select{enumeration|floating-point}1 type %3">,
+  InGroup<EnumFloatConversion>, DefaultIgnore;
+def warn_arith_conv_enum_float_cxx2a : Warning<
+  "%sub{select_arith_conv_kind}0 "
+  "%select{floating-point|enumeration}1 type %2 "
+  "%plural{2:with|4:from|:and}0 "
+  "%select{enumeration|floating-point}1 type %3 is deprecated">,
+  InGroup<DeprecatedEnumFloatConversion>;
+def warn_arith_conv_mixed_enum_types : Warning<
+  "%sub{select_arith_conv_kind}0 "
+  "
diff erent enumeration types%
diff { ($ and $)|}1,2">,
+  InGroup<EnumEnumConversion>, DefaultIgnore;
+def warn_arith_conv_mixed_enum_types_cxx2a : Warning<
+  "%sub{select_arith_conv_kind}0 "
+  "
diff erent enumeration types%
diff { ($ and $)|}1,2 is deprecated">,
+  InGroup<DeprecatedEnumEnumConversion>;
+def warn_arith_conv_mixed_anon_enum_types : Warning<
+  warn_arith_conv_mixed_enum_types.Text>,
+  InGroup<AnonEnumEnumConversion>, DefaultIgnore;
+def warn_arith_conv_mixed_anon_enum_types_cxx2a : Warning<
+  warn_arith_conv_mixed_enum_types_cxx2a.Text>,
+  InGroup<DeprecatedAnonEnumEnumConversion>;
+def warn_conditional_mixed_enum_types : Warning<
+  warn_arith_conv_mixed_enum_types.Text>,
+  InGroup<EnumCompareConditional>, DefaultIgnore;
+def warn_conditional_mixed_enum_types_cxx2a : Warning<
+  warn_arith_conv_mixed_enum_types_cxx2a.Text>,
+  InGroup<DeprecatedEnumCompareConditional>;
+def warn_comparison_mixed_enum_types : Warning<
+  warn_arith_conv_mixed_enum_types.Text>,
+  InGroup<EnumCompare>;
+def warn_comparison_mixed_enum_types_cxx2a : Warning<
+  warn_arith_conv_mixed_enum_types_cxx2a.Text>,
+  InGroup<DeprecatedEnumCompare>;
+def warn_comparison_of_mixed_enum_types_switch : Warning<
+  "comparison of 
diff erent enumeration types in switch statement"
+  "%
diff { ($ and $)|}0,1">,
+  InGroup<EnumCompareSwitch>;
+
 def err_typecheck_assign_const : Error<
   "%select{"
   "cannot assign to return value because function %1 returns a const value|"
@@ -6272,18 +6318,6 @@ def warn_left_shift_always : Warning<
   "converting the result of '<<' to a boolean always evaluates "
   "to %select{false|true}0">,
   InGroup<TautologicalConstantCompare>;
-def warn_comparison_of_mixed_enum_types : Warning<
-  "comparison of two values with 
diff erent enumeration types"
-  "%
diff { ($ and $)|}0,1">,
-  InGroup<EnumCompare>;
-def warn_conditional_mixed_enum_types : Warning<
-  "enumeration type mismatch in conditional expression"
-  "%
diff { ($ and $)|}0,1">,
-  InGroup<EnumCompareConditional>, DefaultIgnore;
-def warn_comparison_of_mixed_enum_types_switch : Warning<
-  "comparison of two values with 
diff erent enumeration types in switch statement"
-  "%
diff { ($ and $)|}0,1">,
-  InGroup<EnumCompareSwitch>;
 def warn_null_in_arithmetic_operation : Warning<
   "use of NULL in arithmetic operation">,
   InGroup<NullArithmetic>;
@@ -8507,6 +8541,10 @@ def warn_comparison_bitwise_or : Warning<
 def warn_tautological_overlap_comparison : Warning<
   "overlapping comparisons always evaluate to %select{false|true}0">,
   InGroup<TautologicalOverlapCompare>, DefaultIgnore;
+def warn_depr_array_comparison : Warning<
+  "comparison between two arrays is deprecated; "
+  "to compare array addresses, use unary '+' to decay operands to pointers">,
+  InGroup<DeprecatedArrayCompare>;
 
 def warn_stringcompare : Warning<
   "result of comparison against %select{a string literal|@encode}0 is "

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index a4a4c2ab2ed5..238cd913530a 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10344,13 +10344,27 @@ class Sema final {
   ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
                                               FunctionDecl *FDecl);
 
+  /// Context in which we're performing a usual arithmetic conversion.
+  enum ArithConvKind {
+    /// An arithmetic operation.
+    ACK_Arithmetic,
+    /// A bitwise operation.
+    ACK_BitwiseOp,
+    /// A comparison.
+    ACK_Comparison,
+    /// A conditional (?:) operator.
+    ACK_Conditional,
+    /// A compound assignment expression.
+    ACK_CompAssign,
+  };
+
   // UsualArithmeticConversions - performs the UsualUnaryConversions on it's
   // operands and then handles various conversions that are common to binary
   // operators (C99 6.3.1.8). If both operands aren't arithmetic, this
   // routine returns the first non-arithmetic type found. The client is
   // responsible for emitting appropriate error diagnostics.
   QualType UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
-                                      bool IsCompAssign = false);
+                                      SourceLocation Loc, ArithConvKind ACK);
 
   /// AssignConvertType - All of the 'assignment' semantic checks return this
   /// enum to indicate whether the assignment was allowed.  These checks are

diff  --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 2eae2ebb6174..85447d682ba2 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1856,7 +1856,10 @@ bool Type::isIntegralOrUnscopedEnumerationType() const {
   if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
     return BT->getKind() >= BuiltinType::Bool &&
            BT->getKind() <= BuiltinType::Int128;
+  return isUnscopedEnumerationType();
+}
 
+bool Type::isUnscopedEnumerationType() const {
   // Check for a complete enum type; incomplete enum types are not properly an
   // enumeration type in the sense required here.
   // C++0x: However, if the underlying type of the enum is fixed, it is

diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index aff63aef2934..910afefffb6d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5756,7 +5756,8 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
 
   // Do standard promotions between the two arguments, returning their common
   // type.
-  QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false);
+  QualType Res = UsualArithmeticConversions(
+      OrigArg0, OrigArg1, TheCall->getExprLoc(), ACK_Comparison);
   if (OrigArg0.isInvalid() || OrigArg1.isInvalid())
     return true;
 
@@ -11514,32 +11515,6 @@ static const IntegerLiteral *getIntegerLiteral(Expr *E) {
   return IL;
 }
 
-static void CheckConditionalWithEnumTypes(Sema &S, SourceLocation Loc,
-                                          Expr *LHS, Expr *RHS) {
-  QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType();
-  QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType();
-
-  const auto *LHSEnumType = LHSStrippedType->getAs<EnumType>();
-  if (!LHSEnumType)
-    return;
-  const auto *RHSEnumType = RHSStrippedType->getAs<EnumType>();
-  if (!RHSEnumType)
-    return;
-
-  // Ignore anonymous enums.
-  if (!LHSEnumType->getDecl()->hasNameForLinkage())
-    return;
-  if (!RHSEnumType->getDecl()->hasNameForLinkage())
-    return;
-
-  if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
-    return;
-
-  S.Diag(Loc, diag::warn_conditional_mixed_enum_types)
-      << LHSStrippedType << RHSStrippedType << LHS->getSourceRange()
-      << RHS->getSourceRange();
-}
-
 static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {
   E = E->IgnoreParenImpCasts();
   SourceLocation ExprLoc = E->getExprLoc();
@@ -12031,8 +12006,6 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
   bool Suspicious = false;
   CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious);
   CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious);
-  CheckConditionalWithEnumTypes(S, E->getBeginLoc(), E->getTrueExpr(),
-                                E->getFalseExpr());
 
   if (T->isBooleanType())
     DiagnoseIntInBoolContext(S, E);

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e1921f0ddf78..86c3684d03f4 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -1333,13 +1333,72 @@ static QualType handleFixedPointConversion(Sema &S, QualType LHSTy,
   return ResultTy;
 }
 
+/// Check that the usual arithmetic conversions can be performed on this pair of
+/// expressions that might be of enumeration type.
+static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS,
+                                           SourceLocation Loc,
+                                           Sema::ArithConvKind ACK) {
+  // C++2a [expr.arith.conv]p1:
+  //   If one operand is of enumeration type and the other operand is of a
+  //   
diff erent enumeration type or a floating-point type, this behavior is
+  //   deprecated ([depr.arith.conv.enum]).
+  //
+  // Warn on this in all language modes. Produce a deprecation warning in C++20.
+  // Eventually we will presumably reject these cases (in C++23 onwards?).
+  QualType L = LHS->getType(), R = RHS->getType();
+  bool LEnum = L->isUnscopedEnumerationType(),
+       REnum = R->isUnscopedEnumerationType();
+  bool IsCompAssign = ACK == Sema::ACK_CompAssign;
+  if ((!IsCompAssign && LEnum && R->isFloatingType()) ||
+      (REnum && L->isFloatingType())) {
+    S.Diag(Loc, S.getLangOpts().CPlusPlus2a
+                    ? diag::warn_arith_conv_enum_float_cxx2a
+                    : diag::warn_arith_conv_enum_float)
+        << LHS->getSourceRange() << RHS->getSourceRange()
+        << (int)ACK << LEnum << L << R;
+  } else if (!IsCompAssign && LEnum && REnum &&
+             !S.Context.hasSameUnqualifiedType(L, R)) {
+    unsigned DiagID;
+    if (!L->castAs<EnumType>()->getDecl()->hasNameForLinkage() ||
+        !R->castAs<EnumType>()->getDecl()->hasNameForLinkage()) {
+      // If either enumeration type is unnamed, it's less likely that the
+      // user cares about this, but this situation is still deprecated in
+      // C++2a. Use a 
diff erent warning group.
+      DiagID = S.getLangOpts().CPlusPlus2a
+                    ? diag::warn_arith_conv_mixed_anon_enum_types_cxx2a
+                    : diag::warn_arith_conv_mixed_anon_enum_types;
+    } else if (ACK == Sema::ACK_Conditional) {
+      // Conditional expressions are separated out because they have
+      // historically had a 
diff erent warning flag.
+      DiagID = S.getLangOpts().CPlusPlus2a
+                   ? diag::warn_conditional_mixed_enum_types_cxx2a
+                   : diag::warn_conditional_mixed_enum_types;
+    } else if (ACK == Sema::ACK_Comparison) {
+      // Comparison expressions are separated out because they have
+      // historically had a 
diff erent warning flag.
+      DiagID = S.getLangOpts().CPlusPlus2a
+                   ? diag::warn_comparison_mixed_enum_types_cxx2a
+                   : diag::warn_comparison_mixed_enum_types;
+    } else {
+      DiagID = S.getLangOpts().CPlusPlus2a
+                   ? diag::warn_arith_conv_mixed_enum_types_cxx2a
+                   : diag::warn_arith_conv_mixed_enum_types;
+    }
+    S.Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange()
+                        << (int)ACK << L << R;
+  }
+}
+
 /// UsualArithmeticConversions - Performs various conversions that are common to
 /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this
 /// routine returns the first non-arithmetic type found. The client is
 /// responsible for emitting appropriate error diagnostics.
 QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
-                                          bool IsCompAssign) {
-  if (!IsCompAssign) {
+                                          SourceLocation Loc,
+                                          ArithConvKind ACK) {
+  checkEnumArithmeticConversions(*this, LHS.get(), RHS.get(), Loc, ACK);
+
+  if (ACK != ACK_CompAssign) {
     LHS = UsualUnaryConversions(LHS.get());
     if (LHS.isInvalid())
       return QualType();
@@ -1376,7 +1435,7 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
   QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get());
   if (!LHSBitfieldPromoteTy.isNull())
     LHSType = LHSBitfieldPromoteTy;
-  if (LHSType != LHSUnpromotedType && !IsCompAssign)
+  if (LHSType != LHSUnpromotedType && ACK != ACK_CompAssign)
     LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast);
 
   // If both types are identical, no conversion is needed.
@@ -1393,24 +1452,24 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
   // Handle complex types first (C99 6.3.1.8p1).
   if (LHSType->isComplexType() || RHSType->isComplexType())
     return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType,
-                                        IsCompAssign);
+                                        ACK == ACK_CompAssign);
 
   // Now handle "real" floating types (i.e. float, double, long double).
   if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType())
     return handleFloatConversion(*this, LHS, RHS, LHSType, RHSType,
-                                 IsCompAssign);
+                                 ACK == ACK_CompAssign);
 
   // Handle GCC complex int extension.
   if (LHSType->isComplexIntegerType() || RHSType->isComplexIntegerType())
     return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType,
-                                      IsCompAssign);
+                                      ACK == ACK_CompAssign);
 
   if (LHSType->isFixedPointType() || RHSType->isFixedPointType())
     return handleFixedPointConversion(*this, LHSType, RHSType);
 
   // Finally, we have two 
diff ering integer types.
   return handleIntegerConversion<doIntegralCast, doIntegralCast>
-           (*this, LHS, RHS, LHSType, RHSType, IsCompAssign);
+           (*this, LHS, RHS, LHSType, RHSType, ACK == ACK_CompAssign);
 }
 
 //===----------------------------------------------------------------------===//
@@ -7393,7 +7452,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
                                /*AllowBothBool*/true,
                                /*AllowBoolConversions*/false);
 
-  QualType ResTy = UsualArithmeticConversions(LHS, RHS);
+  QualType ResTy =
+      UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
   if (LHS.isInvalid() || RHS.isInvalid())
     return QualType();
 
@@ -9312,7 +9372,8 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
                                /*AllowBothBool*/getLangOpts().AltiVec,
                                /*AllowBoolConversions*/false);
 
-  QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign);
+  QualType compType = UsualArithmeticConversions(
+      LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic);
   if (LHS.isInvalid() || RHS.isInvalid())
     return QualType();
 
@@ -9340,7 +9401,8 @@ QualType Sema::CheckRemainderOperands(
     return InvalidOperands(Loc, LHS, RHS);
   }
 
-  QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign);
+  QualType compType = UsualArithmeticConversions(
+      LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic);
   if (LHS.isInvalid() || RHS.isInvalid())
     return QualType();
 
@@ -9629,7 +9691,8 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
     return compType;
   }
 
-  QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy);
+  QualType compType = UsualArithmeticConversions(
+      LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic);
   if (LHS.isInvalid() || RHS.isInvalid())
     return QualType();
 
@@ -9723,7 +9786,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
     return compType;
   }
 
-  QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy);
+  QualType compType = UsualArithmeticConversions(
+      LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic);
   if (LHS.isInvalid() || RHS.isInvalid())
     return QualType();
 
@@ -10054,35 +10118,6 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
   return LHSType;
 }
 
-/// If two 
diff erent enums are compared, raise a warning.
-static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS,
-                                Expr *RHS) {
-  QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType();
-  QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType();
-
-  const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>();
-  if (!LHSEnumType)
-    return;
-  const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>();
-  if (!RHSEnumType)
-    return;
-
-  // Ignore anonymous enums.
-  if (!LHSEnumType->getDecl()->getIdentifier() &&
-      !LHSEnumType->getDecl()->getTypedefNameForAnonDecl())
-    return;
-  if (!RHSEnumType->getDecl()->getIdentifier() &&
-      !RHSEnumType->getDecl()->getTypedefNameForAnonDecl())
-    return;
-
-  if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
-    return;
-
-  S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types)
-      << LHSStrippedType << RHSStrippedType
-      << LHS->getSourceRange() << RHS->getSourceRange();
-}
-
 /// Diagnose bad pointer comparisons.
 static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc,
                                               ExprResult &LHS, ExprResult &RHS,
@@ -10380,6 +10415,19 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
     AlwaysEqual, // std::strong_ordering::equal from operator<=>
   };
 
+  // C++2a [depr.array.comp]:
+  //   Equality and relational comparisons ([expr.eq], [expr.rel]) between two
+  //   operands of array type are deprecated.
+  if (S.getLangOpts().CPlusPlus2a && LHSStripped->getType()->isArrayType() &&
+      RHSStripped->getType()->isArrayType()) {
+    S.Diag(Loc, diag::warn_depr_array_comparison)
+        << LHS->getSourceRange() << RHS->getSourceRange()
+        << LHSStripped->getType() << RHSStripped->getType();
+    // Carry on to produce the tautological comparison warning, if this
+    // expression is potentially-evaluated, we can resolve the array to a
+    // non-weak declaration, and so on.
+  }
+
   if (!LHS->getBeginLoc().isMacroID() && !RHS->getBeginLoc().isMacroID()) {
     if (Expr::isSameComparisonOperand(LHS, RHS)) {
       unsigned Result;
@@ -10558,6 +10606,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
     return QualType();
   }
 
+  // FIXME: Consider combining this with checkEnumArithmeticConversions.
   int NumEnumArgs = (int)LHSStrippedType->isEnumeralType() +
                     RHSStrippedType->isEnumeralType();
   if (NumEnumArgs == 1) {
@@ -10593,7 +10642,8 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
 
   // C++2a [expr.spaceship]p4: If both operands have arithmetic types, the
   // usual arithmetic conversions are applied to the operands.
-  QualType Type = S.UsualArithmeticConversions(LHS, RHS);
+  QualType Type =
+      S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison);
   if (LHS.isInvalid() || RHS.isInvalid())
     return QualType();
   if (Type.isNull())
@@ -10624,15 +10674,14 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
     return checkArithmeticOrEnumeralThreeWayCompare(S, LHS, RHS, Loc);
 
   // C99 6.5.8p3 / C99 6.5.9p4
-  QualType Type = S.UsualArithmeticConversions(LHS, RHS);
+  QualType Type =
+      S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison);
   if (LHS.isInvalid() || RHS.isInvalid())
     return QualType();
   if (Type.isNull())
     return S.InvalidOperands(Loc, LHS, RHS);
   assert(Type->isArithmeticType() || Type->isEnumeralType());
 
-  checkEnumComparison(S, Loc, LHS.get(), RHS.get());
-
   if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc))
     return S.InvalidOperands(Loc, LHS, RHS);
 
@@ -11335,9 +11384,13 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
   if (Opc == BO_And)
     diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc);
 
+  if (LHS.get()->getType()->hasFloatingRepresentation() ||
+      RHS.get()->getType()->hasFloatingRepresentation())
+    return InvalidOperands(Loc, LHS, RHS);
+
   ExprResult LHSResult = LHS, RHSResult = RHS;
-  QualType compType = UsualArithmeticConversions(LHSResult, RHSResult,
-                                                 IsCompAssign);
+  QualType compType = UsualArithmeticConversions(
+      LHSResult, RHSResult, Loc, IsCompAssign ? ACK_CompAssign : ACK_BitwiseOp);
   if (LHSResult.isInvalid() || RHSResult.isInvalid())
     return QualType();
   LHS = LHSResult.get();

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 9e5e49fa0f93..47b58df0acd9 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5993,7 +5993,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
   //      the usual arithmetic conversions are performed to bring them to a
   //      common type, and the result is of that type.
   if (LTy->isArithmeticType() && RTy->isArithmeticType()) {
-    QualType ResTy = UsualArithmeticConversions(LHS, RHS);
+    QualType ResTy =
+        UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
     if (LHS.isInvalid() || RHS.isInvalid())
       return QualType();
     if (ResTy.isNull()) {

diff  --git a/clang/test/CXX/expr/expr.arith.conv/p2.cpp b/clang/test/CXX/expr/expr.arith.conv/p2.cpp
new file mode 100644
index 000000000000..0df3e302d0b3
--- /dev/null
+++ b/clang/test/CXX/expr/expr.arith.conv/p2.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -verify %s -std=c++17 -Weverything -Wno-deprecated -Wno-float-equal
+// RUN: %clang_cc1 -verify %s -std=c++2a -Wdeprecated
+
+static enum E1 {} e1, e1b;
+static enum E2 {} e2;
+static double d;
+extern void f();
+extern bool b;
+
+void f() {
+  void(e1 * e1);
+  void(e1 * e2); // expected-warning {{arithmetic between 
diff erent enumeration types}}
+  void(e1 * d); // expected-warning {{arithmetic between enumeration type 'enum E1' and floating-point type 'double'}}
+  void(d * e1); // expected-warning {{arithmetic between floating-point type 'double' and enumeration type 'enum E1'}}
+
+  void(e1 + e1);
+  void(e1 + e2); // expected-warning {{arithmetic between 
diff erent enumeration types}}
+  void(e1 + d); // expected-warning {{arithmetic between enumeration type 'enum E1' and floating-point type 'double'}}
+  void(d + e1); // expected-warning {{arithmetic between floating-point type 'double' and enumeration type 'enum E1'}}
+
+#if __cplusplus > 201703L
+  void(e1 <=> e1b); // expected-error {{include <compare>}}
+  void(e1 <=> e2); // expected-error {{invalid operands}}
+  void(e1 <=> d); // expected-error {{invalid operands}}
+  void(d <=> e1); // expected-error {{invalid operands}}
+#endif
+
+  void(e1 < e1b);
+  void(e1 < e2); // expected-warning {{comparison of 
diff erent enumeration types}}
+  void(e1 < d); // expected-warning {{comparison of enumeration type 'enum E1' with floating-point type 'double'}}
+  void(d < e1); // expected-warning {{comparison of floating-point type 'double' with enumeration type 'enum E1'}}
+
+  void(e1 == e1b);
+  void(e1 == e2); // expected-warning {{comparison of 
diff erent enumeration types}}
+  void(e1 == d); // expected-warning {{comparison of enumeration type 'enum E1' with floating-point type 'double'}}
+  void(d == e1); // expected-warning {{comparison of floating-point type 'double' with enumeration type 'enum E1'}}
+
+  void(b ? e1 : e1b);
+  void(b ? e1 : e2); // expected-warning {{conditional expression between 
diff erent enumeration types}}
+  void(b ? e1 : d); // expected-warning {{conditional expression between enumeration type 'enum E1' and floating-point type 'double'}}
+  void(b ? d : e1); // expected-warning {{conditional expression between floating-point type 'double' and enumeration type 'enum E1'}}
+
+  void(e1 = e1b);
+  void(e1 = e2); // expected-error {{incompatible}}
+  void(e1 = d); // expected-error {{incompatible}}
+  void(d = e1); // FIXME: Should we warn on this?
+
+  void(e1 += e1b); // expected-error {{incompatible}}
+  void(e1 += e2); // expected-error {{incompatible}}
+  void(e1 += d); // expected-error {{incompatible}}
+  void(d += e1); // expected-warning {{compound assignment of floating-point type 'double' from enumeration type 'enum E1'}}
+}

diff  --git a/clang/test/Sema/switch.c b/clang/test/Sema/switch.c
index f704c886c96f..2c9fe915d4c4 100644
--- a/clang/test/Sema/switch.c
+++ b/clang/test/Sema/switch.c
@@ -383,7 +383,7 @@ void switch_on_ExtendedEnum1(enum ExtendedEnum1 e) {
   case EE1_b: break;
   case EE1_c: break; // no-warning
   case EE1_d: break; // expected-warning {{case value not in enumerated type 'enum ExtendedEnum1'}}
-  // expected-warning at -1 {{comparison of two values with 
diff erent enumeration types in switch statement ('enum ExtendedEnum1' and 'enum ExtendedEnum1_unrelated')}}
+  // expected-warning at -1 {{comparison of 
diff erent enumeration types in switch statement ('enum ExtendedEnum1' and 'enum ExtendedEnum1_unrelated')}}
   }
 }
 

diff  --git a/clang/test/Sema/warn-conditional-emum-types-mismatch.c b/clang/test/Sema/warn-conditional-emum-types-mismatch.c
index 12264ff89270..c9e2eddc7764 100644
--- a/clang/test/Sema/warn-conditional-emum-types-mismatch.c
+++ b/clang/test/Sema/warn-conditional-emum-types-mismatch.c
@@ -19,7 +19,7 @@ enum ExtendedStatusCodes {
 int get_flag(int cond) {
   return cond ? A : B; 
   #ifdef __cplusplus
-  // expected-warning at -2 {{enumeration type mismatch in conditional expression ('ro' and 'rw')}}
+  // expected-warning at -2 {{conditional expression between 
diff erent enumeration types ('ro' and 'rw')}}
   #else 
   // expected-no-diagnostics
   #endif

diff  --git a/clang/test/SemaCXX/deprecated.cpp b/clang/test/SemaCXX/deprecated.cpp
index b303c2b4225c..b2320c41073c 100644
--- a/clang/test/SemaCXX/deprecated.cpp
+++ b/clang/test/SemaCXX/deprecated.cpp
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -std=c++98 %s -Wno-parentheses -Wdeprecated -verify -triple x86_64-linux-gnu
-// RUN: %clang_cc1 -std=c++11 %s -Wno-parentheses -Wdeprecated -verify -triple x86_64-linux-gnu
-// RUN: %clang_cc1 -std=c++14 %s -Wno-parentheses -Wdeprecated -verify -triple x86_64-linux-gnu
-// RUN: %clang_cc1 -std=c++17 %s -Wno-parentheses -Wdeprecated -verify -triple x86_64-linux-gnu
+// RUN: %clang_cc1 -std=c++98 %s -Wno-parentheses -Wdeprecated -verify=expected,not-cxx20 -triple x86_64-linux-gnu
+// RUN: %clang_cc1 -std=c++11 %s -Wno-parentheses -Wdeprecated -verify=expected,not-cxx20 -triple x86_64-linux-gnu
+// RUN: %clang_cc1 -std=c++14 %s -Wno-parentheses -Wdeprecated -verify=expected,not-cxx20 -triple x86_64-linux-gnu
+// RUN: %clang_cc1 -std=c++17 %s -Wno-parentheses -Wdeprecated -verify=expected,not-cxx20 -triple x86_64-linux-gnu
 // RUN: %clang_cc1 -std=c++2a %s -Wno-parentheses -Wdeprecated -verify=expected,cxx20 -triple x86_64-linux-gnu
 
-// RUN: %clang_cc1 -std=c++14 %s -Wno-parentheses -Wdeprecated -verify -triple x86_64-linux-gnu -Wno-deprecated-register -DNO_DEPRECATED_FLAGS
+// RUN: %clang_cc1 -std=c++14 %s -Wno-parentheses -Wdeprecated -verify=expected,not-cxx20 -triple x86_64-linux-gnu -Wno-deprecated-register -DNO_DEPRECATED_FLAGS
 
 #include "Inputs/register.h"
 
@@ -223,5 +223,32 @@ namespace DeprecatedVolatile {
   }
 }
 
+namespace ArithConv {
+  enum E { e } e2;
+  enum F { f };
+  bool b1 = e == e2;
+  bool b2 = e == f; // not-cxx20-warning-re {{
diff erent enumeration types ('ArithConv::E' and 'ArithConv::F'){{$}}}} cxx20-warning {{F') is deprecated}}
+  bool b3 = e == 0.0; // cxx20-warning {{comparison of enumeration type 'ArithConv::E' with floating-point type 'double' is deprecated}}
+  bool b4 = 0.0 == f; // cxx20-warning {{comparison of floating-point type 'double' with enumeration type 'ArithConv::F' is deprecated}}
+  int n1 = true ? e : f; // cxx20-warning {{conditional expression between 
diff erent enumeration types ('ArithConv::E' and 'ArithConv::F') is deprecated}}
+  int n2 = true ? e : 0.0; // cxx20-warning {{conditional expression between enumeration type 'ArithConv::E' and floating-point type 'double' is deprecated}}
+}
+
+namespace ArrayComp {
+  int arr1[3], arr2[4];
+  bool b1 = arr1 == arr2; // expected-warning {{array comparison always evaluates to false}} cxx20-warning {{comparison between two arrays is deprecated}}
+  bool b2 = arr1 < arr2; // expected-warning {{array comparison always evaluates to a constant}} cxx20-warning {{comparison between two arrays is deprecated}}
+  __attribute__((weak)) int arr3[3];
+  bool b3 = arr1 == arr3; // cxx20-warning {{comparison between two arrays is deprecated}}
+  bool b4 = arr1 < arr3; // cxx20-warning {{comparison between two arrays is deprecated}}
+#if __cplusplus > 201703L
+  bool b5 = arr1 <=> arr2; // cxx20-error {{invalid operands}}
+#endif
+
+  int (&f())[3];
+  bool b6 = arr1 == f(); // cxx20-warning {{comparison between two arrays is deprecated}}
+  bool b7 = arr1 == +f();
+}
+
 # 1 "/usr/include/system-header.h" 1 3
 void system_header_function(void) throw();

diff  --git a/clang/test/SemaCXX/self-comparison.cpp b/clang/test/SemaCXX/self-comparison.cpp
index 95b830c910f5..72127f110241 100644
--- a/clang/test/SemaCXX/self-comparison.cpp
+++ b/clang/test/SemaCXX/self-comparison.cpp
@@ -15,16 +15,16 @@ struct A {
   int b[3];
   bool f() { return x == x; } // expected-warning {{self-comparison always evaluates to true}}
   bool g() { return x2 == x2; } // no-warning
-  bool h() { return a == b; } // expected-warning {{array comparison always evaluates to false}}
+  bool h() { return a == b; } // expected-warning {{array comparison always evaluates to false}} expected-warning {{deprecated}}
   bool i() {
     int c[3];
-    return a == c; // expected-warning {{array comparison always evaluates to false}}
+    return a == c; // expected-warning {{array comparison always evaluates to false}} expected-warning {{deprecated}}
   }
 };
 
 namespace NA { extern "C" int x[3]; }
 namespace NB { extern "C" int x[3]; }
-bool k = NA::x == NB::x; // expected-warning {{self-comparison always evaluates to true}}
+bool k = NA::x == NB::x; // expected-warning {{self-comparison always evaluates to true}} expected-warning {{deprecated}}
 
 template<typename T> struct Y { static inline int n; };
 bool f() {
@@ -81,7 +81,7 @@ int struct_test(S s1, S s2, S *s3, T t) {
   return s2.field == s2.field;  // expected-warning {{self-comparison always evaluates to true}}
   return s1.static_field == s2.static_field;  // expected-warning {{self-comparison always evaluates to true}}
   return S::static_field == s1.static_field;  // expected-warning {{self-comparison always evaluates to true}}
-  return s1.array == s1.array;  // expected-warning {{self-comparison always evaluates to true}}
+  return s1.array == s1.array;  // expected-warning {{self-comparison always evaluates to true}} expected-warning {{deprecated}}
   return t.s.static_field == S::static_field;  // expected-warning {{self-comparison always evaluates to true}}
   return s3->field == s3->field;  // expected-warning {{self-comparison always evaluates to true}}
   return s3->static_field == S::static_field;  // expected-warning {{self-comparison always evaluates to true}}
@@ -102,7 +102,7 @@ int struct_test(S s1, S s2, S *s3, T t) {
 
   // no warning
   return s1.field == s2.field;
-  return s2.array == s1.array;
+  return s2.array == s1.array; // FIXME: This always evaluates to false. expected-warning {{deprecated}}
   return s2.array[0] == s1.array[0];
   return s1.array[I1] == s1.array[I2];
 

diff  --git a/clang/test/SemaCXX/warn-enum-compare.cpp b/clang/test/SemaCXX/warn-enum-compare.cpp
index 21dea5dfcb00..eb777b2f6dc7 100644
--- a/clang/test/SemaCXX/warn-enum-compare.cpp
+++ b/clang/test/SemaCXX/warn-enum-compare.cpp
@@ -76,184 +76,184 @@ void test () {
   while (td == AnonAA);  // expected-warning {{comparison of constant 'AnonAA' (42) with expression of type 'TD' is always false}}
 #endif
 
-  while (B1 == B2); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
-  while (name1::B2 == name2::B3); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
-  while (z == name2::B2); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
-
-  while (((((B1)))) == B2); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
-  while (name1::B2 == (name2::B3)); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
-  while (z == ((((name2::B2))))); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
-
-  while ((((B1))) == (((B2)))); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
-  while ((name1::B2) == (((name2::B3)))); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
-  while ((((z))) == (name2::B2)); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
-
-  while (x == a); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'name1::Foo')}}
-  while (x == b); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'oneFoo' (aka 'name1::Foo'))}}
-  while (x == c); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'twoFoo' (aka 'name1::Foo'))}}
-
-  while (x == y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x != y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x >= y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x <= y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x > y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x < y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-
-  while (FooB == y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB != y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB >= y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB <= y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB > y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB < y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-
-  while (FooB == BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB != BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB >= BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB <= BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB > BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB < BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-
-  while (x == BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x != BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x >= BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x <= BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x > BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x < BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-
-  while (getFoo() == y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() != y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() >= y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() <= y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() > y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() < y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-
-  while (getFoo() == BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() != BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() >= BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() <= BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() > BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() < BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-
-  while (getFoo() == getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() != getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() >= getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() <= getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() > getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (getFoo() < getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-
-  while (FooB == getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB != getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB >= getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB <= getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB > getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (FooB < getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-
-  while (x == getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x != getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x >= getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x <= getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x > getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-  while (x < getBar()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'Bar')}}
-
-
-
-  while (y == x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y != x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y >= x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y <= x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y > x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y < x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-
-  while (y == FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y != FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y >= FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y <= FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y > FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y < FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-
-  while (BarD == FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD != FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD >= FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD <= FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD > FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD <FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-
-  while (BarD == x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD != x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD >= x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD <= x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD < x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD > x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-
-  while (y == getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y != getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y >= getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y <= getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y > getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (y < getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-
-  while (BarD == getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD != getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD >= getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD <= getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD > getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (BarD < getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-
-  while (getBar() == getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() != getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() >= getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() <= getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() > getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() < getFoo()); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-
-  while (getBar() == FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() != FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() >= FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() <= FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() > FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() < FooB); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-
-  while (getBar() == x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() != x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() >= x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() <= x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() > x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-  while (getBar() < x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'Foo')}}
-
-  while (td == FooA); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('TD' and 'Foo')}}
-  while (td == BarD); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('TD' and 'Bar')}}
-  while (name1::F1 == td); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Foo' and 'TD')}}
-  while (name2::B1 == td); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name2::Baz' and 'TD')}}
-  while (td == a); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('TD' and 'name1::Foo')}}
-  while (td == b); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('TD' and 'oneFoo' (aka 'name1::Foo'))}}
-  while (td == c); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('TD' and 'twoFoo' (aka 'name1::Foo'))}}
-  while (td == x); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('TD' and 'Foo')}}
-  while (td == y); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('TD' and 'Bar')}}
-  while (td == z); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('TD' and 'name1::Baz')}}
-
-  while (a == TD1); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Foo' and 'TD')}}
-  while (b == TD2); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('oneFoo' (aka 'name1::Foo') and 'TD')}}
-  while (c == TD1); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('twoFoo' (aka 'name1::Foo') and 'TD')}}
-  while (x == TD2); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Foo' and 'TD')}}
-  while (y == TD1); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('Bar' and 'TD')}}
-  while (z == TD2); // expected-warning  {{comparison of two values with 
diff erent enumeration types ('name1::Baz' and 'TD')}}
+  while (B1 == B2); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
+  while (name1::B2 == name2::B3); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
+  while (z == name2::B2); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
+
+  while (((((B1)))) == B2); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
+  while (name1::B2 == (name2::B3)); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
+  while (z == ((((name2::B2))))); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
+
+  while ((((B1))) == (((B2)))); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
+  while ((name1::B2) == (((name2::B3)))); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
+  while ((((z))) == (name2::B2)); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Baz' and 'name2::Baz')}}
+
+  while (x == a); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'name1::Foo')}}
+  while (x == b); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'oneFoo' (aka 'name1::Foo'))}}
+  while (x == c); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'twoFoo' (aka 'name1::Foo'))}}
+
+  while (x == y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x != y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x >= y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x <= y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x > y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x < y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+
+  while (FooB == y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB != y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB >= y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB <= y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB > y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB < y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+
+  while (FooB == BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB != BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB >= BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB <= BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB > BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB < BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+
+  while (x == BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x != BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x >= BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x <= BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x > BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x < BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+
+  while (getFoo() == y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() != y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() >= y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() <= y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() > y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() < y); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+
+  while (getFoo() == BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() != BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() >= BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() <= BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() > BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() < BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+
+  while (getFoo() == getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() != getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() >= getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() <= getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() > getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (getFoo() < getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+
+  while (FooB == getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB != getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB >= getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB <= getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB > getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (FooB < getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+
+  while (x == getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x != getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x >= getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x <= getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x > getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+  while (x < getBar()); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'Bar')}}
+
+
+
+  while (y == x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y != x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y >= x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y <= x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y > x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y < x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+
+  while (y == FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y != FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y >= FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y <= FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y > FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y < FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+
+  while (BarD == FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD != FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD >= FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD <= FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD > FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD <FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+
+  while (BarD == x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD != x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD >= x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD <= x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD < x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD > x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+
+  while (y == getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y != getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y >= getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y <= getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y > getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (y < getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+
+  while (BarD == getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD != getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD >= getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD <= getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD > getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (BarD < getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+
+  while (getBar() == getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() != getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() >= getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() <= getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() > getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() < getFoo()); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+
+  while (getBar() == FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() != FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() >= FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() <= FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() > FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() < FooB); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+
+  while (getBar() == x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() != x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() >= x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() <= x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() > x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+  while (getBar() < x); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'Foo')}}
+
+  while (td == FooA); // expected-warning  {{comparison of 
diff erent enumeration types ('TD' and 'Foo')}}
+  while (td == BarD); // expected-warning  {{comparison of 
diff erent enumeration types ('TD' and 'Bar')}}
+  while (name1::F1 == td); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Foo' and 'TD')}}
+  while (name2::B1 == td); // expected-warning  {{comparison of 
diff erent enumeration types ('name2::Baz' and 'TD')}}
+  while (td == a); // expected-warning  {{comparison of 
diff erent enumeration types ('TD' and 'name1::Foo')}}
+  while (td == b); // expected-warning  {{comparison of 
diff erent enumeration types ('TD' and 'oneFoo' (aka 'name1::Foo'))}}
+  while (td == c); // expected-warning  {{comparison of 
diff erent enumeration types ('TD' and 'twoFoo' (aka 'name1::Foo'))}}
+  while (td == x); // expected-warning  {{comparison of 
diff erent enumeration types ('TD' and 'Foo')}}
+  while (td == y); // expected-warning  {{comparison of 
diff erent enumeration types ('TD' and 'Bar')}}
+  while (td == z); // expected-warning  {{comparison of 
diff erent enumeration types ('TD' and 'name1::Baz')}}
+
+  while (a == TD1); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Foo' and 'TD')}}
+  while (b == TD2); // expected-warning  {{comparison of 
diff erent enumeration types ('oneFoo' (aka 'name1::Foo') and 'TD')}}
+  while (c == TD1); // expected-warning  {{comparison of 
diff erent enumeration types ('twoFoo' (aka 'name1::Foo') and 'TD')}}
+  while (x == TD2); // expected-warning  {{comparison of 
diff erent enumeration types ('Foo' and 'TD')}}
+  while (y == TD1); // expected-warning  {{comparison of 
diff erent enumeration types ('Bar' and 'TD')}}
+  while (z == TD2); // expected-warning  {{comparison of 
diff erent enumeration types ('name1::Baz' and 'TD')}}
 
   switch (a) {
     case name1::F1: break;
     case name1::F3: break;
-    case name2::B2: break; // expected-warning {{comparison of two values with 
diff erent enumeration types in switch statement ('name1::Foo' and 'name2::Baz')}}
+    case name2::B2: break; // expected-warning {{comparison of 
diff erent enumeration types in switch statement ('name1::Foo' and 'name2::Baz')}}
   }
 
   switch (x) {
     case FooB: break;
     case FooC: break;
-    case BarD: break; // expected-warning {{comparison of two values with 
diff erent enumeration types in switch statement ('Foo' and 'Bar')}}
+    case BarD: break; // expected-warning {{comparison of 
diff erent enumeration types in switch statement ('Foo' and 'Bar')}}
   }
 
   switch(getBar()) {
     case BarE: break;
     case BarF: break;
-    case FooA: break; // expected-warning {{comparison of two values with 
diff erent enumeration types in switch statement ('Bar' and 'Foo')}}
+    case FooA: break; // expected-warning {{comparison of 
diff erent enumeration types in switch statement ('Bar' and 'Foo')}}
   }
 
   switch(x) {
@@ -265,8 +265,8 @@ void test () {
 
   switch (td) {
     case TD1: break;
-    case FooB: break; // expected-warning {{comparison of two values with 
diff erent enumeration types in switch statement ('TD' and 'Foo')}}
-    case BarF: break; // expected-warning {{comparison of two values with 
diff erent enumeration types in switch statement ('TD' and 'Bar')}}
+    case FooB: break; // expected-warning {{comparison of 
diff erent enumeration types in switch statement ('TD' and 'Foo')}}
+    case BarF: break; // expected-warning {{comparison of 
diff erent enumeration types in switch statement ('TD' and 'Bar')}}
     // expected-warning at -1 {{case value not in enumerated type 'TD'}}
     case AnonAA: break; // expected-warning {{case value not in enumerated type 'TD'}}
   }
@@ -277,8 +277,8 @@ void test () {
   }
 
   switch (a) {
-    case TD1: break; // expected-warning {{comparison of two values with 
diff erent enumeration types in switch statement ('name1::Foo' and 'TD')}}
-    case TD2: break; // expected-warning {{comparison of two values with 
diff erent enumeration types in switch statement ('name1::Foo' and 'TD')}}
+    case TD1: break; // expected-warning {{comparison of 
diff erent enumeration types in switch statement ('name1::Foo' and 'TD')}}
+    case TD2: break; // expected-warning {{comparison of 
diff erent enumeration types in switch statement ('name1::Foo' and 'TD')}}
     case name1::F3: break;
   }
 }

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 3f7cfd1308bf..0829a2b1298b 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -926,18 +926,16 @@ <h2 id="cxx20">C++2a implementation status</h2>
     <tr>
       <td rowspan="8">Consistent comparison (<tt>operator<=></tt>)</td>
       <td><a href="https://wg21.link/p0515r3">P0515R3</a></td>
-      <td rowspan="2" class="svn" align="center">SVN</td>
+      <td rowspan="7" class="svn" align="center">SVN</td>
     </tr>
       <tr> <!-- from Jacksonville -->
         <td><a href="https://wg21.link/p0905r1">P0905R1</a></td>
       </tr>
       <tr> <!-- from Rapperswil -->
         <td><a href="https://wg21.link/p1120r0">P1120R0</a></td>
-        <td class="partial" align="center">Partial</td>
       </tr>
       <tr> <!-- from Kona 2019 -->
         <td><a href="https://wg21.link/p1185r2">P1185R2</a></td>
-        <td rowspan="4" class="svn" align="center">SVN</td>
       </tr>
       <tr> <!-- from Cologne -->
         <td><a href="https://wg21.link/p1186r3">P1186R3</a></td>


        


More information about the cfe-commits mailing list