[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 15 12:55:04 PDT 2025
https://github.com/tinnamchoi updated https://github.com/llvm/llvm-project/pull/152698
>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 01/15] [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 02/15] [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 03/15] [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'}}
+ }
+}
>From 79d4d08bfab5c481557b1f010791af9e09dd8b1d Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Sat, 9 Aug 2025 16:15:40 +0800
Subject: [PATCH 04/15] [Clang] Remove unnecessary if block in scoped enum test
Block containing `<=>` kept since it didn't exist prior to C++20
---
clang/test/SemaCXX/enum-scoped.cpp | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp
index 091afff024b4c..584c93eabbb22 100644
--- a/clang/test/SemaCXX/enum-scoped.cpp
+++ b/clang/test/SemaCXX/enum-scoped.cpp
@@ -1,5 +1,5 @@
-// 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++11 -verify=expected,cxx11-17 -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++17 -verify=expected,cxx11-17 -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 {
@@ -329,10 +329,8 @@ 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}}
+ using E::a; // cxx11-17-warning {{using declaration naming a scoped enumerator is a C++20 extension}}
E b = a;
- #endif
}
namespace test11 {
>From e22ad8b07080ad0f2e51ab9f40511b0cb8389c15 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Sat, 9 Aug 2025 17:26:19 +0800
Subject: [PATCH 05/15] [Clang] Add tests for `fix-it`s for scoped enums
---
clang/test/SemaCXX/enum-scoped.cpp | 67 +++++++++++++++++++++++++++++-
1 file changed, 66 insertions(+), 1 deletion(-)
diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp
index 584c93eabbb22..49b328f833b9f 100644
--- a/clang/test/SemaCXX/enum-scoped.cpp
+++ b/clang/test/SemaCXX/enum-scoped.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify=expected,cxx11-17 -triple x86_64-apple-darwin %s
// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++17 -verify=expected,cxx11-17 -triple x86_64-apple-darwin %s
// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++20 -verify -triple x86_64-apple-darwin %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++20 -triple x86_64-apple-darwin %s 2>&1 | FileCheck %s
enum class E1 {
Val1 = 1L
@@ -376,76 +377,140 @@ namespace GH24265 {
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
+ // expected-note at -4 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-5]]:16-[[@LINE-5]]:16}:"static_cast<long>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-6]]:24-[[@LINE-6]]:24}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
#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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
#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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
// TODO: These do not have the diagnostic yet
E_int b;
>From 76baf51ceaad8793697ae30a55467f9bba87c9e3 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Sat, 9 Aug 2025 17:41:14 +0800
Subject: [PATCH 06/15] [Clang]: Refactor Sema::CheckMultiplyDivideOperands for
clarity
---
clang/include/clang/Sema/Sema.h | 4 ++--
clang/lib/Sema/SemaExpr.cpp | 17 +++++++----------
2 files changed, 9 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 3fc8f14eded85..dfa078651883b 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8055,8 +8055,8 @@ class Sema final : public SemaBase {
ExprResult &RHS);
QualType CheckMultiplyDivideOperands( // C99 6.5.5
- ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign,
- bool IsDivide);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
+ BinaryOperatorKind Opc);
QualType CheckRemainderOperands( // C99 6.5.5
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
bool IsCompAssign = false);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 87a6f448ba581..3550ec9a27e98 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -10782,8 +10782,10 @@ static void diagnoseScopedEnums(Sema &S, const SourceLocation Loc,
}
QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
- SourceLocation Loc,
- bool IsCompAssign, bool IsDiv) {
+ SourceLocation Loc, BinaryOperatorKind Opc) {
+ bool IsCompAssign = Opc == BO_MulAssign || Opc == BO_DivAssign;
+ bool IsDiv = Opc == BO_Div || Opc == BO_DivAssign;
+
checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false);
QualType LHSTy = LHS.get()->getType();
@@ -10813,10 +10815,7 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &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);
+ diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
return QualType();
}
if (IsDiv) {
@@ -15127,8 +15126,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
case BO_Mul:
case BO_Div:
ConvertHalfVec = true;
- ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false,
- Opc == BO_Div);
+ ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, Opc);
break;
case BO_Rem:
ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc);
@@ -15183,8 +15181,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
case BO_MulAssign:
case BO_DivAssign:
ConvertHalfVec = true;
- CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, true,
- Opc == BO_DivAssign);
+ CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, Opc);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy =
>From 824084e8abb12ac6d48548a41be41f0db3ea3463 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Sat, 9 Aug 2025 18:59:33 +0800
Subject: [PATCH 07/15] [Clang] Suggest using `std::to_underlying` for invalid
scoped enum operations in C++23
---
.../clang/Basic/DiagnosticSemaKinds.td | 3 ++
clang/lib/Sema/SemaExpr.cpp | 31 ++++++++++---------
2 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e69ab1b9893d9..d212924147871 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4405,6 +4405,9 @@ def warn_impcast_int_to_enum : Warning<
def note_no_implicit_conversion_for_scoped_enum
: Note<"no implicit conversion for scoped enum; consider casting to "
"underlying type">;
+def note_no_implicit_conversion_for_scoped_enum_cxx23
+ : Note<"no implicit conversion for scoped enum; consider using "
+ "std::to_underlying">;
def warn_impcast_bool_to_null_pointer : Warning<
"initialization of pointer of type %0 to null from a constant boolean "
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 3550ec9a27e98..f056437d1124f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -10761,23 +10761,26 @@ static void diagnoseScopedEnums(Sema &S, const SourceLocation Loc,
return;
if (BinaryOperator::isAssignmentOp(Opc) && LHSIsScoped)
return;
+ bool isCxx23 = S.getLangOpts().CPlusPlus23;
+ unsigned diagID =
+ isCxx23 ? diag::note_no_implicit_conversion_for_scoped_enum_cxx23
+ : diag::note_no_implicit_conversion_for_scoped_enum;
+ auto diagnosticHelper = [&S, isCxx23, diagID](const Expr *expr, const QualType type) {
+ SourceLocation beginLoc = expr->getBeginLoc();
+ QualType intType =
+ type->castAs<EnumType>()->getDecl()->getIntegerType();
+ std::string insertionString =
+ isCxx23 ? "std::to_underlying("
+ : "static_cast<" + intType.getAsString() + ">(";
+ S.Diag(beginLoc, diagID)
+ << FixItHint::CreateInsertion(beginLoc, insertionString)
+ << FixItHint::CreateInsertion(expr->getEndLoc(), ")");
+ };
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(), ")");
+ diagnosticHelper(LHSExpr, LHSType);
}
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(), ")");
+ diagnosticHelper(RHSExpr, RHSType);
}
}
>From 6193ea0857a783a5003f9f4936df4f4f21b429f1 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Sat, 9 Aug 2025 21:52:55 +0800
Subject: [PATCH 08/15] [Clang] Add tests for diagnostics for scoped enums in
C++23
---
clang/test/SemaCXX/enum-scoped.cpp | 307 +++++++++++++++++++----------
1 file changed, 204 insertions(+), 103 deletions(-)
diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp
index 49b328f833b9f..fe327ab28f9af 100644
--- a/clang/test/SemaCXX/enum-scoped.cpp
+++ b/clang/test/SemaCXX/enum-scoped.cpp
@@ -1,7 +1,9 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify=expected,cxx11-17 -triple x86_64-apple-darwin %s
-// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++17 -verify=expected,cxx11-17 -triple x86_64-apple-darwin %s
-// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++20 -verify -triple x86_64-apple-darwin %s
-// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++20 -triple x86_64-apple-darwin %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify=expected,cxx11-17,cxx11-20 -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++17 -verify=expected,cxx11-17,cxx11-20 -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++20 -verify=expected,cxx11-20 -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++23 -verify=expected,cxx23 -triple x86_64-apple-darwin %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++20 -triple x86_64-apple-darwin %s 2>&1 | FileCheck %s --check-prefix=CXX20
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++23 -triple x86_64-apple-darwin %s 2>&1 | FileCheck %s --check-prefix=CXX23
enum class E1 {
Val1 = 1L
@@ -130,10 +132,13 @@ 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}}
+ // cxx11-20-note at -1{{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // cxx23-note at -2{{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // cxx11-20-note at -3{{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // cxx23-note at -4{{no implicit conversion for scoped enum; consider using std::to_underlying}}
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}}
+ // cxx11-20-note at -1{{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // cxx23-note at -2{{no implicit conversion for scoped enum; consider using std::to_underlying}}
}
}
@@ -376,141 +381,237 @@ namespace GH24265 {
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
- // expected-note at -4 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-5]]:16-[[@LINE-5]]:16}:"static_cast<long>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-6]]:24-[[@LINE-6]]:24}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:5-[[@LINE-5]]:5}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:12-[[@LINE-6]]:12}:")"
+ // cxx11-20-note at -7 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-8]]:16-[[@LINE-8]]:16}:"static_cast<long>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-9]]:24-[[@LINE-9]]:24}:")"
+ // cxx23-note at -10 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-11]]:16-[[@LINE-11]]:16}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-12]]:24-[[@LINE-12]]:24}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:5-[[@LINE-5]]:5}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:12-[[@LINE-6]]:12}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
#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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:11-[[@LINE-5]]:11}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:18-[[@LINE-6]]:18}:")"
#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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
+ // cxx11-20-note at -2 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
+ // cxx23-note at -5 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:10-[[@LINE-6]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-7]]:17-[[@LINE-7]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
+ // cxx11-20-note at -2 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
+ // cxx23-note at -5 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:10-[[@LINE-6]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-7]]:17-[[@LINE-7]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:11-[[@LINE-5]]:11}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:18-[[@LINE-6]]:18}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:11-[[@LINE-5]]:11}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:18-[[@LINE-6]]:18}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
+ // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
+ // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
// TODO: These do not have the diagnostic yet
E_int b;
>From 45c8c060cc45cd3abfb3d4d4eda676ab6ce30890 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Sat, 9 Aug 2025 23:18:35 +0800
Subject: [PATCH 09/15] [Clang] Update ReleaseNotes.rst
---
clang/docs/ReleaseNotes.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9231f2cae9bfa..0ba1ad5f85c03 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -125,6 +125,7 @@ Improvements to Clang's diagnostics
an override of a virtual method.
- Fixed fix-it hint for fold expressions. Clang now correctly places the suggested right
parenthesis when diagnosing malformed fold expressions. (#GH151787)
+- Added fix-it hint for when scoped enumerations require explicit conversions for binary operations. (#GH24265)
Improvements to Clang's time-trace
----------------------------------
>From 1c32a639d66b330caef7f97cd021663a8120497a Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Fri, 15 Aug 2025 23:08:14 +0800
Subject: [PATCH 10/15] [Clang] Fix variable capitalization
---
clang/lib/Sema/SemaExpr.cpp | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index f056437d1124f..e47b5c846911c 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -10761,26 +10761,26 @@ static void diagnoseScopedEnums(Sema &S, const SourceLocation Loc,
return;
if (BinaryOperator::isAssignmentOp(Opc) && LHSIsScoped)
return;
- bool isCxx23 = S.getLangOpts().CPlusPlus23;
- unsigned diagID =
- isCxx23 ? diag::note_no_implicit_conversion_for_scoped_enum_cxx23
+ bool IsCxx23 = S.getLangOpts().CPlusPlus23;
+ unsigned DiagID =
+ IsCxx23 ? diag::note_no_implicit_conversion_for_scoped_enum_cxx23
: diag::note_no_implicit_conversion_for_scoped_enum;
- auto diagnosticHelper = [&S, isCxx23, diagID](const Expr *expr, const QualType type) {
- SourceLocation beginLoc = expr->getBeginLoc();
- QualType intType =
+ auto DiagnosticHelper = [&S, IsCxx23, DiagID](const Expr *expr, const QualType type) {
+ SourceLocation BeginLoc = expr->getBeginLoc();
+ QualType IntType =
type->castAs<EnumType>()->getDecl()->getIntegerType();
- std::string insertionString =
- isCxx23 ? "std::to_underlying("
- : "static_cast<" + intType.getAsString() + ">(";
- S.Diag(beginLoc, diagID)
- << FixItHint::CreateInsertion(beginLoc, insertionString)
+ std::string InsertionString =
+ IsCxx23 ? "std::to_underlying("
+ : "static_cast<" + IntType.getAsString() + ">(";
+ S.Diag(BeginLoc, DiagID)
+ << FixItHint::CreateInsertion(BeginLoc, InsertionString)
<< FixItHint::CreateInsertion(expr->getEndLoc(), ")");
};
if (LHSIsScoped) {
- diagnosticHelper(LHSExpr, LHSType);
+ DiagnosticHelper(LHSExpr, LHSType);
}
if (RHSIsScoped) {
- diagnosticHelper(RHSExpr, RHSType);
+ DiagnosticHelper(RHSExpr, RHSType);
}
}
>From 771f9ac72d5e8065f453f830690836d78fac8bb5 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Fri, 15 Aug 2025 23:32:50 +0800
Subject: [PATCH 11/15] [Clang] Remove >=C++23 version of scoped enum
diagnostic
---
.../clang/Basic/DiagnosticSemaKinds.td | 3 -
clang/lib/Sema/SemaExpr.cpp | 18 +-
clang/test/SemaCXX/enum-scoped.cpp | 307 ++++++------------
3 files changed, 109 insertions(+), 219 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d212924147871..e69ab1b9893d9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4405,9 +4405,6 @@ def warn_impcast_int_to_enum : Warning<
def note_no_implicit_conversion_for_scoped_enum
: Note<"no implicit conversion for scoped enum; consider casting to "
"underlying type">;
-def note_no_implicit_conversion_for_scoped_enum_cxx23
- : Note<"no implicit conversion for scoped enum; consider using "
- "std::to_underlying">;
def warn_impcast_bool_to_null_pointer : Warning<
"initialization of pointer of type %0 to null from a constant boolean "
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e47b5c846911c..e50d58b59eac3 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -10761,18 +10761,11 @@ static void diagnoseScopedEnums(Sema &S, const SourceLocation Loc,
return;
if (BinaryOperator::isAssignmentOp(Opc) && LHSIsScoped)
return;
- bool IsCxx23 = S.getLangOpts().CPlusPlus23;
- unsigned DiagID =
- IsCxx23 ? diag::note_no_implicit_conversion_for_scoped_enum_cxx23
- : diag::note_no_implicit_conversion_for_scoped_enum;
- auto DiagnosticHelper = [&S, IsCxx23, DiagID](const Expr *expr, const QualType type) {
+ auto DiagnosticHelper = [&S](const Expr *expr, const QualType type) {
SourceLocation BeginLoc = expr->getBeginLoc();
- QualType IntType =
- type->castAs<EnumType>()->getDecl()->getIntegerType();
- std::string InsertionString =
- IsCxx23 ? "std::to_underlying("
- : "static_cast<" + IntType.getAsString() + ">(";
- S.Diag(BeginLoc, DiagID)
+ QualType IntType = type->castAs<EnumType>()->getDecl()->getIntegerType();
+ std::string InsertionString = "static_cast<" + IntType.getAsString() + ">(";
+ S.Diag(BeginLoc, diag::note_no_implicit_conversion_for_scoped_enum)
<< FixItHint::CreateInsertion(BeginLoc, InsertionString)
<< FixItHint::CreateInsertion(expr->getEndLoc(), ")");
};
@@ -10785,7 +10778,8 @@ static void diagnoseScopedEnums(Sema &S, const SourceLocation Loc,
}
QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
- SourceLocation Loc, BinaryOperatorKind Opc) {
+ SourceLocation Loc,
+ BinaryOperatorKind Opc) {
bool IsCompAssign = Opc == BO_MulAssign || Opc == BO_DivAssign;
bool IsDiv = Opc == BO_Div || Opc == BO_DivAssign;
diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp
index fe327ab28f9af..49b328f833b9f 100644
--- a/clang/test/SemaCXX/enum-scoped.cpp
+++ b/clang/test/SemaCXX/enum-scoped.cpp
@@ -1,9 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify=expected,cxx11-17,cxx11-20 -triple x86_64-apple-darwin %s
-// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++17 -verify=expected,cxx11-17,cxx11-20 -triple x86_64-apple-darwin %s
-// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++20 -verify=expected,cxx11-20 -triple x86_64-apple-darwin %s
-// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++23 -verify=expected,cxx23 -triple x86_64-apple-darwin %s
-// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++20 -triple x86_64-apple-darwin %s 2>&1 | FileCheck %s --check-prefix=CXX20
-// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++23 -triple x86_64-apple-darwin %s 2>&1 | FileCheck %s --check-prefix=CXX23
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify=expected,cxx11-17 -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++17 -verify=expected,cxx11-17 -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++20 -verify -triple x86_64-apple-darwin %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++20 -triple x86_64-apple-darwin %s 2>&1 | FileCheck %s
enum class E1 {
Val1 = 1L
@@ -132,13 +130,10 @@ namespace rdar9366066 {
void f(X x) {
x % X::value; // expected-error{{invalid operands to binary expression ('X' and 'rdar9366066::X')}}
- // cxx11-20-note at -1{{no implicit conversion for scoped enum; consider casting to underlying type}}
- // cxx23-note at -2{{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // cxx11-20-note at -3{{no implicit conversion for scoped enum; consider casting to underlying type}}
- // cxx23-note at -4{{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // 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')}}
- // cxx11-20-note at -1{{no implicit conversion for scoped enum; consider casting to underlying type}}
- // cxx23-note at -2{{no implicit conversion for scoped enum; consider using std::to_underlying}}
+ // expected-note at -1{{no implicit conversion for scoped enum; consider casting to underlying type}}
}
}
@@ -381,237 +376,141 @@ namespace GH24265 {
void f() {
E_int::e + E_long::e; // expected-error {{invalid operands to binary expression ('GH24265::E_int' and 'GH24265::E_long')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:5-[[@LINE-5]]:5}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:12-[[@LINE-6]]:12}:")"
- // cxx11-20-note at -7 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-8]]:16-[[@LINE-8]]:16}:"static_cast<long>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-9]]:24-[[@LINE-9]]:24}:")"
- // cxx23-note at -10 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-11]]:16-[[@LINE-11]]:16}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-12]]:24-[[@LINE-12]]:24}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
+ // expected-note at -4 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-5]]:16-[[@LINE-5]]:16}:"static_cast<long>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-6]]:24-[[@LINE-6]]:24}:")"
E_int::e + 0; // expected-error {{invalid operands to binary expression ('GH24265::E_int' and 'int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:5-[[@LINE-5]]:5}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:12-[[@LINE-6]]:12}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
0 * E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
0 / E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
0 % E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
0 + E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
0 - E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
0 << E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
0 >> E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
#if __cplusplus >= 202002L
0 <=> E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:11-[[@LINE-5]]:11}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:18-[[@LINE-6]]:18}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
#endif
0 < E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
0 > E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
0 <= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
0 >= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
0 == E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
0 != E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
0 & E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
0 ^ E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
0 | E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:9-[[@LINE-5]]:9}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:16-[[@LINE-6]]:16}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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')}}
- // cxx11-20-note at -2 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
- // cxx23-note at -5 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:10-[[@LINE-6]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-7]]:17-[[@LINE-7]]:17}:")"
+ // expected-note at -2 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
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')}}
- // cxx11-20-note at -2 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
- // cxx23-note at -5 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:10-[[@LINE-6]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-7]]:17-[[@LINE-7]]:17}:")"
+ // expected-note at -2 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
int a;
a *= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
a /= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
a %= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
a += E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
a -= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
a <<= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:11-[[@LINE-5]]:11}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:18-[[@LINE-6]]:18}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
a >>= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:11-[[@LINE-5]]:11}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:18-[[@LINE-6]]:18}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
a &= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
a ^= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
a |= E_int::e; // expected-error {{invalid operands to binary expression ('int' and 'GH24265::E_int')}}
- // cxx11-20-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CXX20: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CXX20: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
- // cxx23-note at -4 {{no implicit conversion for scoped enum; consider using std::to_underlying}}
- // CXX23: fix-it:{{.*}}:{[[@LINE-5]]:10-[[@LINE-5]]:10}:"std::to_underlying("
- // CXX23: fix-it:{{.*}}:{[[@LINE-6]]:17-[[@LINE-6]]:17}:")"
+ // expected-note at -1 {{no implicit conversion for scoped enum; consider casting to underlying type}}
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
// TODO: These do not have the diagnostic yet
E_int b;
>From d3388ffdfc3312efa1fa7937b3d5c275a531a454 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Sat, 16 Aug 2025 00:44:30 +0800
Subject: [PATCH 12/15] [Clang] Don't rely on `InvalidOperands` always
returning `QualType()`
---
clang/lib/Sema/SemaExpr.cpp | 40 ++++++++++++++++++-------------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e50d58b59eac3..22166d020ea71 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -10811,9 +10811,9 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
return QualType();
if (compType.isNull() || !compType->isArithmeticType()) {
- InvalidOperands(Loc, LHS, RHS);
+ QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
- return QualType();
+ return ResultTy;
}
if (IsDiv) {
DetectPrecisionLossInComplexDivision(*this, RHS.get()->getType(), Loc);
@@ -10878,10 +10878,10 @@ QualType Sema::CheckRemainderOperands(
if (compType.isNull() ||
(!compType->isIntegerType() &&
!(getLangOpts().HLSL && compType->isFloatingType()))) {
- InvalidOperands(Loc, LHS, RHS);
+ QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
diagnoseScopedEnums(*this, Loc, LHS, RHS,
IsCompAssign ? BO_RemAssign : BO_Rem);
- return QualType();
+ return ResultTy;
}
DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, false /* IsDiv */);
return compType;
@@ -11238,9 +11238,9 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
} else if (PExp->getType()->isObjCObjectPointerType()) {
isObjCPointer = true;
} else {
- InvalidOperands(Loc, LHS, RHS);
+ QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
- return QualType();
+ return ResultTy;
}
}
assert(PExp->getType()->isAnyPointerType());
@@ -11443,9 +11443,9 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
}
}
- InvalidOperands(Loc, LHS, RHS);
+ QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
- return QualType();
+ return ResultTy;
}
static bool isScopedEnumerationType(QualType T) {
@@ -11794,9 +11794,9 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
if ((!LHSType->isFixedPointOrIntegerType() &&
!LHSType->hasIntegerRepresentation()) ||
!RHSType->hasIntegerRepresentation()) {
- InvalidOperands(Loc, LHS, RHS);
+ QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
- return QualType();
+ return ResultTy;
}
// C++0x: Don't allow scoped enums. FIXME: Use something better than
@@ -12364,9 +12364,9 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (Type.isNull()) {
- S.InvalidOperands(Loc, LHS, RHS);
+ QualType ResultTy = S.InvalidOperands(Loc, LHS, RHS);
diagnoseScopedEnums(S, Loc, LHS, RHS, BO_Cmp);
- return QualType();
+ return ResultTy;
}
std::optional<ComparisonCategoryType> CCT =
@@ -12400,9 +12400,9 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (Type.isNull()) {
- S.InvalidOperands(Loc, LHS, RHS);
+ QualType ResultTy = S.InvalidOperands(Loc, LHS, RHS);
diagnoseScopedEnums(S, Loc, LHS, RHS, Opc);
- return QualType();
+ return ResultTy;
}
assert(Type->isArithmeticType() || Type->isEnumeralType());
@@ -13413,9 +13413,9 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
if (!compType.isNull() && compType->isIntegralOrUnscopedEnumerationType())
return compType;
- InvalidOperands(Loc, LHS, RHS);
+ QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
- return QualType();
+ return ResultTy;
}
// C99 6.5.[13,14]
@@ -13518,17 +13518,17 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
// The operands are both contextually converted to type bool.
ExprResult LHSRes = PerformContextuallyConvertToBool(LHS.get());
if (LHSRes.isInvalid()) {
- InvalidOperands(Loc, LHS, RHS);
+ QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
- return QualType();
+ return ResultTy;
}
LHS = LHSRes;
ExprResult RHSRes = PerformContextuallyConvertToBool(RHS.get());
if (RHSRes.isInvalid()) {
- InvalidOperands(Loc, LHS, RHS);
+ QualType ResultTy = InvalidOperands(Loc, LHS, RHS);
diagnoseScopedEnums(*this, Loc, LHS, RHS, Opc);
- return QualType();
+ return ResultTy;
}
RHS = RHSRes;
>From 34485af964f97ecd70a630d34b44c1716c2033b1 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Sat, 16 Aug 2025 00:57:15 +0800
Subject: [PATCH 13/15] [Clang] Reorder checks in diagnoseScopedEnums for
efficiency
---
clang/lib/Sema/SemaExpr.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 22166d020ea71..41b1401d93447 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -10745,22 +10745,22 @@ static void DiagnoseBadDivideOrRemainderValues(Sema& S, ExprResult &LHS,
static void diagnoseScopedEnums(Sema &S, const SourceLocation Loc,
const ExprResult &LHS, const ExprResult &RHS,
BinaryOperatorKind Opc) {
+ if (!LHS.isUsable() || !RHS.isUsable())
+ return;
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 (BinaryOperator::isAssignmentOp(Opc) && LHSIsScoped)
+ return;
if (!LHSIsScoped && !LHSType->isIntegralOrUnscopedEnumerationType())
return;
if (!RHSIsScoped && !RHSType->isIntegralOrUnscopedEnumerationType())
return;
- if (BinaryOperator::isAssignmentOp(Opc) && LHSIsScoped)
- return;
auto DiagnosticHelper = [&S](const Expr *expr, const QualType type) {
SourceLocation BeginLoc = expr->getBeginLoc();
QualType IntType = type->castAs<EnumType>()->getDecl()->getIntegerType();
>From e13b3a73adb3f1b187464de4e1e9049a55514de0 Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Sat, 16 Aug 2025 01:10:30 +0800
Subject: [PATCH 14/15] [Clang] Move FixIt tests for scoped enums
---
clang/test/FixIt/fixit-enum-scoped.cpp | 95 ++++++++++++++++++++++++++
clang/test/SemaCXX/enum-scoped.cpp | 67 +-----------------
2 files changed, 96 insertions(+), 66 deletions(-)
create mode 100644 clang/test/FixIt/fixit-enum-scoped.cpp
diff --git a/clang/test/FixIt/fixit-enum-scoped.cpp b/clang/test/FixIt/fixit-enum-scoped.cpp
new file mode 100644
index 0000000000000..b7e4138b7d216
--- /dev/null
+++ b/clang/test/FixIt/fixit-enum-scoped.cpp
@@ -0,0 +1,95 @@
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++20 -triple x86_64-apple-darwin %s 2>&1 | FileCheck %s
+
+namespace GH24265 {
+ enum class E_int { e };
+ enum class E_long : long { e };
+
+ void f() {
+ E_int::e + E_long::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:5-[[@LINE]]:5}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:12-[[@LINE-1]]:12}:")"
+ // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:16-[[@LINE-2]]:16}:"static_cast<long>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:24-[[@LINE-3]]:24}:")"
+ E_int::e + 0; // CHECK: fix-it:{{.*}}:{[[@LINE]]:5-[[@LINE]]:5}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:12-[[@LINE-1]]:12}:")"
+
+ 0 * E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
+ 0 / E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
+ 0 % E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
+ 0 + E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
+ 0 - E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
+ 0 << E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ 0 >> E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ 0 <=> E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:11-[[@LINE]]:11}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:18-[[@LINE-1]]:18}:")"
+ 0 < E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
+ 0 > E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
+ 0 <= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ 0 >= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ 0 == E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ 0 != E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ 0 & E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
+ 0 ^ E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
+ 0 | E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:9-[[@LINE]]:9}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:16-[[@LINE-1]]:16}:")"
+ 0 && E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ 0 || E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+
+ int a;
+ a *= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ a /= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ a %= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ a += E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ a -= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ a <<= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:11-[[@LINE]]:11}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:18-[[@LINE-1]]:18}:")"
+ a >>= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:11-[[@LINE]]:11}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:18-[[@LINE-1]]:18}:")"
+ a &= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ a ^= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+ a |= E_int::e; // CHECK: fix-it:{{.*}}:{[[@LINE]]:10-[[@LINE]]:10}:"static_cast<int>("
+ // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:17-[[@LINE-1]]:17}:")"
+
+ // TODO: These do not have the diagnostic yet
+ E_int b;
+ b *= 0;
+ b /= 0;
+ b %= 0;
+ b += 0;
+ b -= 0;
+ b <<= 0;
+ b >>= 0;
+ b &= 0;
+ b ^= 0;
+ b |= 0;
+
+ a = E_int::e;
+ b = 0;
+
+ E_int c = 0;
+ int d = E_int::e;
+ }
+}
diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp
index 49b328f833b9f..584c93eabbb22 100644
--- a/clang/test/SemaCXX/enum-scoped.cpp
+++ b/clang/test/SemaCXX/enum-scoped.cpp
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++11 -verify=expected,cxx11-17 -triple x86_64-apple-darwin %s
// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++17 -verify=expected,cxx11-17 -triple x86_64-apple-darwin %s
// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++20 -verify -triple x86_64-apple-darwin %s
-// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -std=c++20 -triple x86_64-apple-darwin %s 2>&1 | FileCheck %s
enum class E1 {
Val1 = 1L
@@ -377,140 +376,76 @@ namespace GH24265 {
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
- // expected-note at -4 {{no implicit conversion for scoped enum; consider casting to underlying type}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-5]]:16-[[@LINE-5]]:16}:"static_cast<long>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-6]]:24-[[@LINE-6]]:24}:")"
+ // 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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:5-[[@LINE-2]]:5}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:12-[[@LINE-3]]:12}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
#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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
#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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:9-[[@LINE-2]]:9}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:16-[[@LINE-3]]:16}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:10-[[@LINE-3]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-4]]:17-[[@LINE-4]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:11-[[@LINE-2]]:11}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:18-[[@LINE-3]]:18}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
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}}
- // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:10-[[@LINE-2]]:10}:"static_cast<int>("
- // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:17-[[@LINE-3]]:17}:")"
// TODO: These do not have the diagnostic yet
E_int b;
>From 3a6e09b4db43a8374bfe01cb1e97929bc91714aa Mon Sep 17 00:00:00 2001
From: tinnamchoi <tinnam.choi at gmail.com>
Date: Sat, 16 Aug 2025 01:42:14 +0800
Subject: [PATCH 15/15] [Clang] Fix error caused by upstream changes in
91cdd35008e9ab32dffb7e401cdd7313b3461892
---
clang/lib/Sema/SemaExpr.cpp | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 397552f17cb8d..108b48034e94e 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -10771,7 +10771,10 @@ static void diagnoseScopedEnums(Sema &S, const SourceLocation Loc,
return;
auto DiagnosticHelper = [&S](const Expr *expr, const QualType type) {
SourceLocation BeginLoc = expr->getBeginLoc();
- QualType IntType = type->castAs<EnumType>()->getDecl()->getIntegerType();
+ QualType IntType = type->castAs<EnumType>()
+ ->getOriginalDecl()
+ ->getDefinitionOrSelf()
+ ->getIntegerType();
std::string InsertionString = "static_cast<" + IntType.getAsString() + ">(";
S.Diag(BeginLoc, diag::note_no_implicit_conversion_for_scoped_enum)
<< FixItHint::CreateInsertion(BeginLoc, InsertionString)
More information about the cfe-commits
mailing list