Skip to content

Commit 8b5503d

Browse files
authored
[Clang] Add diagnostic when scoped enumeration requires an explicit conversion for binary operations (#152698)
```diff main.cpp:4:8: error: invalid operands to binary expression ('E' and 'int') 4 | E::e + 0; | ~~~~ ^ ~ +main.cpp:4:3: note: no implicit conversion for scoped enum; consider casting to underlying type + 4 | E::e + 0; + | ^ + | static_cast<int>( ) ``` Resolves #24265
1 parent 5b5a8cd commit 8b5503d

File tree

8 files changed

+306
-32
lines changed

8 files changed

+306
-32
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ Improvements to Clang's diagnostics
209209
an override of a virtual method.
210210
- Fixed fix-it hint for fold expressions. Clang now correctly places the suggested right
211211
parenthesis when diagnosing malformed fold expressions. (#GH151787)
212+
- Added fix-it hint for when scoped enumerations require explicit conversions for binary operations. (#GH24265)
212213

213214
- Fixed an issue where emitted format-signedness diagnostics were not associated with an appropriate
214215
diagnostic id. Besides being incorrect from an API standpoint, this was user visible, e.g.:

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4407,6 +4407,11 @@ def warn_impcast_different_enum_types : Warning<
44074407
def warn_impcast_int_to_enum : Warning<
44084408
"implicit conversion from %0 to enumeration type %1 is invalid in C++">,
44094409
InGroup<ImplicitIntToEnumCast>, DefaultIgnore;
4410+
4411+
def note_no_implicit_conversion_for_scoped_enum
4412+
: Note<"no implicit conversion for scoped enum; consider casting to "
4413+
"underlying type">;
4414+
44104415
def warn_impcast_bool_to_null_pointer : Warning<
44114416
"initialization of pointer of type %0 to null from a constant boolean "
44124417
"expression">, InGroup<BoolConversion>;

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8065,8 +8065,8 @@ class Sema final : public SemaBase {
80658065
ExprResult &RHS);
80668066

80678067
QualType CheckMultiplyDivideOperands( // C99 6.5.5
8068-
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign,
8069-
bool IsDivide);
8068+
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
8069+
BinaryOperatorKind Opc);
80708070
QualType CheckRemainderOperands( // C99 6.5.5
80718071
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
80728072
bool IsCompAssign = false);
@@ -8075,7 +8075,7 @@ class Sema final : public SemaBase {
80758075
BinaryOperatorKind Opc, QualType *CompLHSTy = nullptr);
80768076
QualType CheckSubtractionOperands( // C99 6.5.6
80778077
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
8078-
QualType *CompLHSTy = nullptr);
8078+
BinaryOperatorKind Opc, QualType *CompLHSTy = nullptr);
80798079
QualType CheckShiftOperands( // C99 6.5.7
80808080
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
80818081
BinaryOperatorKind Opc, bool IsCompAssign = false);

clang/lib/Sema/SemaExpr.cpp

Lines changed: 93 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10748,9 +10748,50 @@ static void DiagnoseBadDivideOrRemainderValues(Sema& S, ExprResult &LHS,
1074810748
<< IsDiv << RHS.get()->getSourceRange());
1074910749
}
1075010750

