diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-31 06:41:30 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-31 06:41:30 +0000 |
commit | 82f28583b8e81ae9b61635a0652f6a45623df16d (patch) | |
tree | 0c115e17cc6345a73e0627e2afde2cf40e3b9315 | |
parent | ff8f9ec8336c62b5e3504e2a394f4b25c0cb1963 (diff) |
constexpr: the result of a relational operator between pointers to void is
unspecified unless the pointers are equal; therefore, such a comparison is not
a constant expression unless the pointers are equal.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@149366 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticASTKinds.td | 2 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 12 | ||||
-rw-r--r-- | test/CXX/expr/expr.const/p2-0x.cpp | 13 |
3 files changed, 26 insertions, 1 deletions
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index 9fe22ad3ba..1cdbcb962e 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -53,6 +53,8 @@ def note_constexpr_var_init_non_constant : Note< def note_constexpr_typeid_polymorphic : Note< "typeid applied to expression of polymorphic type %0 is " "not allowed in a constant expression">; +def note_constexpr_void_comparison : Note< + "comparison between unequal pointers to void has unspecified result">; def note_constexpr_temporary_here : Note<"temporary created here">; def note_constexpr_literal_here : Note<"literal written here">; def note_constexpr_depth_limit_exceeded : Note< diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index c038e3feae..5a385e6eb4 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -4331,6 +4331,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { const CharUnits &LHSOffset = LHSValue.getLValueOffset(); const CharUnits &RHSOffset = RHSValue.getLValueOffset(); + + // C++11 [expr.rel]p3: + // Pointers to void (after pointer conversions) can be compared, with a + // result defined as follows: If both pointers represent the same + // address or are both the null pointer value, the result is true if the + // operator is <= or >= and false otherwise; otherwise the result is + // unspecified. + // We interpret this as applying to pointers to *cv* void. + if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset && + E->getOpcode() != BO_EQ && E->getOpcode() != BO_NE) + CCEDiag(E, diag::note_constexpr_void_comparison); + switch (E->getOpcode()) { default: llvm_unreachable("missing comparison operator"); case BO_LT: return Success(LHSOffset < RHSOffset, E); diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp index a39de4d2b9..617edc5faa 100644 --- a/test/CXX/expr/expr.const/p2-0x.cpp +++ b/test/CXX/expr/expr.const/p2-0x.cpp @@ -376,10 +376,21 @@ namespace UnspecifiedRelations { // If two pointers point to non-static data members of the same object with // different access control, the result is unspecified. - // FIXME: // [expr.rel]p3: Pointers to void can be compared [...] if both pointers // represent the same address or are both the null pointer [...]; otherwise // the result is unspecified. + struct S { int a, b; } s; + constexpr void *null = 0; + constexpr void *pv = (void*)&s.a; + constexpr void *qv = (void*)&s.b; + constexpr bool v1 = null < 0; + constexpr bool v2 = null < pv; // expected-error {{constant expression}} + constexpr bool v3 = null == pv; // ok + constexpr bool v4 = qv == pv; // ok + constexpr bool v5 = qv >= pv; // expected-error {{constant expression}} expected-note {{unequal pointers to void}} + constexpr bool v6 = qv > null; // expected-error {{constant expression}} + constexpr bool v7 = qv <= (void*)&s.b; // ok + constexpr bool v8 = qv > (void*)&s.a; // expected-error {{constant expression}} expected-note {{unequal pointers to void}} // FIXME: Implement comparisons of pointers to members. // [expr.eq]p2: If either is a pointer to a virtual member function and |