constexpr: disallow signed integer overflow in integral conversions in constant

expressions in C++11.

llvm-svn: 149286
This commit is contained in:
Richard Smith 2012-01-30 22:27:01 +00:00
parent aa11e6e28c
commit 911e142f03
3 changed files with 36 additions and 12 deletions

View File

@ -1086,13 +1086,21 @@ static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E,
return true;
}
static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
APSInt &Value, const ASTContext &Ctx) {
unsigned DestWidth = Ctx.getIntWidth(DestType);
static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E,
QualType DestType, QualType SrcType,
APSInt &Value) {
unsigned DestWidth = Info.Ctx.getIntWidth(DestType);
APSInt Result = Value;
// Figure out if this is a truncate, extend or noop cast.
// If the input is signed, do a sign extend, noop, or truncate.
Result = Result.extOrTrunc(DestWidth);
// Check whether we overflowed. If so, fold the cast anyway.
if (DestType->isSignedIntegerOrEnumerationType() &&
((Result.isNegative() && Value.isUnsigned()) ||
Result.extOrTrunc(Value.getBitWidth()) != Value))
(void)HandleOverflow(Info, E, Value, DestType);
Result.setIsUnsigned(DestType->isUnsignedIntegerOrEnumerationType());
return Result;
}
@ -4703,8 +4711,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType);
}
return Success(HandleIntToIntCast(DestType, SrcType,
Result.getInt(), Info.Ctx), E);
return Success(HandleIntToIntCast(Info, E, DestType, SrcType,
Result.getInt()), E);
}
case CK_PointerToIntegral: {
@ -4716,6 +4724,9 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (LV.getLValueBase()) {
// Only allow based lvalue casts if they are lossless.
// FIXME: Allow a larger integer size than the pointer size, and allow
// narrowing back down to pointer width in subsequent integral casts.
// FIXME: Check integer type's active bits, not its type size.
if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(SrcType))
return Error(E);
@ -4726,7 +4737,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset().getQuantity(),
SrcType);
return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E);
return Success(HandleIntToIntCast(Info, E, DestType, SrcType, AsInt), E);
}
case CK_IntegralComplexToReal: {
@ -5200,8 +5211,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
QualType From
= E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
Result.IntReal = HandleIntToIntCast(To, From, Result.IntReal, Info.Ctx);
Result.IntImag = HandleIntToIntCast(To, From, Result.IntImag, Info.Ctx);
Result.IntReal = HandleIntToIntCast(Info, E, To, From, Result.IntReal);
Result.IntImag = HandleIntToIntCast(Info, E, To, From, Result.IntImag);
return true;
}

View File

@ -4646,6 +4646,7 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
// Check for a narrowing implicit conversion.
APValue PreNarrowingValue;
bool Diagnosed = false;
switch (SCS->getNarrowingKind(Context, Result.get(), PreNarrowingValue)) {
case NK_Variable_Narrowing:
// Implicit conversion to a narrower type, and the value is not a constant
@ -4657,11 +4658,13 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
Diag(From->getSourceRange().getBegin(), diag::err_cce_narrowing)
<< CCE << /*Constant*/1
<< PreNarrowingValue.getAsString(Context, QualType()) << T;
Diagnosed = true;
break;
case NK_Type_Narrowing:
Diag(From->getSourceRange().getBegin(), diag::err_cce_narrowing)
<< CCE << /*Constant*/0 << From->getType() << T;
Diagnosed = true;
break;
}
@ -4674,12 +4677,19 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
// The expression can't be folded, so we can't keep it at this position in
// the AST.
Result = ExprError();
} else if (Notes.empty()) {
// It's a constant expression.
} else {
Value = Eval.Val.getInt();
return Result;
if (Notes.empty()) {
// It's a constant expression.
return Result;
}
}
// Only issue one narrowing diagnostic.
if (Diagnosed)
return Result;
// It's not a constant expression. Produce an appropriate diagnostic.
if (Notes.size() == 1 &&
Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr)
@ -4690,7 +4700,7 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
for (unsigned I = 0; I < Notes.size(); ++I)
Diag(Notes[I].first, Notes[I].second);
}
return ExprError();
return Result;
}
/// dropPointerConversions - If the given standard conversion sequence

View File

@ -118,6 +118,9 @@ namespace UndefinedBehavior {
void f(int n) {
switch (n) {
case (int)4.4e9: // expected-error {{constant expression}} expected-note {{value 4.4E+9 is outside the range of representable values of type 'int'}}
case (int)10000000000ll: // expected-error {{constant expression}} expected-note {{value 10000000000 is outside the range of representable values of type 'int'}} expected-note {{here}}
case (int)0x80000000u: // expected-error {{constant expression}} expected-note {{value 2147483648 is outside the range of representable values of type 'int'}}
case (unsigned int)10000000000ll: // expected-error {{duplicate case value}}
case (int)(unsigned)(long long)4.4e9: // ok
case (int)(float)1e300: // expected-error {{constant expression}} expected-note {{value 1.0E+300 is outside the range of representable values of type 'float'}}
case (int)((float)1e37 / 1e30): // ok