10751+
static void diagnoseScopedEnums(Sema &S, const SourceLocation Loc,
10752+
const ExprResult &LHS, const ExprResult &RHS,
10753+
BinaryOperatorKind Opc) {
10754+
if (!LHS.isUsable() || !RHS.isUsable())
10755+
return;
10756+
const Expr *LHSExpr = LHS.get();
10757+
const Expr *RHSExpr = RHS.get();
10758+
const QualType LHSType = LHSExpr->getType();
10759+
const QualType RHSType = RHSExpr->getType();
10760+
const bool LHSIsScoped = LHSType->isScopedEnumeralType();
10761+
const bool RHSIsScoped = RHSType->isScopedEnumeralType();
10762+
if (!LHSIsScoped && !RHSIsScoped)
10763+
return;
10764+
if (BinaryOperator::isAssignmentOp(Opc) && LHSIsScoped)
10765+
return;
10766+
if (!LHSIsScoped && !LHSType->isIntegralOrUnscopedEnumerationType())
10767+
return;
10768+
if (!RHSIsScoped && !RHSType->isIntegralOrUnscopedEnumerationType())
10769+
return;
10770+
auto DiagnosticHelper = [&S](const Expr *expr, const QualType type) {
10771+
SourceLocation BeginLoc = expr->getBeginLoc();
10772+
QualType IntType = type->castAs<EnumType>()
10773+
->getOriginalDecl()
10774+
->getDefinitionOrSelf()
10775+
->getIntegerType();
10776+
std::string InsertionString = "static_cast<" + IntType.getAsString() + ">(";
10777+
S.Diag(BeginLoc, diag::note_no_implicit_conversion_for_scoped_enum)
10778+
<< FixItHint::CreateInsertion(BeginLoc, InsertionString)
10779+
<< FixItHint::CreateInsertion(expr->getEndLoc(), ")");
10780+
};
10781+
if (LHSIsScoped) {
10782+
DiagnosticHelper(LHSExpr, LHSType);
10783+
}
10784+
if (RHSIsScoped) {
10785+
DiagnosticHelper(RHSExpr, RHSType);
10786+
}
10787+
}
10788+
1075110789
QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
1075210790
SourceLocation Loc,
10753-
bool IsCompAssign, bool IsDiv) {
10791+
BinaryOperatorKind Opc) {
10792+
bool IsCompAssign = Opc == BO_MulAssign || Opc == BO_DivAssign;
10793+
bool IsDiv = Opc == BO_Div || Opc == BO_DivAssign;
10794+
1075410795
checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false);
1075510796

1075610797
QualType LHSTy = LHS.get()->getType();
@@ -10778,9 +10819,11 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
1077810819
if (LHS.isInvalid() || RHS.isInvalid())
1077910820
return QualType();
1078010821

10781-
10782-
if (compType.isNull() || !compType->isArithmeticType())
10783-
return InvalidOperands(Loc, LHS, RHS);
10822+
if (compType.isNull() || !compType->isArithmeticType()) {
10823+
QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
10824+
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
10825+
return ResultTy;
10826+
}
1078410827
if (IsDiv) {
1078510828
DetectPrecisionLossInComplexDivision(*this, RHS.get()->getType(), Loc);
1078610829
DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, IsDiv);
@@ -10843,8 +10886,12 @@ QualType Sema::CheckRemainderOperands(
1084310886

1084410887
if (compType.isNull() ||
1084510888
(!compType->isIntegerType() &&
10846-
!(getLangOpts().HLSL && compType->isFloatingType())))
10847-
return InvalidOperands(Loc, LHS, RHS);
10889+
!(getLangOpts().HLSL && compType->isFloatingType()))) {
10890+
QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
10891+
diagnoseScopedEnums(*this, Loc, LHS, RHS,
10892+
IsCompAssign ? BO_RemAssign : BO_Rem);
10893+
return ResultTy;
10894+
}
1084810895
DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, false /* IsDiv */);
1084910896
return compType;
1085010897
}
@@ -11200,7 +11247,9 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
1120011247
} else if (PExp->getType()->isObjCObjectPointerType()) {
1120111248
isObjCPointer = true;
1120211249
} else {
11203-
return InvalidOperands(Loc, LHS, RHS);
11250+
QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
11251+
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
11252+
return ResultTy;
1120411253
}
1120511254
}
1120611255
assert(PExp->getType()->isAnyPointerType());
@@ -11257,7 +11306,8 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
1125711306
// C99 6.5.6
1125811307
QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
1125911308
SourceLocation Loc,
11260-
QualType* CompLHSTy) {
11309+
BinaryOperatorKind Opc,
11310+
QualType *CompLHSTy) {
1126111311
checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false);
1126211312

1126311313
if (LHS.get()->getType()->isVectorType() ||
@@ -11402,7 +11452,9 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
1140211452
}
1140311453
}
1140411454

