r181376 - C++1y constant expression evaluation: compound assignment support for floating-point and pointer types.

Richard Smith richard-llvm at metafoo.co.uk
Tue May 7 16:34:45 PDT 2013


Author: rsmith
Date: Tue May  7 18:34:45 2013
New Revision: 181376

URL: http://llvm.org/viewvc/llvm-project?rev=181376&view=rev
Log:
C++1y constant expression evaluation: compound assignment support for floating-point and pointer types.

Modified:
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=181376&r1=181375&r2=181376&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Tue May  7 18:34:45 2013
@@ -23,8 +23,8 @@
 //    where it is possible to determine the evaluated result regardless.
 //
 //  * A set of notes indicating why the evaluation was not a constant expression
-//    (under the C++11 rules only, at the moment), or, if folding failed too,
-//    why the expression could not be folded.
+//    (under the C++11 / C++1y rules only, at the moment), or, if folding failed
+//    too, why the expression could not be folded.
 //
 // If we are checking for a potential constant expression, failure to constant
 // fold a potential constant sub-expression will be indicated by a 'false'
@@ -925,6 +925,13 @@ static bool EvaluateIgnoredValue(EvalInf
   return true;
 }
 
+/// Sign- or zero-extend a value to 64 bits. If it's already 64 bits, just
+/// return its existing value.
+static int64_t getExtValue(const APSInt &Value) {
+  return Value.isSigned() ? Value.getSExtValue()
+                          : static_cast<int64_t>(Value.getZExtValue());
+}
+
 /// Should this call expression be treated as a string literal?
 static bool IsStringLiteralCall(const CallExpr *E) {
   unsigned Builtin = E->isBuiltinCall();
@@ -1421,6 +1428,33 @@ static bool handleIntIntBinOp(EvalInfo &
   }
 }
 
+/// Perform the given binary floating-point operation, in-place, on LHS.
+static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E,
+                                  APFloat &LHS, BinaryOperatorKind Opcode,
+                                  const APFloat &RHS) {
+  switch (Opcode) {
+  default:
+    Info.Diag(E);
+    return false;
+  case BO_Mul:
+    LHS.multiply(RHS, APFloat::rmNearestTiesToEven);
+    break;
+  case BO_Add:
+    LHS.add(RHS, APFloat::rmNearestTiesToEven);
+    break;
+  case BO_Sub:
+    LHS.subtract(RHS, APFloat::rmNearestTiesToEven);
+    break;
+  case BO_Div:
+    LHS.divide(RHS, APFloat::rmNearestTiesToEven);
+    break;
+  }
+
+  if (LHS.isInfinity() || LHS.isNaN())
+    Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
+  return true;
+}
+
 /// Cast an lvalue referring to a base subobject to a derived class, by
 /// truncating the lvalue's path to the given length.
 static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
@@ -1737,7 +1771,7 @@ static void expandArray(APValue &Array,
   Array.swap(NewValue);
 }
 
