diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1973,6 +1973,7 @@ /// 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 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -60,7 +60,27 @@ 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 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 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 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 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6219,6 +6219,52 @@ "%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, 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; +def warn_arith_conv_mixed_enum_types : Warning< + "%sub{select_arith_conv_kind}0 " + "different enumeration types%diff{ ($ and $)|}1,2">, + InGroup, 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; +def warn_arith_conv_mixed_anon_enum_types : Warning< + warn_arith_conv_mixed_enum_types.Text>, + InGroup, DefaultIgnore; +def warn_arith_conv_mixed_anon_enum_types_cxx2a : Warning< + warn_arith_conv_mixed_enum_types_cxx2a.Text>, + InGroup; +def warn_conditional_mixed_enum_types : Warning< + warn_arith_conv_mixed_enum_types.Text>, + InGroup, DefaultIgnore; +def warn_conditional_mixed_enum_types_cxx2a : Warning< + warn_arith_conv_mixed_enum_types_cxx2a.Text>, + InGroup; +def warn_comparison_mixed_enum_types : Warning< + warn_arith_conv_mixed_enum_types.Text>, + InGroup; +def warn_comparison_mixed_enum_types_cxx2a : Warning< + warn_arith_conv_mixed_enum_types_cxx2a.Text>, + InGroup; +def warn_comparison_of_mixed_enum_types_switch : Warning< + "comparison of different enumeration types in switch statement" + "%diff{ ($ and $)|}0,1">, + InGroup; + def err_typecheck_assign_const : Error< "%select{" "cannot assign to return value because function %1 returns a const value|" @@ -6272,18 +6318,6 @@ "converting the result of '<<' to a boolean always evaluates " "to %select{false|true}0">, InGroup; -def warn_comparison_of_mixed_enum_types : Warning< - "comparison of two values with different enumeration types" - "%diff{ ($ and $)|}0,1">, - InGroup; -def warn_conditional_mixed_enum_types : Warning< - "enumeration type mismatch in conditional expression" - "%diff{ ($ and $)|}0,1">, - InGroup, 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; def warn_null_in_arithmetic_operation : Warning< "use of NULL in arithmetic operation">, InGroup; @@ -8507,6 +8541,10 @@ def warn_tautological_overlap_comparison : Warning< "overlapping comparisons always evaluate to %select{false|true}0">, InGroup, 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; 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 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10344,13 +10344,27 @@ 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 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1856,7 +1856,10 @@ if (const auto *BT = dyn_cast(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 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -5756,7 +5756,8 @@ // 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 @@ 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(); - if (!LHSEnumType) - return; - const auto *RHSEnumType = RHSStrippedType->getAs(); - 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 @@ 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 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1333,13 +1333,72 @@ 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()->getDecl()->hasNameForLinkage() || + !R->castAs()->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 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 @@ // 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 - (*this, LHS, RHS, LHSType, RHSType, IsCompAssign); + (*this, LHS, RHS, LHSType, RHSType, ACK == ACK_CompAssign); } //===----------------------------------------------------------------------===// @@ -7393,7 +7452,8 @@ /*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 @@ /*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 @@ 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 @@ 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 @@ 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 @@ 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(); - if (!LHSEnumType) - return; - const EnumType *RHSEnumType = RHSStrippedType->getAs(); - 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 @@ 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 @@ return QualType(); } + // FIXME: Consider combining this with checkEnumArithmeticConversions. int NumEnumArgs = (int)LHSStrippedType->isEnumeralType() + RHSStrippedType->isEnumeralType(); if (NumEnumArgs == 1) { @@ -10593,7 +10642,8 @@ // 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 @@ 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 @@ 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 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5993,7 +5993,8 @@ // 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 --- /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 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 }} + 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'}} +} diff --git a/clang/test/Sema/switch.c b/clang/test/Sema/switch.c --- a/clang/test/Sema/switch.c +++ b/clang/test/Sema/switch.c @@ -383,7 +383,7 @@ 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')}} } } diff --git a/clang/test/Sema/warn-conditional-emum-types-mismatch.c b/clang/test/Sema/warn-conditional-emum-types-mismatch.c --- a/clang/test/Sema/warn-conditional-emum-types-mismatch.c +++ b/clang/test/Sema/warn-conditional-emum-types-mismatch.c @@ -19,7 +19,7 @@ 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 diff --git a/clang/test/SemaCXX/deprecated.cpp b/clang/test/SemaCXX/deprecated.cpp --- 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 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(); diff --git a/clang/test/SemaCXX/self-comparison.cpp b/clang/test/SemaCXX/self-comparison.cpp --- a/clang/test/SemaCXX/self-comparison.cpp +++ b/clang/test/SemaCXX/self-comparison.cpp @@ -15,16 +15,16 @@ 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 struct Y { static inline int n; }; bool f() { @@ -81,7 +81,7 @@ 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 @@ // 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 --- a/clang/test/SemaCXX/warn-enum-compare.cpp +++ b/clang/test/SemaCXX/warn-enum-compare.cpp @@ -76,184 +76,184 @@ 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 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 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 (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 == 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 (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 == 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 (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 (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() == 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() == 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 (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 (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 (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 == 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 (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 = 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 (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 (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 (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() == 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() == 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 (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 (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 (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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 @@ 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 @@ } 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; } } diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -926,18 +926,16 @@ Consistent comparison (operator<=>) P0515R3 - SVN + SVN P0905R1 P1120R0 - Partial P1185R2 - SVN P1186R3