11405-
return InvalidOperands(Loc, LHS, RHS);
11455+
QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
11456+
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
11457+
return ResultTy;
1140611458
}
1140711459

1140811460
static bool isScopedEnumerationType(QualType T) {
@@ -11750,8 +11802,11 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
1175011802
// Embedded-C 4.1.6.2.2: The LHS may also be fixed-point.
1175111803
if ((!LHSType->isFixedPointOrIntegerType() &&
1175211804
!LHSType->hasIntegerRepresentation()) ||
11753-
!RHSType->hasIntegerRepresentation())
11754-
return InvalidOperands(Loc, LHS, RHS);
11805+
!RHSType->hasIntegerRepresentation()) {
11806+
QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
11807+
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
11808+
return ResultTy;
11809+
}
1175511810

1175611811
// C++0x: Don't allow scoped enums. FIXME: Use something better than
1175711812
// hasIntegerRepresentation() above instead of this.
@@ -12319,8 +12374,11 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
1231912374
S.UsualArithmeticConversions(LHS, RHS, Loc, ArithConvKind::Comparison);
1232012375
if (LHS.isInvalid() || RHS.isInvalid())
1232112376
return QualType();
12322-
if (Type.isNull())
12323-
return S.InvalidOperands(Loc, LHS, RHS);
12377+
if (Type.isNull()) {
12378+
QualType ResultTy = S.InvalidOperands(Loc, LHS, RHS);
12379+
diagnoseScopedEnums(S, Loc, LHS, RHS, BO_Cmp);
12380+
return ResultTy;
12381+
}
1232412382

1232512383
std::optional<ComparisonCategoryType> CCT =
1232612384
getComparisonCategoryForBuiltinCmp(Type);
@@ -12352,8 +12410,11 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
1235212410
S.UsualArithmeticConversions(LHS, RHS, Loc, ArithConvKind::Comparison);
1235312411
if (LHS.isInvalid() || RHS.isInvalid())
1235412412
return QualType();
12355-
if (Type.isNull())
12356-
return S.InvalidOperands(Loc, LHS, RHS);
12413+
if (Type.isNull()) {
12414+
QualType ResultTy = S.InvalidOperands(Loc, LHS, RHS);
12415+
diagnoseScopedEnums(S, Loc, LHS, RHS, Opc);
12416+
return ResultTy;
12417+
}
1235712418
assert(Type->isArithmeticType() || Type->isEnumeralType());
1235812419

1235912420
if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc))
@@ -13363,7 +13424,9 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
1336313424

1336413425
if (!compType.isNull() && compType->isIntegralOrUnscopedEnumerationType())
1336513426
return compType;
13366-
return InvalidOperands(Loc, LHS, RHS);
13427+
QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
13428+
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
13429+
return ResultTy;
1336713430
}
1336813431

1336913432
// C99 6.5.[13,14]
@@ -13465,13 +13528,19 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
1346513528
// C++ [expr.log.or]p1
1346613529
// The operands are both contextually converted to type bool.
1346713530
ExprResult LHSRes = PerformContextuallyConvertToBool(LHS.get());
13468-
if (LHSRes.isInvalid())
13469-
return InvalidOperands(Loc, LHS, RHS);
13531+
if (LHSRes.isInvalid()) {
13532+
QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
13533+
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
13534+
return ResultTy;
13535+
}
1347013536
LHS = LHSRes;
1347113537

1347213538
ExprResult RHSRes = PerformContextuallyConvertToBool(RHS.get());
13473-
if (RHSRes.isInvalid())
13474-
return InvalidOperands(Loc, LHS, RHS);
13539+
if (RHSRes.isInvalid()) {
13540+
QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
13541+
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
13542+
return ResultTy;
13543+
}
1347513544
RHS = RHSRes;
1347613545

