From a0138390dd2ac2130c9f76e6778d6e45e4dc5526 Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Thu, 12 Jan 2023 08:02:00 -0800 Subject: [PATCH] [Clang] Diagnose undefined behavior in a constant expression while evaluating a compound assignment with remainder as operand Currently we don't diagnose overflow in a constant expression for the case of compound assignment with remainder as a operand. In handleIntIntBinOp the arguments LHS and Result can be the same source but in the check for remainder in this function we assigned to Result before checking for overflow. In all the other operations the check is done before Result is assigned to. Differential Revision: https://reviews.llvm.org/D140455 --- clang/docs/ReleaseNotes.rst | 2 ++ clang/lib/AST/ExprConstant.cpp | 9 +++++---- clang/test/CXX/expr/expr.const/p2-0x.cpp | 9 +++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3d7b07f..a9f1a1c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -447,6 +447,8 @@ Improvements to Clang's diagnostics ``#pragma clang __debug sloc_usage`` can also be used to request this report. - Clang no longer permits the keyword 'bool' in a concept declaration as a concepts-ts compatibility extension. +- Clang now diagnoses overflow undefined behavior in a constant expression while + evaluating a compound assignment with remainder as operand. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 9e0e630..47383a2 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2751,6 +2751,7 @@ static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E, static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, BinaryOperatorKind Opcode, APSInt RHS, APSInt &Result) { + bool HandleOverflowResult = true; switch (Opcode) { default: Info.FFDiag(E); @@ -2773,14 +2774,14 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, Info.FFDiag(E, diag::note_expr_divide_by_zero); return false; } - Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS); // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. APSInt supports // this operation and gives the two's complement result. if (RHS.isNegative() && RHS.isAllOnes() && LHS.isSigned() && LHS.isMinSignedValue()) - return HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), - E->getType()); - return true; + HandleOverflowResult = HandleOverflow( + Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType()); + Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS); + return HandleOverflowResult; case BO_Shl: { if (Info.getLangOpts().OpenCL) // OpenCL 6.3j: shift values are effectively % word size of LHS. diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp index d8b228f..a8dece1 100644 --- a/clang/test/CXX/expr/expr.const/p2-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -298,6 +298,15 @@ constexpr float negpi = -pi; // expect no error on unary operator static_assert(isinf(f6), ""); static_assert(isinf(f9), ""); } + +#if __cplusplus >= 201703L +namespace CompoundAssignment { +constexpr int rem() { // expected-error {{constexpr function never produces a constant expression}} + int x = ~__INT_MAX__; + return x%=-1; // cxx20-note {{value 2147483648 is outside the range of representable values of type 'int'}} +} +} +#endif } // - a lambda-expression (5.1.2); -- 2.7.4