[Clang] Diagnose undefined behavior in a constant expression while evaluating a compo...
authorShafik Yaghmour <shafik.yaghmour@intel.com>
Thu, 12 Jan 2023 16:02:00 +0000 (08:02 -0800)
committerShafik Yaghmour <shafik.yaghmour@intel.com>
Thu, 12 Jan 2023 16:04:04 +0000 (08:04 -0800)
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
clang/lib/AST/ExprConstant.cpp
clang/test/CXX/expr/expr.const/p2-0x.cpp

index 3d7b07f88101d9f26806c28e365d8fcc9a5577e8..a9f1a1caf0bb7ae25ce9abe191ef48963db357ec 100644 (file)
@@ -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
 -------------------------------------------------
index 9e0e630061a2050f65061fb0dbb8f40202c814f7..47383a205785d0752aabc034a28c28fb9677dc99 100644 (file)
@@ -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.
index d8b228f123a903d9651f81790aa05eb7c457caf7..a8dece1b90d5ae6a1067efede061f9ceecd6dbf4 100644 (file)
@@ -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);