[cfe-commits] r149463 - in /cfe/trunk: include/clang/Basic/DiagnosticASTKinds.td lib/AST/ExprConstant.cpp test/SemaCXX/constant-expression-cxx11.cpp

Richard Smith richard-llvm at metafoo.co.uk
Tue Jan 31 17:42:44 PST 2012


Author: rsmith
Date: Tue Jan 31 19:42:44 2012
New Revision: 149463

URL: http://llvm.org/viewvc/llvm-project?rev=149463&view=rev
Log:
constexpr: add support for comparisons of pointer-to-members.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=149463&r1=149462&r2=149463&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Tue Jan 31 19:42:44 2012
@@ -39,6 +39,8 @@
 def note_constexpr_pointer_arithmetic : Note<
   "cannot refer to element %0 of non-array object in a constant "
   "expression">;
+def note_constexpr_compare_virtual_mem_ptr : Note<
+  "comparison of pointer to virtual member function %0 has unspecified value">;
 def note_constexpr_past_end : Note<
   "dereferenced pointer past the end of %select{|subobject of }0"
   "%select{temporary|%2}1 is not a constant expression">;

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=149463&r1=149462&r2=149463&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Jan 31 19:42:44 2012
@@ -813,6 +813,15 @@
     }
   };
 
+  /// Compare two member pointers, which are assumed to be of the same type.
+  static bool operator==(const MemberPtr &LHS, const MemberPtr &RHS) {
+    if (!LHS.getDecl() || !RHS.getDecl())
+      return !LHS.getDecl() && !RHS.getDecl();
+    if (LHS.getDecl()->getCanonicalDecl() != RHS.getDecl()->getCanonicalDecl())
+      return false;
+    return LHS.Path == RHS.Path;
+  }
+
   /// Kinds of constant expression checking, for diagnostics.
   enum CheckConstantExpressionKind {
     CCEK_Constant,    ///< A normal constant.
@@ -4295,9 +4304,9 @@
             (!RHSValue.Base && !RHSValue.Offset.isZero()))
           return Error(E);
         // It's implementation-defined whether distinct literals will have
-        // distinct addresses. In clang, we do not guarantee the addresses are
-        // distinct. However, we do know that the address of a literal will be
-        // non-null.
+        // distinct addresses. In clang, the result of such a comparison is
+        // unspecified, so it is not a constant expression. However, we do know
+        // that the address of a literal will be non-null.
         if ((IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) &&
             LHSValue.Base && RHSValue.Base)
           return Error(E);
@@ -4354,6 +4363,45 @@
       }
     }
   }
+
+  if (LHSTy->isMemberPointerType()) {
+    assert(E->isEqualityOp() && "unexpected member pointer operation");
+    assert(RHSTy->isMemberPointerType() && "invalid comparison");
+
+    MemberPtr LHSValue, RHSValue;
+
+    bool LHSOK = EvaluateMemberPointer(E->getLHS(), LHSValue, Info);
+    if (!LHSOK && Info.keepEvaluatingAfterFailure())
+      return false;
+
+    if (!EvaluateMemberPointer(E->getRHS(), RHSValue, Info) || !LHSOK)
+      return false;
+
+    // C++11 [expr.eq]p2:
+    //   If both operands are null, they compare equal. Otherwise if only one is
+    //   null, they compare unequal.
+    if (!LHSValue.getDecl() || !RHSValue.getDecl()) {
+      bool Equal = !LHSValue.getDecl() && !RHSValue.getDecl();
+      return Success(E->getOpcode() == BO_EQ ? Equal : !Equal, E);
+    }
+
+    //   Otherwise if either is a pointer to a virtual member function, the
+    //   result is unspecified.
+    if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(LHSValue.getDecl()))
+      if (MD->isVirtual())
+        CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
+    if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(RHSValue.getDecl()))
+      if (MD->isVirtual())
+        CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
+
+    //   Otherwise they compare equal if and only if they would refer to the
+    //   same member of the same most derived object or the same subobject if
+    //   they were dereferenced with a hypothetical object of the associated
+    //   class type.
+    bool Equal = LHSValue == RHSValue;
+    return Success(E->getOpcode() == BO_EQ ? Equal : !Equal, E);
+  }
+
   if (!LHSTy->isIntegralOrEnumerationType() ||
       !RHSTy->isIntegralOrEnumerationType()) {
     // We can't continue from here for non-integral types.

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=149463&r1=149462&r2=149463&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Tue Jan 31 19:42:44 2012
@@ -827,6 +827,18 @@
   static_assert((s.*&S::f)() == 2, "");
   static_assert((s.*s.pf)() == 2, "");
 
+  static_assert(pf == &S::f, "");
+  static_assert(pf == s.*&S::pf, "");
+  static_assert(pm == &S::m, "");
+  static_assert(pm != pn, "");
+  static_assert(s.pn != pn, "");
+  static_assert(s.pn == pm, "");
+  static_assert(pg != nullptr, "");
+  static_assert(pf != nullptr, "");
+  static_assert((int S::*)nullptr == nullptr, "");
+  static_assert(pg == pg, ""); // expected-error {{constant expression}} expected-note {{comparison of pointer to virtual member function 'g' has unspecified value}}
+  static_assert(pf != pg, ""); // expected-error {{constant expression}} expected-note {{comparison of pointer to virtual member function 'g' has unspecified value}}
+
   template<int n> struct T : T<n-1> {};
   template<> struct T<0> { int n; };
   template<> struct T<30> : T<29> { int m; };
@@ -836,10 +848,13 @@
 
   constexpr int (T<10>::*deepn) = &T<0>::n;
   static_assert(&(t17.*deepn) == &t17.n, "");
+  static_assert(deepn == &T<2>::n, "");
 
   constexpr int (T<15>::*deepm) = (int(T<10>::*))&T<30>::m;
   constexpr int *pbad = &(t17.*deepm); // expected-error {{constant expression}}
   static_assert(&(t30.*deepm) == &t30.m, "");
+  static_assert(deepm == &T<50>::m, "");
+  static_assert(deepm != deepn, "");
 
   constexpr T<5> *p17_5 = &t17;
   constexpr T<13> *p17_13 = (T<13>*)p17_5;
@@ -857,6 +872,14 @@
   static_assert(&(p30_5->*(int(T<2>::*))deepm) == &t30.m, "");
   static_assert(&(((T<17>*)p30_13)->*deepm) == &t30.m, "");
   static_assert(&(p30_23->*deepm) == &t30.m, "");
+
+  struct Base { int n; };
+  template<int N> struct Mid : Base {};
+  struct Derived : Mid<0>, Mid<1> {};
+  static_assert(&Mid<0>::n == &Mid<1>::n, "");
+  static_assert((int Derived::*)(int Mid<0>::*)&Mid<0>::n !=
+                (int Derived::*)(int Mid<1>::*)&Mid<1>::n, "");
+  static_assert(&Mid<0>::n == (int Mid<0>::*)&Base::n, "");
 }
 
 namespace ArrayBaseDerived {





More information about the cfe-commits mailing list