[clang] [Clang] Add diagnostic when scoped enumeration requires an explicit conversion for binary operations (PR #152698)
Timothy Choi via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 8 05:21:43 PDT 2025
https://github.com/tinnamchoi created https://github.com/llvm/llvm-project/pull/152698
Fixes #24265
>From 214a9541d4becd3dfae00cc33be5d35228455089 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Fri, 8 Aug 2025 14:39:50 +0800
Subject: [PATCH 1/3] [Clang] Add diagnostic when scoped enumeration requires
an explicit conversion for binary operations
Fixes #24265
---
.../clang/Basic/DiagnosticSemaKinds.td | 5 +
clang/include/clang/Sema/Sema.h | 2 +-
clang/lib/Sema/SemaExpr.cpp | 112 ++++++++++++++----
3 files changed, 97 insertions(+), 22 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 9ce142e7b37cc..e69ab1b9893d9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4401,6 +4401,11 @@ def warn_impcast_different_enum_types : Warning<
def warn_impcast_int_to_enum : Warning<
"implicit conversion from %0 to enumeration type %1 is invalid in C++">,
InGroup<ImplicitIntToEnumCast>, DefaultIgnore;
+
+def note_no_implicit_conversion_for_scoped_enum
+ : Note<"no implicit conversion for scoped enum; consider casting to "
+ "underlying type">;
+
def warn_impcast_bool_to_null_pointer : Warning<
"initialization of pointer of type %0 to null from a constant boolean "
"expression">, InGroup<BoolConversion>;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5211373367677..3fc8f14eded85 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8065,7 +8065,7 @@ class Sema final : public SemaBase {
BinaryOperatorKind Opc, QualType *CompLHSTy = nullptr);
QualType CheckSubtractionOperands( // C99 6.5.6
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
- QualType *CompLHSTy = nullptr);
+ BinaryOperatorKind Opc, QualType *CompLHSTy = nullptr);
QualType CheckShiftOperands( // C99 6.5.7
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
BinaryOperatorKind Opc, bool IsCompAssign = false);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 6793d6da85cb1..87a6f448ba581 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -10742,6 +10742,45 @@ static void DiagnoseBadDivideOrRemainderValues(Sema& S, ExprResult &LHS,
<< IsDiv << RHS.get()->getSourceRange());
}
+static void diagnoseScopedEnums(Sema &S, const SourceLocation Loc,
+ const ExprResult &LHS, const ExprResult &RHS,
+ BinaryOperatorKind Opc) {
+ const Expr *LHSExpr = LHS.get();
+ const Expr *RHSExpr = RHS.get();
+ if (!LHSExpr || !RHSExpr)
+ return;
+ const QualType LHSType = LHSExpr->getType();
+ const QualType RHSType = RHSExpr->getType();
+ const bool LHSIsScoped = LHSType->isScopedEnumeralType();
+ const bool RHSIsScoped = RHSType->isScopedEnumeralType();
+ if (!LHSIsScoped && !RHSIsScoped)
+ return;
+ if (!LHSIsScoped && !LHSType->isIntegralOrUnscopedEnumerationType())
+ return;
+ if (!RHSIsScoped && !RHSType->isIntegralOrUnscopedEnumerationType())
+ return;
+ if (BinaryOperator::isAssignmentOp(Opc) && LHSIsScoped)
+ return;
+ if (LHSIsScoped) {
+ SourceLocation LHSBegin = LHSExpr->getBeginLoc();
+ QualType LHSIntType =
+ LHSType->castAs<EnumType>()->getDecl()->getIntegerType();
+ S.Diag(LHSBegin, diag::note_no_implicit_conversion_for_scoped_enum)
+ << FixItHint::CreateInsertion(
+ LHSBegin, "static_cast<" + LHSIntType.getAsString() + ">(")
+ << FixItHint::CreateInsertion(LHSExpr->getEndLoc(), ")");
+ }
+ if (RHSIsScoped) {
+ SourceLocation RHSBegin = RHSExpr->getBeginLoc();
+ QualType RHSIntType =
+ RHSType->castAs<EnumType>()->getDecl()->getIntegerType();
+ S.Diag(RHSBegin, diag::note_no_implicit_conversion_for_scoped_enum)
+ << FixItHint::CreateInsertion(
+ RHSBegin, "static_cast<" + RHSIntType.getAsString() + ">(")
+ << FixItHint::CreateInsertion(RHSExpr->getEndLoc(), ")");
+ }
+}
+
QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
bool IsCompAssign, bool IsDiv) {
@@ -10772,9 +10811,14 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
-
- if (compType.isNull() || !compType->isArithmeticType())
- return InvalidOperands(Loc, LHS, RHS);
+ if (compType.isNull() || !compType->isArithmeticType()) {
+ InvalidOperands(Loc, LHS, RHS);
+ diagnoseScopedEnums(*this, Loc, LHS, RHS,
+ IsCompAssign ? IsDiv ? BO_DivAssign : BO_MulAssign
+ : IsDiv ? BO_Div
+ : BO_Mul);
+ return QualType();
+ }
if (IsDiv) {
DetectPrecisionLossInComplexDivision(*this, RHS.get()->getType(), Loc);
DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, IsDiv);
@@ -10837,8 +10881,12 @@ QualType Sema::CheckRemainderOperands(
if (compType.isNull() ||
(!compType->isIntegerType() &&
- !(getLangOpts().HLSL && compType->isFloatingType())))
- return InvalidOperands(Loc, LHS, RHS);
+ !(getLangOpts().HLSL && compType->isFloatingType()))) {
+ InvalidOperands(Loc, LHS, RHS);
+ diagnoseScopedEnums(*this, Loc, LHS, RHS,
+ IsCompAssign ? BO_RemAssign : BO_Rem);
+ return QualType();
+ }
DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, false /* IsDiv */);
return compType;
}
@@ -11194,7 +11242,9 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
} else if (PExp->getType()->isObjCObjectPointerType()) {
isObjCPointer = true;
} else {
- return InvalidOperands(Loc, LHS, RHS);
+ InvalidOperands(Loc, LHS, RHS);
+ diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
+ return QualType();
}
}
assert(PExp->getType()->isAnyPointerType());
@@ -11251,7 +11301,8 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
// C99 6.5.6
QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
- QualType* CompLHSTy) {
+ BinaryOperatorKind Opc,
+ QualType *CompLHSTy) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
@@ -11396,7 +11447,9 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
}
}
- return InvalidOperands(Loc, LHS, RHS);
+ InvalidOperands(Loc, LHS, RHS);
+ diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
+ return QualType();
}
static bool isScopedEnumerationType(QualType T) {
@@ -11744,8 +11797,11 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
// Embedded-C 4.1.6.2.2: The LHS may also be fixed-point.
if ((!LHSType->isFixedPointOrIntegerType() &&
!LHSType->hasIntegerRepresentation()) ||
- !RHSType->hasIntegerRepresentation())
- return InvalidOperands(Loc, LHS, RHS);
+ !RHSType->hasIntegerRepresentation()) {
+ InvalidOperands(Loc, LHS, RHS);
+ diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
+ return QualType();
+ }
// C++0x: Don't allow scoped enums. FIXME: Use something better than
// hasIntegerRepresentation() above instead of this.
@@ -12311,8 +12367,11 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
S.UsualArithmeticConversions(LHS, RHS, Loc, ArithConvKind::Comparison);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
- if (Type.isNull())
- return S.InvalidOperands(Loc, LHS, RHS);
+ if (Type.isNull()) {
+ S.InvalidOperands(Loc, LHS, RHS);
+ diagnoseScopedEnums(S, Loc, LHS, RHS, BO_Cmp);
+ return QualType();
+ }
std::optional<ComparisonCategoryType> CCT =
getComparisonCategoryForBuiltinCmp(Type);
@@ -12344,8 +12403,11 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
S.UsualArithmeticConversions(LHS, RHS, Loc, ArithConvKind::Comparison);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
- if (Type.isNull())
- return S.InvalidOperands(Loc, LHS, RHS);
+ if (Type.isNull()) {
+ S.InvalidOperands(Loc, LHS, RHS);
+ diagnoseScopedEnums(S, Loc, LHS, RHS, Opc);
+ return QualType();
+ }
assert(Type->isArithmeticType() || Type->isEnumeralType());
if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc))
@@ -13355,7 +13417,9 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
if (!compType.isNull() && compType->isIntegralOrUnscopedEnumerationType())
return compType;
- return InvalidOperands(Loc, LHS, RHS);
+ InvalidOperands(Loc, LHS, RHS);
+ diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
+ return QualType();
}
// C99 6.5.[13,14]
@@ -13457,13 +13521,19 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
// C++ [expr.log.or]p1
// The operands are both contextually converted to type bool.
ExprResult LHSRes = PerformContextuallyConvertToBool(LHS.get());
- if (LHSRes.isInvalid())
- return InvalidOperands(Loc, LHS, RHS);
+ if (LHSRes.isInvalid()) {
+ InvalidOperands(Loc, LHS, RHS);
+ diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
+ return QualType();
+ }
LHS = LHSRes;
ExprResult RHSRes = PerformContextuallyConvertToBool(RHS.get());
- if (RHSRes.isInvalid())
- return InvalidOperands(Loc, LHS, RHS);
+ if (RHSRes.isInvalid()) {
+ InvalidOperands(Loc, LHS, RHS);
+ diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
+ return QualType();
+ }
RHS = RHSRes;
// C++ [expr.log.and]p2
@@ -15069,7 +15139,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_Sub:
ConvertHalfVec = true;
- ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc);
+ ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, Opc);
break;
case BO_Shl:
case BO_Shr:
@@ -15136,7 +15206,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_SubAssign:
ConvertHalfVec = true;
- CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy);
+ CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy);
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy =
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
>From ab9d87b3d294d6887cd686407dbe1c0df764cca4 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Fri, 8 Aug 2025 15:04:43 +0800
Subject: [PATCH 2/3] [Clang] Update existing tests to reflect new diagnostics
for scoped enums
---
.../over/over.match/over.match.funcs/over.match.oper/p3.cpp | 1 +
clang/test/SemaCXX/enum-scoped.cpp | 3 +++
.../test/SemaCXX/opaque-enum-declaration-in-class-template.cpp | 2 ++
3 files changed, 6 insertions(+)
diff --git a/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp b/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp
index d88d5beb4e99e..7a0cacc2e65be 100644
--- a/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp
+++ b/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp
@@ -13,6 +13,7 @@ enum class E { e };
template<typename T> int f(T t) { return ~t; } // expected-error {{invalid argument type}}
template<typename T, typename U> int f(T t, U u) { return t % u; } // expected-error {{invalid operands to}}
+ // expected-note at -1 {{no implicit conversion for scoped enum}}
int b1 = ~E::e; // expected-error {{invalid argument type}}
int b2 = f(E::e); // expected-note {{in instantiation of}}
diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp
index 2d7b3c9557ebd..103b3051c46c9 100644
--- a/clang/test/SemaCXX/enum-scoped.cpp
+++ b/clang/test/SemaCXX/enum-scoped.cpp
@@ -128,7 +128,10 @@ namespace rdar9366066 {
void f(X x) {
x % X::value; // expected-error{{invalid operands to binary expression ('X' and 'rdar9366066::X')}}
+ // expected-note at -1{{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // expected-note at -2{{no implicit conversion for scoped enum; consider casting to underlying type}}
x % 8; // expected-error{{invalid operands to binary expression ('X' and 'int')}}
+ // expected-note at -1{{no implicit conversion for scoped enum; consider casting to underlying type}}
}
}
diff --git a/clang/test/SemaCXX/opaque-enum-declaration-in-class-template.cpp b/clang/test/SemaCXX/opaque-enum-declaration-in-class-template.cpp
index 7101a153c6ebb..4257e53ce9af0 100644
--- a/clang/test/SemaCXX/opaque-enum-declaration-in-class-template.cpp
+++ b/clang/test/SemaCXX/opaque-enum-declaration-in-class-template.cpp
@@ -94,7 +94,9 @@ struct S5 {
};
int X5 = S5<char>::E1{} + '\0'; // expected-error{{invalid operands to binary expression}}
+ // expected-note at -1{{no implicit conversion for scoped enum; consider casting to underlying type}}
int Y5 = S5<char>::E2{} + '\0'; // expected-error{{invalid operands to binary expression}}
+ // expected-note at -1{{no implicit conversion for scoped enum; consider casting to underlying type}}
template <typename T>
>From 469f5594dc0a8262095842da798232fbf6354504 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Fri, 8 Aug 2025 16:06:45 +0800
Subject: [PATCH 3/3] [Clang] Add tests for new diagnostics for scoped enums
---
clang/test/SemaCXX/enum-scoped.cpp | 102 +++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp
index 103b3051c46c9..091afff024b4c 100644
--- a/clang/test/SemaCXX/enum-scoped.cpp
+++ b/clang/test/SemaCXX/enum-scoped.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify -triple x86_64-apple-darwin %s
// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++17 -verify -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++20 -verify -triple x86_64-apple-darwin %s
enum class E1 {
Val1 = 1L
@@ -328,8 +329,10 @@ namespace PR18044 {
int E::*p; // expected-error {{does not point into a class}}
using E::f; // expected-error {{no member named 'f'}}
+ #if __cplusplus < 202002L
using E::a; // expected-warning {{using declaration naming a scoped enumerator is a C++20 extension}}
E b = a;
+ #endif
}
namespace test11 {
@@ -367,3 +370,102 @@ S<_Atomic(int)> s; // expected-warning {{'_Atomic' is a C11 extension}}
static_assert(__is_same(__underlying_type(S<_Atomic(long long)>::OhBoy), long long), ""); // expected-warning {{'_Atomic' is a C11 extension}}
// expected-note at -1 {{in instantiation of template class 'GH147736::S<_Atomic(long long)>' requested here}}
}
+
+namespace GH24265 {
+ enum class E_int { e };
+ enum class E_long : long { e };
+
+ void f() {
+ E_int::e + E_long::e; // expected-error {{invalid operands to binary expression ('GH24265::E_int' and 'GH24265::E_long')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // expected-note at -2 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ E_int::e + 0; // expected-error {{invalid operands to binary expression ('GH24265::E_int' and 'int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+
+ 0 * E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 / E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 % E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 + E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 - E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 << E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 >> E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+
+ #if __cplusplus >= 202002L
+ 0 <=> E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ #endif
+
+ 0 < E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 > E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 <= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 >= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 == E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 != E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 & E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 ^ E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 | E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 && E_int::e; // expected-error {{value of type 'GH24265::E_int' is not contextually convertible to 'bool'}}
+ // expected-error at -1 {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -2 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ 0 || E_int::e; // expected-error {{value of type 'GH24265::E_int' is not contextually convertible to 'bool'}}
+ // expected-error at -1 {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -2 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+
+ int a;
+ a *= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ a /= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ a %= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ a += E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ a -= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ a <<= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ a >>= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ a &= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ a ^= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ a |= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+
+ // TODO: These do not have the diagnostic yet
+ E_int b;
+ b *= 0; // expected-error {{invalid operands to binary expression ('E_int' and 'int')}}
+ b /= 0; // expected-error {{invalid operands to binary expression ('E_int' and 'int')}}
+ b %= 0; // expected-error {{invalid operands to binary expression ('E_int' and 'int')}}
+ b += 0; // expected-error {{invalid operands to binary expression ('E_int' and 'int')}}
+ b -= 0; // expected-error {{invalid operands to binary expression ('E_int' and 'int')}}
+ b <<= 0; // expected-error {{invalid operands to binary expression ('E_int' and 'int')}}
+ b >>= 0; // expected-error {{invalid operands to binary expression ('E_int' and 'int')}}
+ b &= 0; // expected-error {{invalid operands to binary expression ('E_int' and 'int')}}
+ b ^= 0; // expected-error {{invalid operands to binary expression ('E_int' and 'int')}}
+ b |= 0; // expected-error {{invalid operands to binary expression ('E_int' and 'int')}}
+
+ a = E_int::e; // expected-error {{assigning to 'int' from incompatible type 'GH24265::E_int'}}
+ b = 0; // expected-error {{assigning to 'E_int' from incompatible type 'int'}}
+
+ E_int c = 0; // expected-error {{cannot initialize a variable of type 'E_int' with an rvalue of type 'int'}}
+ int d = E_int::e; // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'GH24265::E_int'}}
+ }
+}
More information about the cfe-commits
mailing list