diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-30 22:27:01 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-30 22:27:01 +0000 |
commit | f72fccf533bca206af8e75d041c29db99e6a7f2c (patch) | |
tree | 024c4044375c5ed02ffc50aad332ce8fb680da2f | |
parent | acd8c513b9db3a166b5409cd8e75712a7157b7b6 (diff) |
constexpr: disallow signed integer overflow in integral conversions in constant
expressions in C++11.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149286 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/AST/ExprConstant.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 18 | ||||
-rw-r--r-- | test/CXX/expr/expr.const/p2-0x.cpp | 3 |
3 files changed, 36 insertions, 12 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index d50a4fb830..d2d651c97f 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -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; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 91630e8d74..f681a589cf 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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 diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp index 2570c60512..4b425da73c 100644 --- a/test/CXX/expr/expr.const/p2-0x.cpp +++ b/test/CXX/expr/expr.const/p2-0x.cpp @@ -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 |