]> granicus.if.org Git - clang/commitdiff
C++11 generalized constant expressions: evaluate equality comparisons between
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 31 Oct 2011 05:11:32 +0000 (05:11 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 31 Oct 2011 05:11:32 +0000 (05:11 +0000)
arbitrary pointers, if those pointers don't point to weak objects or literals.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143334 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ExprConstant.cpp
test/SemaCXX/constant-expression-cxx11.cpp

index ee8952917690d0e7b25830e09fd92754f664c49f..f4c9a8336c789a970fe44b89ebc847bfe6af9eaa 100644 (file)
@@ -257,6 +257,39 @@ static bool CheckConstantExpression(const CCValue &Value) {
   return !Value.isLValue() || IsGlobalLValue(Value.getLValueBase());
 }
 
+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;
+}
+
+static bool IsLiteralLValue(const LValue &Value) {
+  return Value.Base &&
+         !isa<DeclRefExpr>(Value.Base) &&
+         !isa<MemberExpr>(Value.Base);
+}
+
+static bool IsWeakLValue(const LValue &Value) {
+  const ValueDecl *Decl = GetLValueBaseDecl(Value);
+  if (!Decl)
+    return false;
+
+  return Decl->hasAttr<WeakAttr>() ||
+         Decl->hasAttr<WeakRefAttr>() ||
+         Decl->isWeakImported();
+}
+
 static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) {
   const Expr* Base = Value.Base;
 
@@ -275,19 +308,7 @@ static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) {
   // be true, but if it'a decl-ref to a weak symbol it can be null at
   // runtime.
   Result = true;
-
-  const DeclRefExpr* DeclRef = dyn_cast<DeclRefExpr>(Base);
-  if (!DeclRef)
-    return true;
-
-  // If it's a weak symbol, it isn't constant-evaluable.
-  const ValueDecl* Decl = DeclRef->getDecl();
-  if (Decl->hasAttr<WeakAttr>() ||
-      Decl->hasAttr<WeakRefAttr>() ||
-      Decl->isWeakImported())
-    return false;
-
-  return true;
+  return !IsWeakLValue(Value);
 }
 
 static bool HandleConversionToBool(const CCValue &Val, bool &Result) {
@@ -417,23 +438,6 @@ static bool IsConstNonVolatile(QualType T) {
   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;
@@ -1925,16 +1929,20 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
       // Reject differing bases from the normal codepath; we special-case
       // comparisons to null.
       if (!HasSameBase(LHSValue, RHSValue)) {
+        // Inequalities and subtractions between unrelated pointers have
+        // unspecified or undefined behavior.
         if (!E->isEqualityOp())
           return false;
-        if ((LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero())&&
-            (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero()))
+        // It's implementation-defined whether distinct literals will have
+        // distinct addresses. We define it to be unspecified.
+        if (IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue))
           return false;
-        LValue &NonNull = LHSValue.getLValueBase() ? LHSValue : RHSValue;
-        bool bres;
-        if (!EvalPointerValueAsBool(NonNull, bres))
+        // We can't tell whether weak symbols will end up pointing to the same
+        // object.
+        if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue))
           return false;
-        return Success(bres ^ (E->getOpcode() == BO_EQ), E);
+        // Pointers with different bases cannot represent the same object.
+        return Success(E->getOpcode() == BO_NE, E);
       }
 
       if (E->getOpcode() == BO_Sub) {
index 9f9c36bc5e65ca14dd101c733ce7aa3a5c05fb88..b02253cf4580cbef8a7024b7987f6dff9d77f32f 100644 (file)
@@ -161,8 +161,8 @@ namespace FunctionPointers {
 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 g1 = &x == &y;
+constexpr bool g2 = &x != &y;
 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}}
@@ -190,8 +190,16 @@ constexpr bool n10 = &x >= 0; // expected-error {{must be initialized by a const
 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}}
 
+constexpr bool s1 = &x == &x;
+constexpr bool s2 = &x != &x;
+constexpr bool s3 = &x <= &x;
+constexpr bool s4 = &x >= &x;
+constexpr bool s5 = &x < &x;
+constexpr bool s6 = &x > &x;
+
 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];
+                  (n1<<6) + (n2<<7) + (n7<<8) + (n8<<9) + (g1<<10) + (g2<<11) +
+               (s1<<12) + (s2<<13) + (s3<<14) + (s4<<15) + (s5<<16) + (s6<<17)];
+using check = int[2+4+16+128+512+2048+4096+16384+32768];
 
 }