Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
112 changes: 91 additions & 21 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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() ||
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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@-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}}
Expand Down
Loading