erichkeane created this revision.
erichkeane added reviewers: eli.friedman, efriedma, craig.topper.

As reported here https://bugs.llvm.org/show_bug.cgi?id=42000, it was
possible to get the constexpr version of __builtin_*_overflow to give
the wrong answer.

This was because when extending the operands to fit the largest type (so
that the math could be done), the decision on whether to sign/zero
extend the operands was based on the result signedness, not on the
operands signedness.

In the reported case, (unsigned char)255 - (int)100 needed
to have each extended to the int in order to do the math.  However, when
extending the first operand to 'int', we incorrectly sign extended it
instead of zero extending.  Thus, the result didnt fit back into the
unsigned char.

The fix for this was simply to choose zero/sign extension based on the
sign of the operand itself.


https://reviews.llvm.org/D62665

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/builtins-overflow.cpp


Index: clang/test/SemaCXX/builtins-overflow.cpp
===================================================================
--- clang/test/SemaCXX/builtins-overflow.cpp
+++ clang/test/SemaCXX/builtins-overflow.cpp
@@ -2,6 +2,7 @@
 // expected-no-diagnostics
 
 #include <limits.h>
+#include <stdint.h>
 
 int a() {
   const int x = 3;
@@ -50,6 +51,7 @@
 static_assert(sub<unsigned char>(static_cast<char>(0),static_cast<char>(1)) == 
Result<unsigned char>{true, UCHAR_MAX});
 static_assert(sub<char>(static_cast<unsigned char>(0),static_cast<unsigned 
char>(1)) == Result<char>{false, -1});
 static_assert(sub<unsigned short>(static_cast<short>(0),static_cast<short>(1)) 
== Result<unsigned short>{true, USHRT_MAX});
+static_assert(sub<uint8_t>(static_cast<uint8_t>(255),static_cast<int>(100)) == 
Result<uint8_t>{false, 155});
 
 static_assert(sub<int>(17,22) == Result<int>{false, -5});
 static_assert(sub<int>(INT_MAX - 22, -23) == Result<int>{true, INT_MIN});
@@ -91,3 +93,4 @@
 static_assert(smul(17,22) == Result<int>{false, 374});
 static_assert(smul(INT_MAX / 22, 23) == Result<int>{true, -2049870757});
 static_assert(smul(INT_MIN / 22, -23) == Result<int>{true, -2049870757});
+
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -9453,9 +9453,11 @@
       if (IsSigned && !AllSigned)
         ++MaxBits;
 
-      LHS = APSInt(IsSigned ? LHS.sextOrSelf(MaxBits) : 
LHS.zextOrSelf(MaxBits),
+      LHS = APSInt(LHS.isSigned() ? LHS.sextOrSelf(MaxBits)
+                                  : LHS.zextOrSelf(MaxBits),
                    !IsSigned);
-      RHS = APSInt(IsSigned ? RHS.sextOrSelf(MaxBits) : 
RHS.zextOrSelf(MaxBits),
+      RHS = APSInt(RHS.isSigned() ? RHS.sextOrSelf(MaxBits)
+                                  : RHS.zextOrSelf(MaxBits),
                    !IsSigned);
       Result = APSInt(MaxBits, !IsSigned);
     }


Index: clang/test/SemaCXX/builtins-overflow.cpp
===================================================================
--- clang/test/SemaCXX/builtins-overflow.cpp
+++ clang/test/SemaCXX/builtins-overflow.cpp
@@ -2,6 +2,7 @@
 // expected-no-diagnostics
 
 #include <limits.h>
+#include <stdint.h>
 
 int a() {
   const int x = 3;
@@ -50,6 +51,7 @@
 static_assert(sub<unsigned char>(static_cast<char>(0),static_cast<char>(1)) == Result<unsigned char>{true, UCHAR_MAX});
 static_assert(sub<char>(static_cast<unsigned char>(0),static_cast<unsigned char>(1)) == Result<char>{false, -1});
 static_assert(sub<unsigned short>(static_cast<short>(0),static_cast<short>(1)) == Result<unsigned short>{true, USHRT_MAX});
+static_assert(sub<uint8_t>(static_cast<uint8_t>(255),static_cast<int>(100)) == Result<uint8_t>{false, 155});
 
 static_assert(sub<int>(17,22) == Result<int>{false, -5});
 static_assert(sub<int>(INT_MAX - 22, -23) == Result<int>{true, INT_MIN});
@@ -91,3 +93,4 @@
 static_assert(smul(17,22) == Result<int>{false, 374});
 static_assert(smul(INT_MAX / 22, 23) == Result<int>{true, -2049870757});
 static_assert(smul(INT_MIN / 22, -23) == Result<int>{true, -2049870757});
+
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -9453,9 +9453,11 @@
       if (IsSigned && !AllSigned)
         ++MaxBits;
 
-      LHS = APSInt(IsSigned ? LHS.sextOrSelf(MaxBits) : LHS.zextOrSelf(MaxBits),
+      LHS = APSInt(LHS.isSigned() ? LHS.sextOrSelf(MaxBits)
+                                  : LHS.zextOrSelf(MaxBits),
                    !IsSigned);
-      RHS = APSInt(IsSigned ? RHS.sextOrSelf(MaxBits) : RHS.zextOrSelf(MaxBits),
+      RHS = APSInt(RHS.isSigned() ? RHS.sextOrSelf(MaxBits)
+                                  : RHS.zextOrSelf(MaxBits),
                    !IsSigned);
       Result = APSInt(MaxBits, !IsSigned);
     }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to