PR21327 / C++ DR1652 / C++ DR73: comparing a past-the-end pointer for one
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 21 Oct 2014 23:01:04 +0000 (23:01 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 21 Oct 2014 23:01:04 +0000 (23:01 +0000)
complete object to a pointer to the start of another complete object does
not evaluate to the constant 'false'. All other comparisons between the
addresses of subobjects of distinct complete objects still do.

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

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

index 532720666bc8b7b56e1f8f51d5dd732e61a08c7c..78de2578bee1f7e59c737c980c80eb4235c4a2e9 100644 (file)
@@ -6461,6 +6461,27 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
          A.getLValueCallIndex() == B.getLValueCallIndex();
 }
 
+/// \brief Determine whether this is a pointer past the end of the complete
+/// object referred to by the lvalue.
+static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx,
+                                            const LValue &LV) {
+  // A null pointer can be viewed as being "past the end" but we don't
+  // choose to look at it that way here.
+  if (!LV.getLValueBase())
+    return false;
+
+  // If the designator is valid and refers to a subobject, we're not pointing
+  // past the end.
+  if (!LV.getLValueDesignator().Invalid &&
+      !LV.getLValueDesignator().isOnePastTheEnd())
+    return false;
+
+  // We're a past-the-end pointer if we point to the byte after the object,
+  // no matter what our type or path is.
+  auto Size = Ctx.getTypeSizeInChars(getType(LV.getLValueBase()));
+  return LV.getLValueOffset() == Size;
+}
+
 namespace {
 
 /// \brief Data recursive integer evaluator of certain binary operators.
@@ -6923,6 +6944,13 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
         // object.
         if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue))
           return Error(E);
+        // We can't compare the address of the start of one object with the
+        // past-the-end address of another object, per C++ DR1652.
+        if ((LHSValue.Base && LHSValue.Offset.isZero() &&
+             isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) ||
+            (RHSValue.Base && RHSValue.Offset.isZero() &&
+             isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue)))
+          return Error(E);
         // Pointers with different bases cannot represent the same object.
         // (Note that clang defaults to -fmerge-all-constants, which can
         // lead to inconsistent results for comparisons involving the address
index 781c1883ff865a1eaa56a5ee30a75d09290aa447..011b4201b0b4775bf235e57bc6cc05977c0059d8 100644 (file)
@@ -823,7 +823,7 @@ namespace dr70 { // dr70: yes
 namespace dr73 { // dr73: no
   // The resolution to dr73 is unworkable. Consider:
   int a, b;
-  static_assert(&a + 1 != &b, "");
+  static_assert(&a + 1 != &b, ""); // expected-error {{not an integral constant expression}}
 }
 #endif
 
index 24a9d670e875fd07d67370ee1e7fc142287a1edb..7c938d54ffa69165f285c9bde88c135a41d39d06 100644 (file)
@@ -1935,3 +1935,7 @@ namespace PR19010 {
   };
   void test() { constexpr Test t; }
 }
+
+void PR21327(int a, int b) {
+  static_assert(&a + 1 != &b, ""); // expected-error {{constant expression}}
+}