[cfe-commits] r149344 - in /cfe/trunk: include/clang/Basic/DiagnosticASTKinds.td lib/AST/ExprConstant.cpp test/CXX/expr/expr.const/p2-0x.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Mon Jan 30 20:08:20 PST 2012
Author: rsmith
Date: Mon Jan 30 22:08:20 2012
New Revision: 149344
URL: http://llvm.org/viewvc/llvm-project?rev=149344&view=rev
Log:
constexpr: catch a collection of integral undefined behaviors:
-INT_MIN and INT_MIN / -1
Shift by a negative or too large quantity
Left shift of negative value
Overflow in left shift
Modified:
cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=149344&r1=149343&r2=149344&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Mon Jan 30 22:08:20 2012
@@ -20,6 +20,10 @@
"cannot cast object of dynamic type %0 to type %1">;
def note_constexpr_overflow : Note<
"value %0 is outside the range of representable values of type %1">;
+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_invalid_function : Note<
"%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot "
"be used in a constant expression">;
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=149344&r1=149343&r2=149344&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Mon Jan 30 22:08:20 2012
@@ -348,6 +348,24 @@
*Diag << v;
return *this;
}
+
+ OptionalDiagnostic &operator<<(const APSInt &I) {
+ if (Diag) {
+ llvm::SmallVector<char, 32> Buffer;
+ I.toString(Buffer);
+ *Diag << StringRef(Buffer.data(), Buffer.size());
+ }
+ return *this;
+ }
+
+ OptionalDiagnostic &operator<<(const APFloat &F) {
+ if (Diag) {
+ llvm::SmallVector<char, 32> Buffer;
+ F.toString(Buffer);
+ *Diag << StringRef(Buffer.data(), Buffer.size());
+ }
+ return *this;
+ }
};
struct EvalInfo {
@@ -1052,10 +1070,8 @@
template<typename T>
static bool HandleOverflow(EvalInfo &Info, const Expr *E,
const T &SrcValue, QualType DestType) {
- llvm::SmallVector<char, 32> Buffer;
- SrcValue.toString(Buffer);
Info.Diag(E->getExprLoc(), diag::note_constexpr_overflow)
- << StringRef(Buffer.data(), Buffer.size()) << DestType;
+ << SrcValue << DestType;
return false;
}
@@ -4405,33 +4421,60 @@
case BO_Div:
if (RHS == 0)
return Error(E, diag::note_expr_divide_by_zero);
+ // Check for overflow case: INT_MIN / -1.
+ if (RHS.isNegative() && RHS.isAllOnesValue() &&
+ LHS.isSigned() && LHS.isMinSignedValue())
+ HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType());
return Success(LHS / RHS, E);
case BO_Rem:
if (RHS == 0)
return Error(E, diag::note_expr_divide_by_zero);
return Success(LHS % RHS, E);
case BO_Shl: {
- // During constant-folding, a negative shift is an opposite shift.
+ // During constant-folding, a negative shift is an opposite shift. Such a
+ // shift is not a constant expression.
if (RHS.isSigned() && RHS.isNegative()) {
+ CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
RHS = -RHS;
goto shift_right;
}
shift_left:
- unsigned SA
- = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of the
+ // shifted type.
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ if (SA != RHS) {
+ CCEDiag(E, diag::note_constexpr_large_shift)
+ << 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.
+ 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());
+ }
+
return Success(LHS << SA, E);
}
case BO_Shr: {
- // During constant-folding, a negative shift is an opposite shift.
+ // During constant-folding, a negative shift is an opposite shift. Such a
+ // shift is not a constant expression.
if (RHS.isSigned() && RHS.isNegative()) {
+ CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
RHS = -RHS;
goto shift_left;
}
shift_right:
- unsigned SA =
- (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of the
+ // shifted type.
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ if (SA != RHS)
+ CCEDiag(E, diag::note_constexpr_large_shift)
+ << RHS << E->getType() << LHS.getBitWidth();
+
return Success(LHS >> SA, E);
}
@@ -4605,7 +4648,11 @@
if (!Visit(E->getSubExpr()))
return false;
if (!Result.isInt()) return Error(E);
- return Success(-Result.getInt(), E);
+ const APSInt &Value = Result.getInt();
+ if (Value.isSigned() && Value.isMinSignedValue())
+ HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
+ E->getType());
+ return Success(-Value, E);
}
case UO_Not: {
if (!Visit(E->getSubExpr()))
Modified: cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp?rev=149344&r1=149343&r2=149344&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp Mon Jan 30 22:08:20 2012
@@ -129,6 +129,30 @@
}
}
+ constexpr int int_min = ~0x7fffffff;
+ constexpr int minus_int_min = -int_min; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}}
+ constexpr int div0 = 3 / 0; // expected-error {{constant expression}} expected-note {{division by zero}} expected-warning {{undefined}}
+ constexpr int mod0 = 3 % 0; // expected-error {{constant expression}} expected-note {{division by zero}} expected-warning {{undefined}}
+ constexpr int int_min_div_minus_1 = int_min / -1; // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range}}
+
+ constexpr int shl_m1 = 0 << -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}} expected-warning {{negative}}
+ constexpr int shl_0 = 0 << 0; // ok
+ constexpr int shl_31 = 0 << 31; // ok
+ constexpr int shl_32 = 0 << 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type 'int' (32}} expected-warning {{>= width of type}}
+ 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_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_ok2 = 1024 << 20; // ok
+
+ constexpr int shr_m1 = 0 >> -1; // expected-error {{constant expression}} expected-note {{negative shift count -1}} expected-warning {{negative}}
+ constexpr int shr_0 = 0 >> 0; // ok
+ constexpr int shr_31 = 0 >> 31; // ok
+ constexpr int shr_32 = 0 >> 32; // expected-error {{constant expression}} expected-note {{shift count 32 >= width of type}} expected-warning {{>= width of type}}
+
struct S {
int m;
};
More information about the cfe-commits
mailing list