[cfe-commits] r143329 - in /cfe/trunk: lib/AST/ExprConstant.cpp test/SemaCXX/constant-expression-cxx11.cpp

Richard Smith richard-llvm at metafoo.co.uk
Sun Oct 30 18:37:14 PDT 2011


Author: rsmith
Date: Sun Oct 30 20:37:14 2011
New Revision: 143329

URL: http://llvm.org/viewvc/llvm-project?rev=143329&view=rev
Log:
C++11 generalized constant expressions: support pointer comparisons where the
result is not unspecified.

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

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143329&r1=143328&r2=143329&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sun Oct 30 20:37:14 2011
@@ -195,9 +195,10 @@
     CharUnits Offset;
     unsigned CallIndex;
 
-    const Expr *getLValueBase() { return Base; }
+    const Expr *getLValueBase() const { return Base; }
     CharUnits &getLValueOffset() { return Offset; }
-    unsigned getLValueCallIndex() { return CallIndex; }
+    const CharUnits &getLValueOffset() const { return Offset; }
+    unsigned getLValueCallIndex() const { return CallIndex; }
 
     void moveInto(CCValue &V) const {
       V = CCValue(Base, Offset, CallIndex);
@@ -416,6 +417,23 @@
   return Quals.hasConst() && !Quals.hasVolatile();
 }
 
+const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
+  if (!LVal.Base)
+    return 0;
+
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LVal.Base))
+    return DRE->getDecl();
+
+  // FIXME: Static data members accessed via a MemberExpr are represented as
+  // that MemberExpr. We should use the Decl directly instead.
+  if (const MemberExpr *ME = dyn_cast<MemberExpr>(LVal.Base)) {
+    assert(!isa<FieldDecl>(ME->getMemberDecl()) && "shouldn't see fields here");
+    return ME->getMemberDecl();
+  }
+
+  return 0;
+}
+
 bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
                                     const LValue &LVal, CCValue &RVal) {
   const Expr *Base = LVal.Base;
@@ -431,26 +449,12 @@
   if (!LVal.Offset.isZero())
     return false;
 
-  const Decl *D = 0;
-
-  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
+  if (const ValueDecl *D = GetLValueBaseDecl(LVal)) {
     // If the lvalue has been cast to some other type, don't try to read it.
     // FIXME: Could simulate a bitcast here.
-    if (!Info.Ctx.hasSameUnqualifiedType(Type, DRE->getType()))
-      return false;
-    D = DRE->getDecl();
-  }
-
-  // FIXME: Static data members accessed via a MemberExpr are represented as
-  // that MemberExpr. We should use the Decl directly instead.
-  if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base)) {
-    if (!Info.Ctx.hasSameUnqualifiedType(Type, ME->getType()))
-      return false;
-    D = ME->getMemberDecl();
-    assert(!isa<FieldDecl>(D) && "shouldn't see fields here");
-  }
+    if (!Info.Ctx.hasSameUnqualifiedType(Type, D->getType()))
+      return 0;
 
-  if (D) {
     // In C++98, const, non-volatile integers initialized with ICEs are ICEs.
     // In C++11, constexpr, non-volatile variables initialized with constant
     // expressions are constant expressions too. Inside constexpr functions,
@@ -1767,6 +1771,25 @@
   }
 }
 
+static bool HasSameBase(const LValue &A, const LValue &B) {
+  if (!A.getLValueBase())
+    return !B.getLValueBase();
+  if (!B.getLValueBase())
+    return false;
+
+  if (A.getLValueBase() != B.getLValueBase()) {
+    const Decl *ADecl = GetLValueBaseDecl(A);
+    if (!ADecl)
+      return false;
+    const Decl *BDecl = GetLValueBaseDecl(B);
+    if (ADecl != BDecl)
+      return false;
+  }
+
+  return IsGlobalLValue(A.getLValueBase()) ||
+         A.getLValueCallIndex() == B.getLValueCallIndex();
+}
+
 bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
   if (E->isAssignmentOp())
     return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E);
@@ -1890,7 +1913,7 @@
   }
 
   if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
