]> granicus.if.org Git - clang/commitdiff
[Sema] Warn when shifting a negative value.
authorDavide Italiano <davide@freebsd.org>
Mon, 6 Jul 2015 18:02:09 +0000 (18:02 +0000)
committerDavide Italiano <davide@freebsd.org>
Mon, 6 Jul 2015 18:02:09 +0000 (18:02 +0000)
Example:
 % ./clang -Wshift-negative-value emit.c
emit.c:3:14: warning: shifting a negative signed value is undefined [-Wshift-negative-value]
  int a = -1 << 3;
          ~~ ^
1 warning generated.

PR: 24026
Differential Revision:  http://reviews.llvm.org/D10938
Reviewed by: rsmith

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241478 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExpr.cpp
test/CXX/expr/expr.const/p2-0x.cpp
test/Sema/shift.c

index 750219483c6c3deff4229dadcff2ecad62db5331..39b602c55142f26c528cfb1bd224914a1003a633 100644 (file)
@@ -4740,6 +4740,8 @@ def warn_division_by_zero : Warning<"division by zero is undefined">,
   InGroup<DivZero>;
 def warn_remainder_by_zero : Warning<"remainder by zero is undefined">,
   InGroup<DivZero>;
+def warn_shift_lhs_negative : Warning<"shifting a negative signed value is undefined">,
+  InGroup<DiagGroup<"shift-negative-value">>;
 def warn_shift_negative : Warning<"shift count is negative">,
   InGroup<DiagGroup<"shift-count-negative">>;
 def warn_shift_gt_typewidth : Warning<"shift count >= width of type">,
index c023c8523a39c8b04aaa96bd457a3c8c46929c59..01a4d488057011488c8b3fc69c2f8af611b7b0c3 100644 (file)
@@ -7937,9 +7937,19 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
   // representable in the result type, so never warn for those.
   llvm::APSInt Left;
   if (LHS.get()->isValueDependent() ||
-      !LHS.get()->isIntegerConstantExpr(Left, S.Context) ||
-      LHSType->hasUnsignedIntegerRepresentation())
+      LHSType->hasUnsignedIntegerRepresentation() ||
+      !LHS.get()->EvaluateAsInt(Left, S.Context))
     return;
+
+  // If LHS does not have a signed type and non-negative value
+  // then, the behavior is undefined. Warn about it.
+  if (Left.isNegative()) {
+    S.DiagRuntimeBehavior(Loc, LHS.get(),
+                          S.PDiag(diag::warn_shift_lhs_negative)
+                            << LHS.get()->getSourceRange());
+    return;
+  }
+
   llvm::APInt ResultBits =
       static_cast<llvm::APInt&>(Right) + Left.getMinSignedBits();
   if (LeftBits.uge(ResultBits))
index d027c7a388bb337efb64bb2454465905a812e7a9..2adefd928afb6282cf13c030f8c812c0c5987a77 100644 (file)
@@ -157,7 +157,7 @@ namespace UndefinedBehavior {
   constexpr int shl_unsigned_negative = unsigned(-3) << 1; // ok
   constexpr int shl_unsigned_into_sign = 1u << 31; // ok
   constexpr int shl_unsigned_overflow = 1024u << 31; // ok
-  constexpr int shl_signed_negative = (-3) << 1; // expected-error {{constant expression}} expected-note {{left shift of negative value -3}}
+  constexpr int shl_signed_negative = (-3) << 1; // expected-warning {{shifting a negative signed value is undefined}} // expected-error {{constant expression}} expected-note {{left shift of negative value -3}}
   constexpr int shl_signed_ok = 1 << 30; // ok
   constexpr int shl_signed_into_sign = 1 << 31; // ok (DR1457)
   constexpr int shl_signed_into_sign_2 = 0x7fffffff << 1; // ok (DR1457)
index d355544885135956ed0aa377881ccce31ac8616e..07c5fe5280ed998649f18b731d8cb659af0b19f9 100644 (file)
@@ -39,7 +39,8 @@ void test() {
   i = 1 << (WORD_BIT - 2);
   i = 2 << (WORD_BIT - 1); // expected-warning {{bits to represent, but 'int' only has}}
   i = 1 << (WORD_BIT - 1); // expected-warning {{sets the sign bit of the shift expression}}
-  i = -1 << (WORD_BIT - 1);
+  i = -1 << (WORD_BIT - 1); // expected-warning {{shifting a negative signed value is undefined}}
+  i = -1 << 0; // expected-warning {{shifting a negative signed value is undefined}}
   i = 0 << (WORD_BIT - 1);
   i = (char)1 << (WORD_BIT - 2);
 
@@ -48,7 +49,7 @@ void test() {
   u = 5U << (WORD_BIT - 1);
 
   long long int lli;
-  lli = INT_MIN << 2; // expected-warning {{bits to represent, but 'int' only has}}
+  lli = INT_MIN << 2; // expected-warning {{shifting a negative signed value is undefined}}
   lli = 1LL << (sizeof(long long) * CHAR_BIT - 2);
 }