[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