Skip to content

Commit 24f52fb

Browse files
committed
[clang-tidy] bugprone-implicit-widening ignores unsigned consts
1 parent 2326a02 commit 24f52fb

File tree

6 files changed

+60
-26
lines changed

6 files changed

+60
-26
lines changed

clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,15 @@ void ImplicitWideningOfMultiplicationResultCheck::handleImplicitCastExpr(
8888

8989
// Is the expression a compile-time constexpr that we know can fit in the
9090
// source type?
91-
if (IgnoreConstantIntExpr && ETy->isIntegerType() &&
92-
!ETy->isUnsignedIntegerType()) {
93-
if (const auto ConstExprResult = E->getIntegerConstantExpr(*Context)) {
91+
if (IgnoreConstantIntExpr && ETy->isIntegerType()) {
92+
if (const auto ConstExprResult =
93+
E->getIntegerConstantExpr(*Context, nullptr, true)) {
9494
const auto TypeSize = Context->getTypeSize(ETy);
95+
const auto Unsigned = ETy->isUnsignedIntegerType();
96+
9597
llvm::APSInt WidenedResult = ConstExprResult->extOrTrunc(TypeSize);
96-
if (WidenedResult <= llvm::APSInt::getMaxValue(TypeSize, false) &&
97-
WidenedResult >= llvm::APSInt::getMinValue(TypeSize, false))
98+
if (WidenedResult <= llvm::APSInt::getMaxValue(TypeSize, Unsigned) &&
99+
WidenedResult >= llvm::APSInt::getMinValue(TypeSize, Unsigned))
98100
return;
99101
}
100102
}

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ New check aliases
104104
Changes in existing checks
105105
^^^^^^^^^^^^^^^^^^^^^^^^^^
106106

107+
- Improved :doc:`bugprone-implicit-widening-of-multiplication-result
108+
<clang-tidy/checks/bugprone/implicit-widening-of-multiplication-result>` check
109+
by allowing the `IgnoreConstantIntExpr` option to apply to both signed and
110+
unsigned integer types.
111+
107112
- Improved :doc:`modernize-use-std-format
108113
<clang-tidy/checks/modernize/use-std-format>` check to support replacing
109114
member function calls too.

clang-tools-extra/docs/clang-tidy/checks/bugprone/implicit-widening-of-multiplication-result.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ Options
4949

5050
If the multiplication operands are compile-time constants (like literals or
5151
are ``constexpr``) and fit within the source expression type, do not emit a
52-
diagnostic or suggested fix. Only considers expressions where the source
53-
expression is a signed integer type. Defaults to ``false``.
52+
diagnostic or suggested fix. Defaults to ``false``.
5453

5554
Examples:
5655

clang-tools-extra/test/clang-tidy/checkers/bugprone/implicit-widening-of-multiplication-result-constants.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ long t5() {
4040
return 1 * min_int;
4141
}
4242

43+
long t6() {
44+
const unsigned int a = 4294967295u; // unsigned int max
45+
return a * 1u;
46+
}
47+
4348
unsigned long n0() {
4449
const int a = 1073741824; // 1/2 of int32_t max
4550
const int b = 3;
@@ -50,7 +55,11 @@ unsigned long n0() {
5055
// CHECK-MESSAGES: :[[@LINE-4]]:10: note: perform multiplication in a wider type
5156
}
5257

53-
double n1() {
54-
const long a = 100000000;
55-
return a * 400;
58+
long n1() {
59+
const unsigned int a = 4294967295u; // unsigned int max
60+
return a * 3u;
61+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: performing an implicit widening conversion to type 'long' of a multiplication performed in type 'unsigned int'
62+
// CHECK-MESSAGES: :[[@LINE-2]]:10: note: make conversion explicit to silence this warning
63+
// CHECK-MESSAGES: static_cast<long>( )
64+
// CHECK-MESSAGES: :[[@LINE-4]]:10: note: perform multiplication in a wider type
5665
}

clang/include/clang/AST/Expr.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -551,11 +551,15 @@ class Expr : public ValueStmt {
551551
/// and fill in Loc (if specified) with the location of the invalid
552552
/// expression.
553553
///
554+
/// If CheckUnsignedOverflow is true, the i-c-e is of an unsigned type, and
555+
/// the i-c-e result cannot fit into the expression type without overflowing,
556+
/// std::nullopt is returned.
557+
///
554558
/// Note: This does not perform the implicit conversions required by C++11
555559
/// [expr.const]p5.
556560
std::optional<llvm::APSInt>
557-
getIntegerConstantExpr(const ASTContext &Ctx,
558-
SourceLocation *Loc = nullptr) const;
561+
getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc = nullptr,
562+
bool CheckUnsignedOverflow = false) const;
559563
bool isIntegerConstantExpr(const ASTContext &Ctx,
560564
SourceLocation *Loc = nullptr) const;
561565

@@ -569,7 +573,8 @@ class Expr : public ValueStmt {
569573
/// Note: This does not perform the implicit conversions required by C++11
570574
/// [expr.const]p5.
571575
bool isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result = nullptr,
572-
SourceLocation *Loc = nullptr) const;
576+
SourceLocation *Loc = nullptr,
577+
bool CheckUnsignedOverflow = false) const;
573578

574579
/// isPotentialConstantExpr - Return true if this function's definition
575580
/// might be usable in a constant expression in C++11, if it were marked

clang/lib/AST/ExprConstant.cpp

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,12 @@ namespace {
980980
/// is set; this is used when evaluating ICEs in C.
981981
bool CheckingForUndefinedBehavior = false;
982982

983+
/// Whether we're checking for an expression that causing the unsigned
984+
/// integer expression type to overflow and wrap-around back to 0 when
985+
/// evaluating an ICE. If set to true, the ICE evaluation will fail as
986+
/// though the expression could not be calculated at compile time
987+
bool CheckingForUnsignedIntegerOverflow = false;
988+
983989
enum EvaluationMode {
984990
/// Evaluate as a constant expression. Stop if we find that the expression
985991
/// is not a constant expression.
@@ -2791,24 +2797,28 @@ static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
27912797

27922798
/// Perform the given integer operation, which is known to need at most BitWidth
27932799
/// bits, and check for overflow in the original type (if that type was not an
2794-
/// unsigned type).
2800+
/// unsigned type or EvalInfo.CheckingForUnsignedIntegerOverflow is true).
27952801
template<typename Operation>
27962802
static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
27972803
const APSInt &LHS, const APSInt &RHS,
27982804
unsigned BitWidth, Operation Op,
27992805
APSInt &Result) {
2800-
if (LHS.isUnsigned()) {
2806+
if (LHS.isUnsigned() && !Info.CheckingForUnsignedIntegerOverflow) {
28012807
Result = Op(LHS, RHS);
28022808
return true;
28032809
}
28042810

2805-
APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
2811+
APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)),
2812+
LHS.isUnsigned());
28062813
Result = Value.trunc(LHS.getBitWidth());
28072814
if (Result.extend(BitWidth) != Value) {
2815+
if (Result.isUnsigned())
2816+
return false;
28082817
if (Info.checkingForUndefinedBehavior())
28092818
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
28102819
diag::warn_integer_constant_overflow)
2811-
<< toString(Result, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
2820+
<< toString(Result, 10, Result.isSigned(),
2821+
/*formatAsCLiteral=*/false,
28122822
/*UpperCase=*/true, /*InsertSeparators=*/true)
28132823
<< E->getType() << E->getSourceRange();
28142824
return HandleOverflow(Info, E, Value, E->getType());
@@ -16943,17 +16953,16 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
1694316953
}
1694416954

1694516955
/// Evaluate an expression as a C++11 integral constant expression.
16946-
static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
16947-
const Expr *E,
16948-
llvm::APSInt *Value,
16949-
SourceLocation *Loc) {
16956+
static bool EvaluateCPlusPlus11IntegralConstantExpr(
16957+
const ASTContext &Ctx, const Expr *E, llvm::APSInt *Value,
16958+
SourceLocation *Loc, bool CheckUnsignedOverflow) {
1695016959
if (!E->getType()->isIntegralOrUnscopedEnumerationType()) {
1695116960
if (Loc) *Loc = E->getExprLoc();
1695216961
return false;
1695316962
}
1695416963

1695516964
APValue Result;
16956-
if (!E->isCXX11ConstantExpr(Ctx, &Result, Loc))
16965+
if (!E->isCXX11ConstantExpr(Ctx, &Result, Loc, CheckUnsignedOverflow))
1695716966
return false;
1695816967

1695916968
if (!Result.isInt()) {
@@ -16973,7 +16982,8 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
1697316982
ExprTimeTraceScope TimeScope(this, Ctx, "isIntegerConstantExpr");
1697416983

1697516984
if (Ctx.getLangOpts().CPlusPlus11)
16976-
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc);
16985+
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc,
16986+
false);
1697716987

1697816988
ICEDiag D = CheckICE(this, Ctx);
1697916989
if (D.Kind != IK_ICE) {
@@ -16984,7 +16994,8 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
1698416994
}
1698516995

1698616996
std::optional<llvm::APSInt>
16987-
Expr::getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc) const {
16997+
Expr::getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc,
16998+
bool CheckUnsignedOverflow) const {
1698816999
if (isValueDependent()) {
1698917000
// Expression evaluator can't succeed on a dependent expression.
1699017001
return std::nullopt;
@@ -16993,7 +17004,8 @@ Expr::getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc) const {
1699317004
APSInt Value;
1699417005

1699517006
if (Ctx.getLangOpts().CPlusPlus11) {
16996-
if (EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc))
17007+
if (EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc,
17008+
CheckUnsignedOverflow))
1699717009
return Value;
1699817010
return std::nullopt;
1699917011
}
@@ -17024,7 +17036,8 @@ bool Expr::isCXX98IntegralConstantExpr(const ASTContext &Ctx) const {
1702417036
}
1702517037

1702617038
bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
17027-
SourceLocation *Loc) const {
17039+
SourceLocation *Loc,
17040+
bool CheckUnsignedOverflow) const {
1702817041
assert(!isValueDependent() &&
1702917042
"Expression evaluator can't be called on a dependent expression.");
1703017043

@@ -17037,6 +17050,7 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
1703717050
SmallVector<PartialDiagnosticAt, 8> Diags;
1703817051
Status.Diag = &Diags;
1703917052
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
17053+
Info.CheckingForUnsignedIntegerOverflow = CheckUnsignedOverflow;
1704017054

1704117055
APValue Scratch;
1704217056
bool IsConstExpr =

0 commit comments

Comments
 (0)