1347713546
// C++ [expr.log.and]p2
@@ -15067,8 +15136,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
1506715136
case BO_Mul:
1506815137
case BO_Div:
1506915138
ConvertHalfVec = true;
15070-
ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false,
15071-
Opc == BO_Div);
15139+
ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, Opc);
1507215140
break;
1507315141
case BO_Rem:
1507415142
ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc);
@@ -15079,7 +15147,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
1507915147
break;
1508015148
case BO_Sub:
1508115149
ConvertHalfVec = true;
15082-
ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc);
15150+
ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, Opc);
1508315151
break;
1508415152
case BO_Shl:
1508515153
case BO_Shr:
@@ -15123,8 +15191,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
1512315191
case BO_MulAssign:
1512415192
case BO_DivAssign:
1512515193
ConvertHalfVec = true;
15126-
CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, true,
15127-
Opc == BO_DivAssign);
15194+
CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, Opc);
1512815195
CompLHSTy = CompResultTy;
1512915196
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
1513015197
ResultTy =
@@ -15146,7 +15213,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
1514615213
break;
1514715214
case BO_SubAssign:
1514815215
ConvertHalfVec = true;
15149-
CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy);
15216+
CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy);
1515015217
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
1515115218
ResultTy =
1515215219
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);

clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ enum class E { e };
1313

1414
template<typename T> int f(T t) { return ~t; } // expected-error {{invalid argument type}}
1515
template<typename T, typename U> int f(T t, U u) { return t % u; } // expected-error {{invalid operands to}}
16+
// expected-note@-1 {{no implicit conversion for scoped enum}}
1617

1718
int b1 = ~E::e; // expected-error {{invalid argument type}}
1819
int b2 = f(E::e); // expected-note {{in instantiation of}}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++20 -triple x86_64-apple-darwin %s 2>&1 | FileCheck %s
2+
3+
namespace GH24265 {
4+
enum class E_int { e };
5+
enum class E_long : long { e };
6+
7+
void f() {
8+
E_int::e + E_long::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:5-[[@LINE]]:5}:"static_cast<int>("
9+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:12-[[@LINE-1]]:12}:")"
10+
// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:"static_cast<long>("
11+
// CHECK: fix-it:{{.*}}:{[[@LINE-3]]:24-[[@LINE-3]]:24}:")"
12+
E_int::e + 0; // CHECK: fix-it:{{.*}}:{[[@LINE]]:5-[[@LINE]]:5}:"static_cast<int>("
13+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:12-[[@LINE-1]]:12}:")"
14+
15+
0 * E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
16+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
17+
0 / E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
18+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
19+
0 % E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
20+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
21+
0 + E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
22+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
23+
0 - E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
24+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
25+
0 << E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
26+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
27+
0 >> E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
28+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
29+
0 <=> E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:11-[[@LINE]]:11}:"static_cast<int>("
30+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:18-[[@LINE-1]]:18}:")"
31+
0 < E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
32+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
33+
0 > E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
34+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
35+
0 <= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
36+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
37+
0 >= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
38+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
39+
0 == E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
40+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
41+
0 != E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
42+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
43+
0 & E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
44+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
45+
0 ^ E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
46+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
47+
0 | E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
48+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
49+
0 && E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
50+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
51+
0 || E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
52+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
53+
54+
int a;
55+
a *= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
56+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
57+
a /= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
58+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
59+
a %= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
60+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
61+
a += E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
62+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
63+
a -= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
64+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
65+
a <<= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:11-[[@LINE]]:11}:"static_cast<int>("
66+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:18-[[@LINE-1]]:18}:")"
67+
a >>= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:11-[[@LINE]]:11}:"static_cast<int>("
68+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:18-[[@LINE-1]]:18}:")"
69+
a &= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
70+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
71+
a ^= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
72+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
73+
a |= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
74+
// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
75+
76+
// TODO: These do not have the diagnostic yet
77+
E_int b;
78+
b *= 0;
79+
b /= 0;
80+
b %= 0;
81+
b += 0;
82+
b -= 0;
83+
b <<= 0;
84+
b >>= 0;
85+
b &= 0;
86+
b ^= 0;
87+
b |= 0;
88+
89+
a = E_int::e;
90+
b = 0;
91+
92+
E_int c = 0;
93+
int d = E_int::e;
94+
}
95+
}

0 commit comments

Comments
 (0)