-/// Kinds of access we can perform on an object.
+/// Kinds of access we can perform on an object, for diagnostics.
 enum AccessKinds {
   AK_Read,
   AK_Assign,
@@ -2340,12 +2374,11 @@ struct CompoundAssignSubobjectHandler {
     return true;
   }
   bool found(APFloat &Value, QualType SubobjType) {
-    if (!checkConst(SubobjType))
-      return false;
-
-    // FIXME: Implement.
-    Info.Diag(E);
-    return false;
+    return checkConst(SubobjType) &&
+           HandleFloatToFloatCast(Info, E, SubobjType, PromotedLHSType,
+                                  Value) &&
+           handleFloatFloatBinOp(Info, E, Value, Opcode, RHS.getFloat()) &&
+           HandleFloatToFloatCast(Info, E, PromotedLHSType, SubobjType, Value);
   }
   bool foundPointer(APValue &Subobj, QualType SubobjType) {
     if (!checkConst(SubobjType))
@@ -2354,14 +2387,23 @@ struct CompoundAssignSubobjectHandler {
     QualType PointeeType;
     if (const PointerType *PT = SubobjType->getAs<PointerType>())
       PointeeType = PT->getPointeeType();
-    else {
+
+    if (PointeeType.isNull() || !RHS.isInt() ||
+        (Opcode != BO_Add && Opcode != BO_Sub)) {
       Info.Diag(E);
       return false;
     }
 
-    // FIXME: Implement.
-    Info.Diag(E);
-    return false;
+    int64_t Offset = getExtValue(RHS.getInt());
+    if (Opcode == BO_Sub)
+      Offset = -Offset;
+
+    LValue LVal;
+    LVal.setFrom(Info.Ctx, Subobj);
+    if (!HandleLValueArrayAdjustment(Info, E, LVal, PointeeType, Offset))
+      return false;
+    LVal.moveInto(Subobj);
+    return true;
   }
   bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) {
     llvm_unreachable("shouldn't encounter string elements here");
@@ -3829,11 +3871,9 @@ bool LValueExprEvaluator::VisitArraySubs
   APSInt Index;
   if (!EvaluateInteger(E->getIdx(), Index, Info))
     return false;
-  int64_t IndexValue
-    = Index.isSigned() ? Index.getSExtValue()
-                       : static_cast<int64_t>(Index.getZExtValue());
 
-  return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), IndexValue);
+  return HandleLValueArrayAdjustment(Info, E, Result, E->getType(),
+                                     getExtValue(Index));
 }
 
 bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
@@ -3986,9 +4026,8 @@ bool PointerExprEvaluator::VisitBinaryOp
   llvm::APSInt Offset;
   if (!EvaluateInteger(IExp, Offset, Info) || !EvalPtrOK)
     return false;
-  int64_t AdditionalOffset
-    = Offset.isSigned() ? Offset.getSExtValue()
-                        : static_cast<int64_t>(Offset.getZExtValue());
+
+  int64_t AdditionalOffset = getExtValue(Offset);
   if (E->getOpcode() == BO_Sub)
     AdditionalOffset = -AdditionalOffset;
 
@@ -6137,7 +6176,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr
       CurrentType = AT->getElementType();
       CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType);
       Result += IdxResult.getSExtValue() * ElementSize;
-        break;
+      break;
     }
 
     case OffsetOfExpr::OffsetOfNode::Field: {
@@ -6568,28 +6607,8 @@ bool FloatExprEvaluator::VisitBinaryOper
   bool LHSOK = EvaluateFloat(E->getLHS(), Result, Info);
   if (!LHSOK && !Info.keepEvaluatingAfterFailure())
     return false;
-  if (!EvaluateFloat(E->getRHS(), RHS, Info) || !LHSOK)
-    return false;
-
-  switch (E->getOpcode()) {
-  default: return Error(E);
-  case BO_Mul:
-    Result.multiply(RHS, APFloat::rmNearestTiesToEven);
-    break;
-  case BO_Add:
-    Result.add(RHS, APFloat::rmNearestTiesToEven);
-    break;
-  case BO_Sub:
-    Result.subtract(RHS, APFloat::rmNearestTiesToEven);
-    break;
-  case BO_Div:
-    Result.divide(RHS, APFloat::rmNearestTiesToEven);
-    break;
-  }
-
-  if (Result.isInfinity() || Result.isNaN())
-    CCEDiag(E, diag::note_constexpr_float_arithmetic) << Result.isNaN();
-  return true;
+  return EvaluateFloat(E->getRHS(), RHS, Info) && LHSOK &&
+         handleFloatFloatBinOp(Info, E, Result, E->getOpcode(), RHS);
 }
 
 bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=181376&r1=181375&r2=181376&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Tue May  7 18:34:45 2013
