[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).
This commit is contained in:
Richard Smith 2019-12-16 15:17:24 -08:00
parent 434905b97d
commit 4b00299958
15 changed files with 437 additions and 253 deletions

View File

@ -1973,6 +1973,7 @@ public:
/// 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)

View File

@ -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",

View File

@ -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 "
"different enumeration types%diff{ ($ and $)|}1,2">,
InGroup<EnumEnumConversion>, DefaultIgnore;
def warn_arith_conv_mixed_enum_types_cxx2a : Warning<
"%sub{select_arith_conv_kind}0 "
"different 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 different 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 different 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 different 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 "

View File

@ -10344,13 +10344,27 @@ public:
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

View File

@ -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

View File

@ -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);

View File

@ -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
// different 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 different 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 different 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 different 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 differing 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 different 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();

View File

@ -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()) {

View File

@ -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 different 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 different 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 different 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 different 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 different 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'}}
}

View File

@ -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@-1 {{comparison of two values with different enumeration types in switch statement ('enum ExtendedEnum1' and 'enum ExtendedEnum1_unrelated')}}
// expected-warning@-1 {{comparison of different enumeration types in switch statement ('enum ExtendedEnum1' and 'enum ExtendedEnum1_unrelated')}}
}
}

View File

@ -19,7 +19,7 @@ enum ExtendedStatusCodes {
int get_flag(int cond) {
return cond ? A : B;
#ifdef __cplusplus
// expected-warning@-2 {{enumeration type mismatch in conditional expression ('ro' and 'rw')}}
// expected-warning@-2 {{conditional expression between different enumeration types ('ro' and 'rw')}}
#else
// expected-no-diagnostics
#endif

View File

@ -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 {{different 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 different 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();

View File

@ -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];

View File

@ -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 different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (name1::B2 == name2::B3); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (z == name2::B2); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (B1 == B2); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (name1::B2 == name2::B3); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (z == name2::B2); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (((((B1)))) == B2); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (name1::B2 == (name2::B3)); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (z == ((((name2::B2))))); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (((((B1)))) == B2); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (name1::B2 == (name2::B3)); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (z == ((((name2::B2))))); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}}
while ((((B1))) == (((B2)))); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'name2::Baz')}}
while ((name1::B2) == (((name2::B3)))); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'name2::Baz')}}
while ((((z))) == (name2::B2)); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'name2::Baz')}}
while ((((B1))) == (((B2)))); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}}
while ((name1::B2) == (((name2::B3)))); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}}
while ((((z))) == (name2::B2)); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}}
while (x == a); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'name1::Foo')}}
while (x == b); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'oneFoo' (aka 'name1::Foo'))}}
while (x == c); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'twoFoo' (aka 'name1::Foo'))}}
while (x == a); // expected-warning {{comparison of different enumeration types ('Foo' and 'name1::Foo')}}
while (x == b); // expected-warning {{comparison of different enumeration types ('Foo' and 'oneFoo' (aka 'name1::Foo'))}}
while (x == c); // expected-warning {{comparison of different enumeration types ('Foo' and 'twoFoo' (aka 'name1::Foo'))}}
while (x == y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x != y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x >= y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x <= y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x > y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x < y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x == y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x != y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x >= y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x <= y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x > y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x < y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB == y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB != y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB >= y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB <= y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB > y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB < y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB == y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB != y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB >= y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB <= y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB > y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB < y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB == BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB != BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB >= BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB <= BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB > BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB < BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB == BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB != BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB >= BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB <= BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB > BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB < BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x == BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x != BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x >= BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x <= BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x > BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x < BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x == BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x != BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x >= BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x <= BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x > BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x < BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() == y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() != y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() >= y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() <= y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() > y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() < y); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() == y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() != y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() >= y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() <= y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() > y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() < y); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() == BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() != BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() >= BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() <= BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() > BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() < BarD); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() == BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() != BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() >= BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() <= BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() > BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() < BarD); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() == getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() != getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() >= getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() <= getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() > getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() < getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (getFoo() == getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() != getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() >= getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() <= getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() > getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (getFoo() < getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB == getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB != getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB >= getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB <= getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB > getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB < getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (FooB == getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB != getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB >= getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB <= getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB > getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (FooB < getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x == getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x != getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x >= getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x <= getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x > getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x < getBar()); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}}
while (x == getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x != getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x >= getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x <= getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x > getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (x < getBar()); // expected-warning {{comparison of different enumeration types ('Foo' and 'Bar')}}
while (y == x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y != x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y >= x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y <= x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y > x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y < x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y == x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y != x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y >= x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y <= x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y > x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y < x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y == FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y != FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y >= FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y <= FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y > FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y < FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y == FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y != FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y >= FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y <= FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y > FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y < FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD == FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD != FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD >= FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD <= FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD > FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD <FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD == FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD != FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD >= FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD <= FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD > FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD <FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD == x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD != x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD >= x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD <= x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD < x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD > x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD == x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD != x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD >= x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD <= x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD < x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD > x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y == getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y != getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y >= getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y <= getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y > getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y < getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (y == getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y != getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y >= getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y <= getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y > getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (y < getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD == getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD != getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD >= getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD <= getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD > getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD < getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (BarD == getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD != getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD >= getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD <= getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD > getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (BarD < getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() == getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() != getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() >= getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() <= getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() > getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() < getFoo()); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() == getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() != getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() >= getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() <= getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() > getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() < getFoo()); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() == FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() != FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() >= FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() <= FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() > FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() < FooB); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() == FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() != FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() >= FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() <= FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() > FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() < FooB); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() == x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() != x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() >= x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() <= x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() > x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() < x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}}
while (getBar() == x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() != x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() >= x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() <= x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() > x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (getBar() < x); // expected-warning {{comparison of different enumeration types ('Bar' and 'Foo')}}
while (td == FooA); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'Foo')}}
while (td == BarD); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'Bar')}}
while (name1::F1 == td); // expected-warning {{comparison of two values with different enumeration types ('name1::Foo' and 'TD')}}
while (name2::B1 == td); // expected-warning {{comparison of two values with different enumeration types ('name2::Baz' and 'TD')}}
while (td == a); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'name1::Foo')}}
while (td == b); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'oneFoo' (aka 'name1::Foo'))}}
while (td == c); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'twoFoo' (aka 'name1::Foo'))}}
while (td == x); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'Foo')}}
while (td == y); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'Bar')}}
while (td == z); // expected-warning {{comparison of two values with different enumeration types ('TD' and 'name1::Baz')}}
while (td == FooA); // expected-warning {{comparison of different enumeration types ('TD' and 'Foo')}}
while (td == BarD); // expected-warning {{comparison of different enumeration types ('TD' and 'Bar')}}
while (name1::F1 == td); // expected-warning {{comparison of different enumeration types ('name1::Foo' and 'TD')}}
while (name2::B1 == td); // expected-warning {{comparison of different enumeration types ('name2::Baz' and 'TD')}}
while (td == a); // expected-warning {{comparison of different enumeration types ('TD' and 'name1::Foo')}}
while (td == b); // expected-warning {{comparison of different enumeration types ('TD' and 'oneFoo' (aka 'name1::Foo'))}}
while (td == c); // expected-warning {{comparison of different enumeration types ('TD' and 'twoFoo' (aka 'name1::Foo'))}}
while (td == x); // expected-warning {{comparison of different enumeration types ('TD' and 'Foo')}}
while (td == y); // expected-warning {{comparison of different enumeration types ('TD' and 'Bar')}}
while (td == z); // expected-warning {{comparison of different enumeration types ('TD' and 'name1::Baz')}}
while (a == TD1); // expected-warning {{comparison of two values with different enumeration types ('name1::Foo' and 'TD')}}
while (b == TD2); // expected-warning {{comparison of two values with different enumeration types ('oneFoo' (aka 'name1::Foo') and 'TD')}}
while (c == TD1); // expected-warning {{comparison of two values with different enumeration types ('twoFoo' (aka 'name1::Foo') and 'TD')}}
while (x == TD2); // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'TD')}}
while (y == TD1); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'TD')}}
while (z == TD2); // expected-warning {{comparison of two values with different enumeration types ('name1::Baz' and 'TD')}}
while (a == TD1); // expected-warning {{comparison of different enumeration types ('name1::Foo' and 'TD')}}
while (b == TD2); // expected-warning {{comparison of different enumeration types ('oneFoo' (aka 'name1::Foo') and 'TD')}}
while (c == TD1); // expected-warning {{comparison of different enumeration types ('twoFoo' (aka 'name1::Foo') and 'TD')}}
while (x == TD2); // expected-warning {{comparison of different enumeration types ('Foo' and 'TD')}}
while (y == TD1); // expected-warning {{comparison of different enumeration types ('Bar' and 'TD')}}
while (z == TD2); // expected-warning {{comparison of different 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 different enumeration types in switch statement ('name1::Foo' and 'name2::Baz')}}
case name2::B2: break; // expected-warning {{comparison of different 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 different enumeration types in switch statement ('Foo' and 'Bar')}}
case BarD: break; // expected-warning {{comparison of different 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 different enumeration types in switch statement ('Bar' and 'Foo')}}
case FooA: break; // expected-warning {{comparison of different 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 different enumeration types in switch statement ('TD' and 'Foo')}}
case BarF: break; // expected-warning {{comparison of two values with different enumeration types in switch statement ('TD' and 'Bar')}}
case FooB: break; // expected-warning {{comparison of different enumeration types in switch statement ('TD' and 'Foo')}}
case BarF: break; // expected-warning {{comparison of different enumeration types in switch statement ('TD' and 'Bar')}}
// expected-warning@-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 different enumeration types in switch statement ('name1::Foo' and 'TD')}}
case TD2: break; // expected-warning {{comparison of two values with different enumeration types in switch statement ('name1::Foo' and 'TD')}}
case TD1: break; // expected-warning {{comparison of different enumeration types in switch statement ('name1::Foo' and 'TD')}}
case TD2: break; // expected-warning {{comparison of different enumeration types in switch statement ('name1::Foo' and 'TD')}}
case name1::F3: break;
}
}

View File

@ -926,18 +926,16 @@ as the draft C++2a standard evolves.
<tr>
<td rowspan="8">Consistent comparison (<tt>operator&lt;=&gt;</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>