]> granicus.if.org Git - clang/commitdiff
Implement the agreed resolution to DR1457: a signed left shift of a 1 bit into
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 8 Feb 2012 06:14:53 +0000 (06:14 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 8 Feb 2012 06:14:53 +0000 (06:14 +0000)
the sign bit doesn't have undefined behavior, but a signed left shift of a 1 bit
out of the sign bit still does. As promised to Howard :)

The suppression of the potential constant expression checking in system headers
is also removed, since the problem it was working around is gone.

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

include/clang/Basic/DiagnosticASTKinds.td
lib/AST/ExprConstant.cpp
lib/Sema/SemaDeclCXX.cpp
test/CXX/expr/expr.const/p2-0x.cpp
test/SemaCXX/constexpr-sysheaders.cpp [deleted file]

index ce1ca5b03867f85bbaa61670e6e77952eaa3f2b7..9e4b63cfe81c9d978dc554ddd6e6bd3c878f3d05 100644 (file)
@@ -24,6 +24,7 @@ def note_constexpr_negative_shift : Note<"negative shift count %0">;
 def note_constexpr_large_shift : Note<
   "shift count %0 >= width of type %1 (%2 bit%s2)">;
 def note_constexpr_lshift_of_negative : Note<"left shift of negative value %0">;
+def note_constexpr_lshift_discards : Note<"signed left shift discards bits">;
 def note_constexpr_invalid_function : Note<
   "%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot "
   "be used in a constant expression">;
index e33d22a4aa35cbdb950f9de6112dde631a367191..410406788dc4cff3ddb82db230ed2a99010a5167 100644 (file)
@@ -4704,12 +4704,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
         << RHS << E->getType() << LHS.getBitWidth();
     } else if (LHS.isSigned()) {
       // C++11 [expr.shift]p2: A signed left shift must have a non-negative
-      // operand, and must not overflow.
+      // operand, and must not overflow the corresponding unsigned type.
       if (LHS.isNegative())
         CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS;
-      else if (LHS.countLeadingZeros() <= SA)
-        HandleOverflow(Info, E, LHS.extend(LHS.getBitWidth() + SA) << SA,
-                       E->getType());
+      else if (LHS.countLeadingZeros() < SA)
+        CCEDiag(E, diag::note_constexpr_lshift_discards);
     }
 
     return Success(LHS << SA, E);
index 2c1642361b807d1b6c21872e21be00405cb71537..ca64af644f6f8813f58aee3a3cf28ea32b12e1c9 100644 (file)
@@ -984,13 +984,8 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body,
   // C++11 [dcl.constexpr]p4:
   //   - every constructor involved in initializing non-static data members and
   //     base class sub-objects shall be a constexpr constructor.
-  //
-  // FIXME: We currently disable this check inside system headers, to work
-  // around early STL implementations which contain constexpr functions which
-  // can't produce constant expressions.
   llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
-  if (!Context.getSourceManager().isInSystemHeader(Dcl->getLocation()) &&
-      !IsInstantiation && !Expr::isPotentialConstantExpr(Dcl, Diags)) {
+  if (!IsInstantiation && !Expr::isPotentialConstantExpr(Dcl, Diags)) {
     Diag(Dcl->getLocation(), diag::err_constexpr_function_never_constant_expr)
       << isa<CXXConstructorDecl>(Dcl);
     for (size_t I = 0, N = Diags.size(); I != N; ++I)
index 6c7a4947d783e01d1505ecac30b3a76404acea3d..71dc2f7104e47b7adb9479eec92c8a389cb27722 100644 (file)
@@ -144,8 +144,11 @@ namespace UndefinedBehavior {
   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_ok = 1 << 30; // ok
-  constexpr int shl_signed_into_sign = 1 << 31; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}}
-  constexpr int shl_signed_overflow = 1024 << 31; // expected-error {{constant expression}} expected-note {{value 2199023255552 is outside the range}} expected-warning {{requires 43 bits to represent}}
+  constexpr int shl_signed_into_sign = 1 << 31; // ok (DR1457)
+  constexpr int shl_signed_into_sign_2 = 0x7fffffff << 1; // ok (DR1457)
+  constexpr int shl_signed_off_end = 2 << 31; // expected-error {{constant expression}} expected-note {{signed left shift discards bits}} expected-warning {{signed shift result (0x100000000) requires 34 bits to represent, but 'int' only has 32 bits}}
+  constexpr int shl_signed_off_end_2 = 0x7fffffff << 2; // expected-error {{constant expression}} expected-note {{signed left shift discards bits}} expected-warning {{signed shift result (0x1FFFFFFFC) requires 34 bits to represent, but 'int' only has 32 bits}}
+  constexpr int shl_signed_overflow = 1024 << 31; // expected-error {{constant expression}} expected-note {{signed left shift discards bits}} expected-warning {{requires 43 bits to represent}}
   constexpr int shl_signed_ok2 = 1024 << 20; // ok
 
   constexpr int shr_m1 = 0 >> -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}} expected-warning {{negative}}
diff --git a/test/SemaCXX/constexpr-sysheaders.cpp b/test/SemaCXX/constexpr-sysheaders.cpp
deleted file mode 100644 (file)
index 5f9a712..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -include %s %s
-
-// libstdc++4.6 has a broken numeric_limits with a non-constant min() for signed
-// integral types. Disable the 'never produces a constant expression' error in
-// system headers to work around it. We still won't treat the function as
-// producing a constant expression, though.
-
-#ifndef INCLUDED_HEADER
-#define INCLUDED_HEADER
-
-#pragma GCC system_header
-
-// An approximation of libstdc++4.6's broken definition of numeric_limits.
-// FIXME: In the -include case, the line numbers are off by one for some reason!
-struct numeric_limits { // expected-note {{value 2147483648 is outside the range}}
-  static constexpr int min() throw() { return (int)1 << (sizeof(int) * 8 - 1); } // no-error
-  // expected-note {{in call to 'min()'}}
-  static constexpr int lowest() throw() { return min(); }
-};
-
-#else
-
-constexpr int k = numeric_limits::lowest(); // expected-error {{constant expression}} expected-note {{in call to 'lowest()'}}
-
-#endif