-    if (E->getOpcode() == BO_Sub || E->isEqualityOp()) {
+    if (E->getOpcode() == BO_Sub || E->isComparisonOp()) {
       LValue LHSValue;
       if (!EvaluatePointer(E->getLHS(), LHSValue, Info))
         return false;
@@ -1899,24 +1922,17 @@
       if (!EvaluatePointer(E->getRHS(), RHSValue, Info))
         return false;
 
-      // Reject any bases from the normal codepath; we special-case comparisons
-      // to null.
-      if (LHSValue.getLValueBase()) {
+      // Reject differing bases from the normal codepath; we special-case
+      // comparisons to null.
+      if (!HasSameBase(LHSValue, RHSValue)) {
         if (!E->isEqualityOp())
           return false;
-        if (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero())
+        if ((LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero())&&
+            (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero()))
           return false;
+        LValue &NonNull = LHSValue.getLValueBase() ? LHSValue : RHSValue;
         bool bres;
-        if (!EvalPointerValueAsBool(LHSValue, bres))
-          return false;
-        return Success(bres ^ (E->getOpcode() == BO_EQ), E);
-      } else if (RHSValue.getLValueBase()) {
-        if (!E->isEqualityOp())
-          return false;
-        if (LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero())
-          return false;
-        bool bres;
-        if (!EvalPointerValueAsBool(RHSValue, bres))
+        if (!EvalPointerValueAsBool(NonNull, bres))
           return false;
         return Success(bres ^ (E->getOpcode() == BO_EQ), E);
       }
@@ -1933,13 +1949,18 @@
                              RHSValue.getLValueOffset();
         return Success(Diff / ElementSize, E);
       }
-      bool Result;
-      if (E->getOpcode() == BO_EQ) {
-        Result = LHSValue.getLValueOffset() == RHSValue.getLValueOffset();
-      } else {
-        Result = LHSValue.getLValueOffset() != RHSValue.getLValueOffset();
+
+      const CharUnits &LHSOffset = LHSValue.getLValueOffset();
+      const CharUnits &RHSOffset = RHSValue.getLValueOffset();
+      switch (E->getOpcode()) {
+      default: llvm_unreachable("missing comparison operator");
+      case BO_LT: return Success(LHSOffset < RHSOffset, E);
+      case BO_GT: return Success(LHSOffset > RHSOffset, E);
+      case BO_LE: return Success(LHSOffset <= RHSOffset, E);
+      case BO_GE: return Success(LHSOffset >= RHSOffset, E);
+      case BO_EQ: return Success(LHSOffset == RHSOffset, E);
+      case BO_NE: return Success(LHSOffset != RHSOffset, E);
       }
-      return Success(Result, E);
     }
   }
   if (!LHSTy->isIntegralOrEnumerationType() ||

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=143329&r1=143328&r2=143329&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Sun Oct 30 20:37:14 2011
@@ -157,3 +157,41 @@
   constexpr int Invalid = Apply(Select(0), 0); // expected-error {{must be initialized by a constant expression}}
 
 }
+
+namespace PointerComparison {
+
+int x, y;
+constexpr bool g1 = &x == &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool g2 = &x != &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool g3 = &x <= &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool g4 = &x >= &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool g5 = &x < &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool g6 = &x > &y; // expected-error {{must be initialized by a constant expression}}
+
+struct S { int x, y; } s;
+constexpr bool m1 = &s.x == &s.y;
+constexpr bool m2 = &s.x != &s.y;
+constexpr bool m3 = &s.x <= &s.y;
+constexpr bool m4 = &s.x >= &s.y;
+constexpr bool m5 = &s.x < &s.y;
+constexpr bool m6 = &s.x > &s.y;
+
+constexpr bool n1 = 0 == &y;
+constexpr bool n2 = 0 != &y;
+constexpr bool n3 = 0 <= &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n4 = 0 >= &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n5 = 0 < &y; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n6 = 0 > &y; // expected-error {{must be initialized by a constant expression}}
+
+constexpr bool n7 = &x == 0;
+constexpr bool n8 = &x != 0;
+constexpr bool n9 = &x <= 0; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n10 = &x >= 0; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n11 = &x < 0; // expected-error {{must be initialized by a constant expression}}
+constexpr bool n12 = &x > 0; // expected-error {{must be initialized by a constant expression}}
+
+using check = int[m1 + (m2<<1) + (m3<<2) + (m4<<3) + (m5<<4) + (m6<<5) +
+                  (n1<<6) + (n2<<7) + (n7<<8) + (n8<<9)];
+using check = int[2+4+16+128+512];
+
+}





More information about the cfe-commits mailing list