@@ -338,34 +338,63 @@ namespace compound_assign {
   constexpr bool test_int() {
     int a = 3;
     a += 6;
-    if (a != 9) throw 0;
+    if (a != 9) return false;
     a -= 2;
-    if (a != 7) throw 0;
+    if (a != 7) return false;
     a *= 3;
-    if (a != 21) throw 0;
-    a /= 10;
-    if (a != 2) throw 0;
+    if (a != 21) return false;
+    if (&(a /= 10) != &a) return false;
+    if (a != 2) return false;
     a <<= 3;
-    if (a != 16) throw 0;
+    if (a != 16) return false;
     a %= 6;
-    if (a != 4) throw 0;
+    if (a != 4) return false;
     a >>= 1;
-    if (a != 2) throw 0;
+    if (a != 2) return false;
     a ^= 10;
-    if (a != 8) throw 0;
+    if (a != 8) return false;
     a |= 5;
-    if (a != 13) throw 0;
+    if (a != 13) return false;
     a &= 14;
-    if (a != 12) throw 0;
+    if (a != 12) return false;
     return true;
   }
   static_assert(test_int(), "");
 
+  constexpr bool test_float() {
+    float f = 123.;
+    f *= 2;
+    if (f != 246.) return false;
+    if ((f -= 0.5) != 245.5) return false;
+    if (f != 245.5) return false;
+    f /= 0.5;
+    if (f != 491.) return false;
+    f += -40;
+    if (f != 451.) return false;
+    return true;
+  }
+  static_assert(test_float(), "");
+
+  constexpr bool test_ptr() {
+    int arr[123] = {};
+    int *p = arr;
+    if ((p += 4) != &arr[4]) return false;
+    if (p != &arr[4]) return false;
+    p += -1;
+    if (p != &arr[3]) return false;
+    if ((p -= -10) != &arr[13]) return false;
+    if (p != &arr[13]) return false;
+    p -= 11;
+    if (p != &arr[2]) return false;
+    return true;
+  }
+  static_assert(test_ptr(), "");
+
   template<typename T>
   constexpr bool test_overflow() {
     T a = 1;
-    while (a)
-      a *= 2; // expected-note {{value 2147483648 is outside the range}} expected-note {{ 9223372036854775808 }}
+    while (a != a / 2)
+      a *= 2; // expected-note {{value 2147483648 is outside the range}} expected-note {{ 9223372036854775808 }} expected-note {{floating point arithmetic produces an infinity}}
     return true;
   }
 
@@ -375,6 +404,7 @@ namespace compound_assign {
   static_assert(test_overflow<unsigned short>(), ""); // ok
   static_assert(test_overflow<unsigned long long>(), ""); // ok
   static_assert(test_overflow<long long>(), ""); // expected-error {{constant}} expected-note {{call}}
+  static_assert(test_overflow<float>(), ""); // expected-error {{constant}} expected-note {{call}}
 
   constexpr short test_promotion(short k) {
     short s = k;
@@ -384,6 +414,17 @@ namespace compound_assign {
   static_assert(test_promotion(100) == 10000, "");
   static_assert(test_promotion(200) == -25536, "");
   static_assert(test_promotion(256) == 0, "");
+
+  constexpr const char *test_bounds(const char *p, int o) {
+    return p += o; // expected-note {{element 5 of}} expected-note {{element -1 of}} expected-note {{element 1000 of}}
+  }
+  static_assert(test_bounds("foo", 0)[0] == 'f', "");
+  static_assert(test_bounds("foo", 3)[0] == 0, "");
+  static_assert(test_bounds("foo", 4)[-3] == 'o', "");
+  static_assert(test_bounds("foo" + 4, -4)[0] == 'f', "");
+  static_assert(test_bounds("foo", 5) != 0, ""); // expected-error {{constant}} expected-note {{call}}
+  static_assert(test_bounds("foo", -1) != 0, ""); // expected-error {{constant}} expected-note {{call}}
+  static_assert(test_bounds("foo", 1000) != 0, ""); // expected-error {{constant}} expected-note {{call}}
 }
 
 namespace loops {





More information about the cfe-commits mailing list